DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: sprblck
今日帖子: 10
在线用户: 15
导航: 论坛 -> 数据库专区 斑竹:liumazi,waterstone  
作者:
男 nalanfeng (纳兰峰) ★☆☆☆☆ -
普通会员
2010/6/9 0:20:23
标题:
探讨关于DevExpress控件DBTreeView的节点移动的问题。 浏览:5370
加入我的收藏
楼主: 我用dxDBTreeView生成一个树,并已经和一个Absolute Database库的数据表做了关联,KeyField和ParentField等也都做了设置。现在我想实现:将树的某结点的一个子节点向上移动一个顺序,即该子节点原来的Index为6,现在将其Index变成5,另外,最重要的一点是,与dxDBTreeView关联的数据库也要进行同步更新,即:当再次打开程序时,dxDBTreeView将保持节点移动后的顺序。我详细使用了一下dxDBTreeView,好像其节点在同级进行移动时,无法将更新结果反映到数据表中去。我写的节点移动代码如下:

if dxDBTreeView1.Selected <> nil then begin
  Node := dxDBTreeView1.Selected.GetPrevSibling;
  dxDBTreeView1.Selected.MoveTo(Node, naInsert);
end;

执行后,在dxDBTreeView中节点移动成功,但打开数据库后发现,节点的移动没有反映到数据表中。鉴于此,我想了一个办法:在与dxDBTreeView关联的数据表中增加了一个“Position”字段,想在每次对dxDBTreeView中的节点进行移动后,就把移动后的节点以及与其同级的其它所有节点的Index值更新到该字段下,然后再在FormCreate()下加入代码,使得每次程序启动后,让dxDBTreeView按“Position”字段中的Index值排列各节点,就应该可以解决上面的问题了。但是现在问题又来了,FormCreate()下的这段代码怎么实现呢?另外,还有没有其它更好的解决办法?

我的开发环境为:WinXP SP3、Delphi2007 SP4、DevExpress 4.3、Absolute Database6.05。
我使用的数据表的结构如下:
此帖子包含附件:
JPEG 图像
大小:36.5K
----------------------------------------------
-
作者:
男 nalanfeng (纳兰峰) ★☆☆☆☆ -
普通会员
2010/6/9 0:38:16
1楼: 帖子里的附件好像无法替换,只好重新再发一个新帖了。下面是新的截图(数据表中多了一个Position字段)。
此帖子包含附件:
JPEG 图像
大小:39.1K
----------------------------------------------
-
作者:
男 roguebear (旺财) ★☆☆☆☆ -
普通会员
2010/6/9 10:32:21
2楼: 你有福了 刚好我搞过。 数据库内的移动得自己写。下面是调试通过的代码 得到两个要交换节点的recno 我用的是locate 不知道还有不有其他更好的方法

#if 0
    if( dt->Locate(sFIELD_ORDERNUMBER, KeyID , TLocateOptions()) )
        {
          RecNo1 = dt->RecNo;
        }
    
        if( dt->Locate(sFIELD_ORDERNUMBER, newKeyID , TLocateOptions()) )
        {
          RecNo2 = dt->RecNo;
        }
#endif


