导航:
论坛 -> 数据库专区
斑竹:liumazi,waterstone
作者:
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。 我使用的数据表的结构如下:
此帖子包含附件: 大小: 36.5K
----------------------------------------------
-
作者:
2010/6/9 0:38:16
1楼:
帖子里的附件好像无法替换,只好重新再发一个新帖了。下面是新的截图(数据表中多了一个Position字段)。
此帖子包含附件: 大小: 39.1K
----------------------------------------------
-
作者:
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; }
----------------------------------------------
-
作者:
2010/6/9 12:27:19
3楼:
谢谢roguebear (旺财)!把你的代码看了,思路我搞明白了,今天就去做下试验,晚上再告诉大家结果!再次谢谢!
----------------------------------------------
-
作者:
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的最后(即最后的节点),这就完全错误了!这些天一直在考虑怎么解决,目前还没想出好方法,各位朋友有兴趣可以尝试一下,不一定要有代码,提出一个思路也可以。大家共同讨论!
----------------------------------------------
-
作者:
2010/6/10 23:45:08
5楼:
这个是devexpress网站上找到的官方代码 具体是原来是delphi,还是c++记不得了。移动带子节点的节点也没有问题。我是c++builder delphi不懂
----------------------------------------------
-
作者:
2010/6/10 23:46:20
6楼:
忘记说一句 移动节点还是要用本身的moveto语句 移动过后然后再在数据库里面移动记录。
----------------------------------------------
-
作者:
2010/6/11 20:18:10
7楼:
我今天做了下试验,发现:节点不需要使用moveto去移动,只要在数据库中移动记录,其所对应的节点会由dxDBTreeView自动去处理,并自动移动到相应位置。这些天根据roguebear (旺财)兄给出的思路,并通过不断的试验,还是很有收获,现在的情况是:不管是否有子节点,都可以根据前面的思路移动成功,但是还有一点问题没有解决:当两个节点互换时,如果节点还有子节点,则该节点及其所有的子节点都会处于Expand的状态,我原本是希望能达到这种效果,就是:移动后的节点状态与移动前的节点状态应保持一致,即该节点或其子节点在移动前是Expand,则移动后也应是Expand的,如果是状态是Collapse的,则移动后也应是Collapse的。两个要互换的节点在移动之后仅仅应该是位置上的变化,其子节点的打开或收起的状态应与移动前一样。roguebear (旺财)兄,还有盒子上的其他朋友,大家共同讨论下吧!看看有没有什么方法解决这个问题。问题解决后,我会公布相应的代码。
----------------------------------------------
-
作者:
2010/6/14 10:12:02
8楼:
还是先移动节点好点。我是先移动节点 然后根据locate的keyid交换记录 。 只有一级子目录。一切挺正常的。
----------------------------------------------
-
作者:
2018/8/25 19:49:47
9楼:
我又来顶了。 最近准备重新搞下这个,发现这个bug太多了。。。 真的是bug,我用最简单工程弄得。 还有cxdbtreelist 也是一样,估计作者都同一个人。 开始不觉得,数据量大了问题就来了,特别是节点移动次数一多,乱跳的,消失的。。。 我放弃了。 过后的如果要用dbtreeview和cxdbtreelist的,最开始一定要用比较大的数据好好测试一段时间。一旦发现莫名其妙的问题就要小心了。
----------------------------------------------
-
作者:
2018/8/25 21:55:47
10楼:
不要用DB的 TcxTreeList随便操 教程:表单树形 平台下载 http://u.163.com/zGdR2jjl 提取码: SHmKYOlm安装教程 注:安装DSPSERVER服务进程必须有超级管理员权限 里面的模块全是不带DB的控件
----------------------------------------------
就怕想不到,没有做不到的
作者:
2018/8/26 14:04:43
11楼:
不用db的 用cxtreelist 数据保存之类的自己写太麻烦了。。。哪里知道一旦出了问题,改不了才叫最操蛋的
----------------------------------------------
-
作者:
2018/9/14 21:37:42
12楼:
自己顶一下。 最近解决了这个多年的bug。 交换数据不要全部交换, key和parent节点不需要变,只需要变其他的。。。 可以稍微研究一下数据结构,很简单一看就知道。
----------------------------------------------
-