我的树有 2 个级别的节点 - 它是一个联系人列表样式树。
我的问题是,我想检查所有“联系人类别”中的每个联系人。这是我现在看起来的联系人列表的屏幕截图(是的,我有权发布它)
如您所见,Todd Hirsch在 Category Test Category中被选中,但不是在All Contacts中。我想要实现的是让联系人在每个类别中都具有相同的检查状态。
示例:我在测试类别中检查 Todd Hirsch - Todd Hirsch 在所有联系人(以及所有其他类别)中自动检查。如果我在所有联系人中检查 Todd Hirsch,他也会在测试类别中检查。如果我在所有联系人中取消选中 Todd Hirsch,他也将在测试类别中取消选中。
我尝试通过 VirtualStringtree 的 OnChecking 事件来完成它,通过循环遍历树中每个节点的整个树,但是当联系人列表很大(2000 +)时,它非常慢,当有 5000 + 时,它甚至可能使我的程序崩溃(应用程序已停止工作)
你有什么建议?
这是我用来确保只检查一次联系人的代码。(这不是我现在想要的,但这是我现在正在使用的。)
////////////////////////////////////////////////////////////////////////////////
/// HasDuplicateChecked
////////////////////////////////////////////////////////////////////////////////
Function HasDuplicateChecked(Node: PVirtualNode): PVirtualNode;
Var
ParentNode, ChildNode: PVirtualNode;
I, J: Integer;
Begin
// IHCW
Result := Nil;
// Get the first node of the tree..
ParentNode := VT.GetFirst;
// Loop thru the parent nodes.
for I := 0 to VT.RootNodeCount - 1 do
begin
// Get the first child node.
ChildNode := ParentNode.FirstChild;
// Loop thru the children..
for J := 0 to ParentNode.ChildCount - 1 do
begin
// If the ChildNode is checked...
if NodeIsChecked(ChildNode) then
// And it is NOT the passed node..
if ChildNode <> Node then
// but the data matches..
if GetData(ChildNode).SkypeID = GetData(Node).SkypeID then
begin
// Then pass the Childnode as a result, and EXIT!
Result := ChildNode;
Exit;
end;
// Next child..
ChildNode := ChildNode.NextSibling;
end;
// Next parent...
ParentNode := ParentNode.NextSibling;
end;
End;
////////////////////////////////////////////////////////////////////////////////
/// vtSkypeChecking
////////////////////////////////////////////////////////////////////////////////
procedure TSkypeListEventHandler.vtSkypeChecking(Sender: TBaseVirtualTree;
Node: PVirtualNode; var NewState: TCheckState; var Allowed: Boolean);
Var
Level: Integer;
I: Integer;
Child: PVirtualNode;
begin
// Allow the checking..
Allowed := True;
// Get the Level..
Level := Sender.GetNodeLevel(Node);
// If the level is 0 (Category Level)
if Level = 0 then
begin
// And if the Node's Childcount is more than 0
if Node.ChildCount > 0 then
Begin
// Get the first child..
Child := Node.FirstChild;
// Loop thru the children..
for I := 0 to Node.ChildCount - 1 do
begin
// Set the checkstate, and go next..
Child.CheckState := NewState;
Child := Child.NextSibling;
end;
End;
end;
// If the level is 1 (User Level)
if Level = 1 then
begin
// and if the Node's parent is not Nil..
if Node.Parent <> nil then
begin
// aaand, if the new state is Unchecked...
if (NewState = csUncheckedNormal) or (NewState = csUncheckedPressed) then
begin
// .. and if the node checkstate is checked..
if NodeIsChecked(Node) then
Begin
// Set the PARENT node's checkstate to Unchecked!
Node.Parent.CheckState := csUncheckedNormal;
End;
end;
// BUT, if there is a DUPLICATE of the node, screw the above, and
// forbid the checking!
if HasDuplicateChecked(Node) <> nil then
Allowed := False;
end;
end;
// Uncheck all the duplicates.
UncheckDuplicates;
// Refresh the Tree
Sender.Refresh;
end;