bool __fastcall ExChangeRecord(TDataSet* dt, int iRecNo1, int iRecNo2)
{
    try
    {
        int fCount = dt->FieldCount;

        int Bounds[2] = {0, fCount};
        Variant  nodeValues    = VarArrayCreate(Bounds, 1, varVariant);
        Variant  nodeNewValues = VarArrayCreate(Bounds, 1, varVariant);

        int iStartIndex = INDEX_OF_FIELD(dt, sFIELD_ORDERNUMBER) ;

        dt->RecNo = iRecNo1;
        for(int i = iStartIndex; i < fCount; i++)
        {
          nodeValues.PutElement(dt->Fields->Fields[i]->Value , i);
        }

        dt->RecNo = iRecNo2;
        dt->Edit();
        for(int i = iStartIndex; i < fCount; i++)
        {
          nodeNewValues.PutElement(dt->Fields->Fields[i]->Value , i);
          dt->Fields->Fields[i]->Value = nodeValues.GetElement(i);
        }
        dt->Post();


        dt->RecNo = iRecNo1;
        dt->Edit();
        for(int i = iStartIndex; i < fCount; i++)
        {
          dt->Fields->Fields[i]->Value = nodeNewValues.GetElement(i);
        }
        dt->Post();
    }
    catch(...)
    {
        return false;
    }

    return true;
}
----------------------------------------------
-
作者:
男 nalanfeng (纳兰峰) ★☆☆☆☆ -
普通会员
2010/6/9 12:27:19
3楼: 谢谢roguebear (旺财)!把你的代码看了,思路我搞明白了,今天就去做下试验,晚上再告诉大家结果!再次谢谢!
----------------------------------------------
-
作者:
男 nalanfeng (纳兰峰) ★☆☆☆☆ -
普通会员
2010/6/10 22:16:11
4楼: 这些天把roguebear (旺财)兄的代码改成delphi的,然后跑了一遍,感觉这个思路非常不错,能够解决数据表中的记录移动问题,但经过这两天对这个问题的进一步思考,我自己也有一些体会,在这里想跟roguebear (旺财)兄以及盒子上的朋友分享一下。以下是修改后的delphi代码。

function ExchangeRecord(const iRecNo1, iRecNo2: Integer): Boolean;
const
  Bounds: array[0..1] of Integer = (0, 10);
var
  I, iStartIndex: Integer;
  S: String;
  temp, nodeValues, nodeNewValues: Variant;
begin
  Result := False;
  try
    I := Table1.FieldCount;
    
    nodeValues    := VarArrayCreate([0, 10], varVariant);
    nodeNewValues := VarArrayCreate([0, 10], varVariant);

    Table1.RecNo := iRecNo1;

    for I := 0 to 9 do begin
      temp := Table1.Fields.Fields[I].Value;
      nodeValues.PutElement(temp, I);
    end;

    Table1.RecNo := iRecNo2;
    Table1.Edit;
    for I := 0 to 9 do begin
      nodeNewValues.PutElement(Table1.Fields.Fields[I].Value, I);
      Table1.Fields.Fields[I].Value := nodeValues.GetElement(I);
    end;
    Table1.Post;

    Table1.RecNo := iRecNo1;
    Table1.Edit;
    for I := 0 to 9 do begin
      Table1.Fields.Fields[I].Value := nodeNewValues.GetElement(I);
    end;
    Table1.Post;

    Result := True;
  except
    //
  end;
end;

我所用的数据表只有10个字段,所以就没用Table1.FieldCount,而是直接用数字9代替了。但现在有几个问题:
问题1:程序每次执行到“nodeValues.PutElement(temp, I);”这条语句就出错,后来我改成了“nodeValues[I] := Table1.Fields.Fields[I].Value”就没问题了!感觉很奇怪!

