【问题标题】:Can someone explain this bit manipulation code?有人可以解释这个位操作代码吗?
【发布时间】:2009-03-19 10:17:06
【问题描述】:

我有一个树控件,每个节点旁边都有复选框,允许节点上的选中、未选中和中间选中状态。单击节点时,将更新父节点和子节点。我发现的代码使用位移,我试图了解到底发生了什么。

谁能解释下面的代码?或者更好的是,重写这段代码以便更容易理解?

// 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);
  }    
}

【问题讨论】:

    标签: apache-flex actionscript-3 actionscript bit-manipulation


    【解决方案1】:

    看起来控件中的 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 {
        ...
    }
    

    【讨论】:

      【解决方案2】:

      基本上是这样的表达式:

      var middle:Boolean = (value & 2 << 1) == (2 << 1);
      

      违反直觉。您通常通过将常量 1 向左移动来测试位,因为这样可以使移动的位数与位的索引相同,将 LSB(最右边)位计为位号 0。

      另外,用 == 比较来测试结果是没有意义的,因为它总是 0 或非零,所以如果你的语言需要,你至少可以测试一些更简单的东西。

      在默认情况下将非零整数解释为“真”的 C 和 C++ 中,比较完全没有必要,只会引入混乱、重复并增加错误的风险。

      我会这样写:

      var middle:Boolean = (value & (1 << 2)) != 0;
      

      额外的括号应该有助于更清楚地了解事物的分组方式。注意“2

      当然你可以把位测试放到子程序中调用,让代码更具可读性。

      【讨论】:

      • 感谢您的回答。因此,如果我理解正确,我可以将 1
      • 没有好处。您也可以将 (1
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多