且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

动态载入数据的无刷新TreeView控件(5)

更新时间:2022-08-22 08:23:29

    今天讨论一下TreeView控件的交互问题。包括鼠标对TreeNode的选取(单选&多选)、Checked;键盘对TreeNode的选取(单选&多选)、Checked;通过代码和控件交互三种方式。最后提供一个现阶段完成版本的演示示例供大家测试。

    使用封装好的代码来操作TreeView的UI,是我们上次主要讲述的内容。要实现交互,最重要的就是管理键盘和鼠标的事件。我原来讲过,关于TreeNode的UI外观,我们在TreeNodeBase那个类中进行处理,而把TreeNode的事件处理放在TreeNode类中来处理,这样的设计是为了提供一个清晰的编程结构。下面我们先看一下TreeNode类的定义和TreeNode.Render方法的代码:
动态载入数据的无刷新TreeView控件(5)<script language="javascript">动态载入数据的无刷新TreeView控件(5)</script>


    当然,为了能灵活的使用鼠标和TreeViee交互,我们需要处理大部分的鼠标事件。包括click、mousedown、mouseover、mouseout和mousemove。同时在处理这些鼠标事件时,很多时候还需要和键盘配合来操作,比如:Shift+Click的区段选取,Ctrl+Click的check方式选取等。

    在TreeNode的Render方法中,处理节点展开和收缩的事件是比较简单的,因为那只是一个开/关状态的转换。在TreeNode上做Check操作时需要注意,为了让控件的脚本类(TreeNode的实例)和DHTML类之间属性值同步,我们需要完全控制Checkbox的状态的变化,并且为了避免后面我们使用键盘来Check节点时出错,我们还必须保证Checkbox始终不能获得焦点。

动态载入数据的无刷新TreeView控件(5) input.onfocus = function(){ FindParentElement(this, 'TD').focus(); };动态载入数据的无刷新TreeView控件(5)

    // 总是把焦点置于Checkbox的Parent元素上

    由于我们已经实现了一套对UI更新的机制,就是统一使用ApplyUIChange()方法来负责。所以除了mousedown事件外,其它的事件处理函数都非常的简单,只需要设置一下控件属性,然后调用ApplyUIChange()就行了,比如:__CheckBoxOnClick(),它的实现就非常的简单清晰。

动态载入数据的无刷新TreeView控件(5) TreeNode.__CheckBoxOnClick = function()
动态载入数据的无刷新TreeView控件(5) {
动态载入数据的无刷新TreeView控件(5)    var elmtNode = FindParentElement(this, 'TR');
动态载入数据的无刷新TreeView控件(5)    if ( elmtNode && elmtNode.Comment == 'TreeNode' )
动态载入数据的无刷新TreeView控件(5)    {
动态载入数据的无刷新TreeView控件(5)        var objNode = elmtNode.Object;
动态载入数据的无刷新TreeView控件(5)        if ( objNode )
动态载入数据的无刷新TreeView控件(5)        {
动态载入数据的无刷新TreeView控件(5)            objNode.SetChecked(this.checked);
动态载入数据的无刷新TreeView控件(5)        }
动态载入数据的无刷新TreeView控件(5)    }   
动态载入数据的无刷新TreeView控件(5) };


    但是由于mousedown事件需要和键盘配合,并且本身它自己就承担着很多的交互功能,所以处理起来比较麻烦。而其中最麻烦的就是按住Shift键再Click的区段TreeNode选取功能。

