Может кто-нибудь объяснить этот бит манипуляции с кодом? - PullRequest
0 голосов
/ 19 марта 2009

У меня есть древовидный элемент управления с флажками рядом с каждым узлом, который учитывает проверенные, непроверенные и средние проверенные состояния на узлах. При нажатии на узел родительский и дочерний элементы обновляются. Код, который я нашел, который использует трюк, использует сдвиг битов, и я пытаюсь понять, что именно происходит.

Может кто-нибудь объяснить следующий код? Или, что еще лучше, переписать этот код, чтобы его было легче понять?

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

Ответы [ 2 ]

2 голосов
/ 19 марта 2009

Похоже, что значение 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 голос
/ 19 марта 2009

В основном это выражение выглядит так:

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

Это нелогично. Обычно вы проверяете биты, сдвигая константу 1 влево, поскольку это позволяет количеству сдвинутых битов совпадать с индексом бита, считая младший бит LSB как бит номер 0.

Кроме того, нет смысла проверять результат с помощью сравнения ==, поскольку он всегда будет равен 0 или не равен нулю, поэтому вы можете по крайней мере проверить что-то более простое, если этого требует ваш язык.

В C и C ++, которые по умолчанию интерпретируют ненулевое целое число как "true", сравнение совершенно не нужно и просто служит для того, чтобы вносить беспорядок, повторяться и увеличивать риск ошибок.

Я бы написал так:

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

Дополнительная скобка должна помочь прояснить, как все сгруппировано. Обратите внимание, как «2 << 1» был переписан как «1 << 2». Это не просто «переключатель», вам нужно вычислить правильный сдвиг, чтобы получить то же значение бита, в данном случае 4. </p>

Конечно, вы можете поместить битовое тестирование в подпрограммы и вызывать их, чтобы сделать код более читабельным.

...