使用GAS我创建了一个UIapp,其中包含一个具有多个(嵌套)树项目的树。 其中一些树状项目有复选框。
我想知道:
1)如果一个treeitem确实知道父小部件已被附加到
2)如何从根开始遍历树
3)是否存在检索项目的方法(如:item = tree.getItemById(<id>);
)
4)我注意到,如果复选框(该treeitem)没有连接onClickHandler,则会调用treeItem的onSelectionHandler。但如果已将一个复选框附加到treeitem,则不会调用它。这可以被某人证实吗?如果是这样的话:为什么这会发生?我是否需要在复选框上使用回调函数才能让树状结构知道?
5)因为创建一个有几百个(嵌套)树项目的树需要很长时间(但它确实有效),我想创建可见的树形部分,然后点击+按钮展开一个级别,只会添加扩展树所需的项目。如何检测用户是否单击treeitem旁边的+按钮以展开它(要使用哪个事件处理程序)?
6)是否可以覆盖类Tree并创建一个实现上述缺失特性的派生类?
答案 0 :(得分:0)
我在3周前开始调查GAS,在搜索SO时,我发现与其他语言相比,很多事情都不容易。
其中一件事情很难找出事件处理程序中eventInfo中存在哪些参数。我没有找到如何获取控件名称的帖子。但我知道这应该是可能的,因为JSON.stringify(e)
会写出参数的名称。
在检查树时,我需要对treeItems的引用,所以我想出了如何获取在事件处理程序中添加的控件的名称。
我在树上执行UI操作时使用了onMouseUpHandler,但也可以使用其他处理程序。
函数validateParameter允许查明参数是否引用控件。 在我的应用程序中,我创建了包含复选框的treeItems,允许识别我想要显示的文件夹。 为了识别控件,我使用了folderId和一个包含下划线的前缀,以便区分我添加的控件和eventInfo的其他参数。
由于我的目标是在需要时填充树的部分(因此:在用户点击treeitem旁边的expand-a-branch-button之后),我刚刚添加了一个&#39;级别&#39;创建树时的指示符。当然可以删除此功能。
var chkPrefix = "chk_"; // Prefix for names and ids of checkboxes on treeitems
var triPrefix = "tri_"; // Prefix for names and ids for treeitems
var useCheckBox = true; // Test using checkboxes --> change accordingly
// false = Do not use checkboxes on treeitems
// true = Use checkboxes on treeitems
// Create various handlers
var onSelectHandler = app.createServerHandler("onSelectHandler");
var onMouseUpHandler = app.createServerHandler("onMouseUpHandler");
var onCheckBoxHandler = app.createServerHandler("onCheckBoxHandler");
// Create a tree of folders starting from 'My Drive' --> to the folder you want
var tree = app.createTree().setAnimationEnabled(true);
var rootTree = DriveApp.getRootFolder(); // Root of the drive --> change to the folder you want
var level = 3; // Allowed maximum depth of the tree (0 = ALL) --> avoiding excessive runtime --> building treeitems when needed
var rootItem = populateFolderTree_(rootTree, tree, level); //
function populateFolderTree_(folder, parentItem, level)
{ // Internal function
var itemName = folder.getName();
var itemId = folder.getId();
if (useCheckBox === false)
{ // Just sho the name of the folder
var treeItem = app.createTreeItem(itemName);
}
else
{ // Create a checkbox on every treeitem
var chkBox = app.createCheckBox(itemName)
.setId(chkPrefix + itemId).setName(chkPrefix + itemId);
chkBox.addClickHandler(onCheckBoxHandler); // Add a handler
var treeItem = app.createTreeItem(chkBox);
}
treeItem.setId(triPrefix + itemId);
parentItem.addItem(treeItem);
if ((level === 0) || (level > 1))
{ // Maximum depth of the tree has not been reached (yet)
var subLevel = level - 1;
var subFolders = folder.getFolders();
while (subFolders.hasNext())
{ // Recursively add subfolders
var subFolder = subFolders.next();
populateFolderTree_(subFolder, treeItem, subLevel);
}
}
return treeItem; // Will eventually return the root of the tree
}
即使这段代码不完整,我相信这两个部分(部分生成文件夹树,检索evenInfo参数的名称)对其他部分也很有用。
function onMouseUpHandler(e)
{
var app = UiApp.getActiveApplication();
var source = e.parameter.source; // Contains the Id of the tree
var widget = app.getElementById(source);
Logger.log('\nOnMouseUpHandler ' + source + ' widget=' + widget.getId() + ' = ' + widget.getType());
var eventParameters = extractParameters(e, validateParameter);
var numParams = eventParameters.length
if (numParams > 0)
{
var keys = eventParameters.keys();
var values = eventParameters.values();
for (var i=0; i<numParams; i++)
{
Logger.log('key[' + i + '] = ' + keys[i] + ' value = ' + values[i]);
};
};
return app;
}
function validateParameter(namePar, valuePar)
{ // Skip all parameters not referring to treeitems
var accept = false;
var xx = namePar.substr(0, chkPrefix.length);
if (chkPrefix === namePar.substr(0, chkPrefix.length))
{
accept = true;
}
else if (triPrefix === namePar.substr(0, triPrefix.length))
{
accept = true;
};
Logger.log('namePar=' + namePar + ' accept=' + accept + ' xx=' + xx);
return accept;
}
function extractParameters(e, validateFunction)
{
var text = JSON.stringify(e);
start = text.indexOf(':{') + 1;
letters = text.indexOf('}') - start;
Logger.log('text=' + text);
var arrParameters = text.replace('"','').substr(start, letters).split(",");
var skipValidation = ((validateFunction === null) || (validateFunction === undefined));
// Store parameters in a hashtable
var statusControls = new HashTable(); // Any hashtable will do
var numParameters = arrParameters.length;
for (var i=0; i<numParameters; i++)
{
var parameter = arrParameters[i];
var pos = parameter.indexOf(":");
var nameVar = parameter.substr(1, pos - 2);
var valueVar = parameter.substr(pos + 2, parameter.length - pos - 3);
var accept = true;
if (skipValidation === false) accept = validateFunction(nameVar, valueVar);
if (accept === true) statusControls.addItem(nameVar, valueVar); // Only store acceptable parameters
}
return statusControls;
}
当我使用JSON.stringify然后解码其输出时,这种获取控件的方法可以肯定地得到改进。但就像我之前写的那样:我没有找到如何做到这一点,所以我自己做了。
我想从Tree(也可能来自TreeItem)创建派生类,在其他语言中执行常见的事情(即在任何级别检索itemCount();在两个方向上行走树;检索状态任何时候在treeItems上的复选框等等)因为当时真的很缺少(至少在我看来),这使得它很难开发。
显然,在仅仅3周的GAS(和Javascript)后,我不能期望知道很多。由于这里有很多人知道我缺少的知识,我希望他们能够通过改进代码并告诉我如何实现这些目标来提供帮助。
最后一句话:
我发现BetterLog
确实比标准Logger更容易开发。看看https://sites.google.com/site/scriptsexamples/custom-methods/betterlog#TOC-Documentation-Support-Resources