动态载入数据的无刷新TreeView控件(5)if ( evt.shiftKey && !evt.ctrlKey )
动态载入数据的无刷新TreeView控件(5){
动态载入数据的无刷新TreeView控件(5)    if ( innerCache.m_Selecteds.m_Count == 0 )
动态载入数据的无刷新TreeView控件(5)    {
动态载入数据的无刷新TreeView控件(5)         objNode.SetSelected(true);
动态载入数据的无刷新TreeView控件(5)         innerCache.m_LastSelected = objNode;
动态载入数据的无刷新TreeView控件(5)    }
动态载入数据的无刷新TreeView控件(5)    var startNode = innerCache.m_LastSelected;
动态载入数据的无刷新TreeView控件(5)    var endNode = objNode; 
动态载入数据的无刷新TreeView控件(5)    var posStart = GetAbsoluteLocation(startNode.m_Element).absoluteTop;
动态载入数据的无刷新TreeView控件(5)    var posEnd = GetAbsoluteLocation(endNode.m_Element).absoluteTop;
动态载入数据的无刷新TreeView控件(5)    innerCache.UnselectAll();
动态载入数据的无刷新TreeView控件(5)    if ( startNode != endNode )
动态载入数据的无刷新TreeView控件(5)    {  
动态载入数据的无刷新TreeView控件(5)         if ( posStart > posEnd )
动态载入数据的无刷新TreeView控件(5)         {
动态载入数据的无刷新TreeView控件(5)                  var tmp = startNode;
动态载入数据的无刷新TreeView控件(5)                  startNode = endNode;
动态载入数据的无刷新TreeView控件(5)                  endNode = tmp;
动态载入数据的无刷新TreeView控件(5)         }
动态载入数据的无刷新TreeView控件(5)         var curNode = startNode;
动态载入数据的无刷新TreeView控件(5)         do
动态载入数据的无刷新TreeView控件(5)         {
动态载入数据的无刷新TreeView控件(5)                  curNode.SetSelected(true);
动态载入数据的无刷新TreeView控件(5)                  curNode = curNode.GetNextRowNode();
动态载入数据的无刷新TreeView控件(5)         }
动态载入数据的无刷新TreeView控件(5)         while(curNode != endNode);
动态载入数据的无刷新TreeView控件(5)         endNode.SetSelected(true); 
动态载入数据的无刷新TreeView控件(5)    }
动态载入数据的无刷新TreeView控件(5)    else
动态载入数据的无刷新TreeView控件(5)    {
动态载入数据的无刷新TreeView控件(5)         endNode.SetSelected(true);
动态载入数据的无刷新TreeView控件(5)    }   
动态载入数据的无刷新TreeView控件(5)}

    这个功能首先需要判断,当前事件是不是mousedown并且同时键盘Shift被按下了。上面第一个if就是做这个判断的,当确认了使这个事件条件后,我们需要判断当前的TreeView上是否存在最近(一种被选中时的循序的状态)被Selected的节点,这个节点将被用作区段选取的起点,鼠标mousedown(width shift)的节点将会是区段选取的终点。innerCache.m_Selecteds.m_Count == 0说明没有起点,那么我们就置当前被点下的点为起点(这是一个最近点),同时完成本次选取操作。如果在mouse down width shift key的时候,TreeView上有超过一个节点已被Selected,那么我们就取出起点(最近点)和终点,并开始计算起点和终点的位置关系,谁在上谁在下?然后把这两个节点整理为起点始终是在上面的节点,终点始终是在下面的节点(在屏幕上的相对位置),这样是为了使用同样的代码就能把两个方向的Selected工作都做了。然后清除TreeView上所有已选中的节点,从起点开始往终点Selected就行了:

动态载入数据的无刷新TreeView控件(5) do
动态载入数据的无刷新TreeView控件(5) {
动态载入数据的无刷新TreeView控件(5)     curNode.SetSelected(true);
动态载入数据的无刷新TreeView控件(5)     curNode = curNode.GetNextRowNode();
动态载入数据的无刷新TreeView控件(5) }
动态载入数据的无刷新TreeView控件(5) while(curNode != endNode);


    简单吧,可是这个curNode.GetNextRowNode()又不是很简单动态载入数据的无刷新TreeView控件(5),在处理键盘事件中我们再来详细说它。那么我们在键盘上需要处理那些操作呢?看下面的代码,我们处理:Up、Down、+、-、Space和Esc这几个按键。

动态载入数据的无刷新TreeView控件(5)<script language="javascript">动态载入数据的无刷新TreeView控件(5)</script>

   上面的代码,switch前是为了取到被操作的TreeNode对象。+、-、Space和Esc都很简单,从代码中一眼就看明白了,麻烦的就是Up和Down这两个操作。其实在这里希望实现的操作都是WinControl的TreeView中支持的,只是被移到Web的控件上而已。Up和Down操作就是Selected最近那个节点的相邻节点,或上面的或下面的。如果我们在一个层次上来找一个节点的上一个和下一个,那是非常简单的index-1、index+1就行了,可是在树这样的层次结构中,寻找一个它的看起来的上一个或下一个展开的节点,就比较郁闷了。两个方法:

动态载入数据的无刷新TreeView控件(5)   var previousNode = currentNode.GetPreviousRowNode();
动态载入数据的无刷新TreeView控件(5)   var nextNode = currentNode.GetNextRowNode();动态载入数据的无刷新TreeView控件(5)

    要说明白它们是干嘛的,都比较难。这么说吧,当这个TreeView展现我们面前时,我们暂时忽略节点之间的层级关系,把它们的节点看成向List的条目一样的结构,GetPreviousRowNode(),就是取上一行的Node,GetNextRowNode()就是取当前节点下一行的节点。

动态载入数据的无刷新TreeView控件(5)<script language="javascript">动态载入数据的无刷新TreeView控件(5)</script>

    弄个图来配合代码看可能比较容易理解些动态载入数据的无刷新TreeView控件(5)
  动态载入数据的无刷新TreeView控件(5)

    嗯,其它的问题先玩玩demo再继续讨论吧动态载入数据的无刷新TreeView控件(5)
  

本文转自博客园鸟食轩的博客,原文链接:http://www.cnblogs.com/birdshome/,如需转载请自行联系原博主。