我有一个树形控件,每个节点旁边都有复选框,允许在节点上进行选中,取消选中和中间检查状态。单击节点时,将更新父节点和子节点。代码我发现这个技巧使用了位移,我试图理解究竟发生了什么。
有人可以解释以下代码吗?或者甚至更好,重写这段代码以便更容易理解?
// click event handler
private function eventMessageTree_itemCheckHandler(event:TreeEvent):void {
var node:ITreeNode = ITreeNode(event.item);
var checkState:uint = TreecheckboxItemRenderer(event.itemRenderer).checkBox.checkState;
updateParents(node, checkState);
updateChilds(node, checkState);
}
private function updateChilds(item:ITreeNode, value:uint):void {
var middle:Boolean = (value & 2 << 1) == (2 << 1);
var selected:Boolean = (value & 1 << 1) == (1 << 1);
if (item.children.length > 0 && !middle) {
for each (var childNode:ITreeNode in item.children) {
childNode.checked = value == (1 << 1 | 2 << 1) ? "2" : value == (1 << 1) ? "1" : "0";
updateChilds(childNode, value);
}
}
}
private function updateParents(item:ITreeNode, value:uint): void {
var checkValue:String = (value == (1 << 1 | 2 << 1) ? "2" : value == (1 << 1) ? "1" : "0");
var parentNode:ITreeNode = item.parent;
if (parentNode) {
for each (var childNode:ITreeNode in parentNode.children) {
if (childNode.checked != checkValue) {
checkValue = "2";
}
}
parentNode.checked = checkValue;
updateParents(parentNode, value);
}
}
答案 0 :(得分:2)
看起来控件中的checkState值可以是1,2或4(或者可能是0,2和4?):
public static const CONTROL_UNCHECKED:uint = 1; // not checked, and some descendants are
public static const CONTROL_CHECKED:uint = 2; // checked, and all descendants are
public static const CONTROL_MIDDLE:uint = 4; // not checked, but some descendants are
,而节点中的选中值可以是0,1或2:
public static const UNCHECKED:uint = 0; // not checked, and some descendants are
public static const CHECKED:uint = 1; // checked, and all descendants are
public static const MIDDLE:uint = 2; // not checked, but some descendants are
这真令人困惑。理想情况下,这些将是相同的常量集。
更新:
private function controlStateToNodeState(value:uint):uint {
return value / 2;
}
...
updateParents(node, controlStateToNodeState(checkState));
updateChilds(node, controlStateToNodeState(checkState));
...
/** Updates the descendants of the node based on state:
* If value is CHECKED, all children are CHECKED
* If value is UNCHECKED, all children are UNCHECKED
* If value is MIDDLE, children are left alone
*/
private function updateChilds(item:ITreeNode, value:uint):void {
if (value == MIDDLE) {
return; // if value is MIDDLE, children are left alone
}
// not middle, so update all children to my state
for each (var childNode:ITreeNode in item.children) {
childNode.checked = value;
updateChilds(childNode, value);
}
}
}
/**
* Updates the ancestor nodes based on state:
* If value is CHECKED, ancestors are made MIDDLE if not already checked
* If value is MIDDLE, ancestors are made middle (they should not already be CHECKED)
*/
private function updateParents(item:ITreeNode, value:uint): void {
...
}
答案 1 :(得分:1)
基本上,这样的表达式:
var middle:Boolean = (value & 2 << 1) == (2 << 1);
反直觉。您通常通过将常数1向左移位来测试位,因为这样可以使位移的位数与位的索引相同,将LSB(最右侧)位计为位数0。
此外,使用==比较测试结果没有意义,因为它总是为0或非零,所以如果你的语言需要,你至少可以测试更简单的东西。
在C和C ++中,默认情况下将非零整数解释为“true”,这种比较完全没必要,只会引入杂乱,重复和增加错误的风险。
我会这样写:
var middle:Boolean = (value & (1 << 2)) != 0;
额外的括号应该有助于更清楚地分组事物。注意如何将“2 <&lt; 1”重写为“1 <&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;这不仅仅是一个“开关”,你需要计算正确的移位以获得相同的位值,在这种情况下为4。
当然,您可以将位测试放入子程序并调用它们,以使代码更具可读性。