问题2:虽然数据表中的两个记录相互交换成功了,但假如其所对应的TdxDBTreeView上的两个节点是HasChildren的,那么仅移动前面提到的两个记录是不行的,还要移动这两个节点下的子节点。但可能您会认为,当记录交换时,这两个记录的keyField内容也相互交换了,就不会存在上面的问题了,但实际上动手去做时,就会发现存在一个困难:假如记录1的keyField是3,假如记录2的keyField是4,则按前面的delphi代码,则在记录进行交换的过程中,会存在两个记录的keyField内容同为3或同为4的情况,而TdxDBTreeView控件一旦碰到该情况,则其中一个节点就不会显示了,当交换完成时,则会重新显示刚才没有显示的节点,但是会将其显示在TdxDBTreeView的最后(即最后的节点),这就完全错误了!这些天一直在考虑怎么解决,目前还没想出好方法,各位朋友有兴趣可以尝试一下,不一定要有代码,提出一个思路也可以。大家共同讨论!
----------------------------------------------
-
作者:
男 roguebear (旺财) ★☆☆☆☆ -
普通会员
2010/6/10 23:45:08
5楼: 这个是devexpress网站上找到的官方代码 具体是原来是delphi,还是c++记不得了。移动带子节点的节点也没有问题。我是c++builder delphi不懂
----------------------------------------------
-
作者:
男 roguebear (旺财) ★☆☆☆☆ -
普通会员
2010/6/10 23:46:20
6楼: 忘记说一句 移动节点还是要用本身的moveto语句 移动过后然后再在数据库里面移动记录。
----------------------------------------------
-
作者:
男 nalanfeng (纳兰峰) ★☆☆☆☆ -
普通会员
2010/6/11 20:18:10
7楼: 我今天做了下试验,发现:节点不需要使用moveto去移动,只要在数据库中移动记录,其所对应的节点会由dxDBTreeView自动去处理,并自动移动到相应位置。这些天根据roguebear (旺财)兄给出的思路,并通过不断的试验,还是很有收获,现在的情况是:不管是否有子节点,都可以根据前面的思路移动成功,但是还有一点问题没有解决:当两个节点互换时,如果节点还有子节点,则该节点及其所有的子节点都会处于Expand的状态,我原本是希望能达到这种效果,就是:移动后的节点状态与移动前的节点状态应保持一致,即该节点或其子节点在移动前是Expand,则移动后也应是Expand的,如果是状态是Collapse的,则移动后也应是Collapse的。两个要互换的节点在移动之后仅仅应该是位置上的变化,其子节点的打开或收起的状态应与移动前一样。roguebear (旺财)兄,还有盒子上的其他朋友,大家共同讨论下吧!看看有没有什么方法解决这个问题。问题解决后,我会公布相应的代码。
----------------------------------------------
-
作者:
男 roguebear (旺财) ★☆☆☆☆ -
普通会员
2010/6/14 10:12:02
8楼: 还是先移动节点好点。我是先移动节点 然后根据locate的keyid交换记录 。 只有一级子目录。一切挺正常的。
----------------------------------------------
-
作者:
男 roguebear (旺财) ★☆☆☆☆ -
普通会员
2018/8/25 19:49:47
9楼: 我又来顶了。  最近准备重新搞下这个,发现这个bug太多了。。。 真的是bug,我用最简单工程弄得。  还有cxdbtreelist 也是一样,估计作者都同一个人。 

开始不觉得,数据量大了问题就来了,特别是节点移动次数一多,乱跳的,消失的。。。
我放弃了。  

过后的如果要用dbtreeview和cxdbtreelist的,最开始一定要用比较大的数据好好测试一段时间。一旦发现莫名其妙的问题就要小心了。
----------------------------------------------
-
作者:
男 lsh341999 (虫子) ★☆☆☆☆ -
普通会员
2018/8/25 21:55:47
10楼: 不要用DB的
TcxTreeList随便操
教程:
表单树形

平台下载
http://u.163.com/zGdR2jjl  
提取码: SHmKYOlm

安装教程
注:安装DSPSERVER服务进程必须有超级管理员权限
里面的模块全是不带DB的控件
----------------------------------------------
就怕想不到,没有做不到的
作者:
男 roguebear (旺财) ★☆☆☆☆ -
普通会员
2018/8/26 14:04:43
11楼: 不用db的 用cxtreelist 数据保存之类的自己写太麻烦了。。。哪里知道一旦出了问题,改不了才叫最操蛋的
----------------------------------------------
-
作者:
男 roguebear (旺财) ★☆☆☆☆ -
普通会员
2018/9/14 21:37:42
12楼: 自己顶一下。 最近解决了这个多年的bug。   交换数据不要全部交换, key和parent节点不需要变,只需要变其他的。。。  可以稍微研究一下数据结构,很简单一看就知道。
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行97.65625毫秒 RSS