2009-03-19 7 views
0

J'ai un contrôle d'arbre avec des cases à cocher à côté de chaque nœud qui permet des états vérifiés, non cochés et intermédiaires sur les nœuds. Lorsque vous cliquez sur un noeud, le parent et les enfants sont mis à jour. Le code que j'ai trouvé qui fait l'affaire utilise le décalage de bits et j'essaie de comprendre ce qui se passe exactement.Quelqu'un peut-il expliquer ce code de manipulation de bits?

Quelqu'un peut-il expliquer le code suivant? Ou encore mieux, réécrire ce code pour qu'il soit plus facile à comprendre?

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

Répondre

1

Fondamentalement, une expression comme ceci:

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

est contre-intuitif. Vous testez habituellement les bits en déplaçant la constante 1 vers la gauche, car cela laisse le nombre de bits décalés être identique à l'indice du bit, en comptant le bit LSB (le plus à droite) comme le bit 0.

De plus, il y a Il est inutile de tester le résultat avec une comparaison ==, car il sera toujours 0 ou non nul, donc vous pouvez au moins tester quelque chose de plus simple si votre langage l'exige. En C et C++, qui interprètent par défaut un entier non nul comme "vrai", la comparaison est totalement inutile et ne sert qu'à introduire le fouillis, la répétition, et augmenter le risque de bugs.

j'écris ceci comme ceci:

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

La parenthèse supplémentaire devrait aider à le rendre plus clair comment les choses sont regroupées. Notez comment "2 < < 1" a été réécrit comme "1 < < 2". Ce n'est pas seulement un "commutateur", vous devez calculer le décalage approprié pour obtenir la même valeur de bit, 4 dans ce cas.

Bien sûr, vous pouvez mettre le test de bits dans des sous-programmes et les appeler, pour rendre le code plus lisible.

+0

Merci pour votre réponse. Donc si je comprends bien, je pourrais juste remplacer 1 << 2 ou 2 << 1 par 4, non? Y at-il un avantage à utiliser le décalage de bits au lieu du nombre constant 4? –

+0

Aucun avantage. Vous pouvez également remplacer (1 << 1 | 2 << 1) par 6. Du point de vue de la lisibilité, c'est probablement aussi mauvais que l'original, mais au moins c'est plus court. Le codage en dur des deux opérandes n'a de sens que lors de la déclaration d'un const comme UNCHECKED = 1 << 2, au lieu de UNCHECKED = 4, pour souligner le bit que vous définissez –

2

Il semble que la valeur checkState dans le contrôle peut être soit 1, 2 ou 4 (ou éventuellement 0, 2 et 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 

tandis que la valeur vérifiée dans les noeuds peut être 0, 1 ou 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 

C'est vraiment déroutant. Idéalement, ce serait le même ensemble de constantes.

Pour mettre à jour:

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 { 
    ... 
} 
Questions connexes