Обновление Я обновил этот ответ, чтобы предоставить полный и автономный пример сохранения флажков TcxTreeList в строку (или TStringList), а затем повторно загрузить их, используя оба формат строки на скриншоте Q. Я проигнорировал код в Q и написал все с нуля, потому что это было проще, чем пытаться угадать, что именно вы собираетесь делать в своем коде - если бы я делал это сам, я бы не использовал метод Q но вместо этого сохраните состояния узлов дерева в TClientDataSet или эквивалент Devex.
В примере требуется только несколько служебных подпрограмм, чтобы выполнить свою работу, и все они принимают TcxTreeList или TcxTreeListNode в качестве входного параметра, чтобы они могли быть переехал в другое подразделение и повторно использовал другие формы.
Эти процедуры заключаются в следующем:
function RootNodeToString(RootNode : TcxTreeListNode) : String;
// This saves a Root node and its subkeys in the format show in the Q's screenshot
// Note: This does NOT save the RootNode's checked state because the q did not define
// whether it should
function TreeListNodesToString(TreeList : TcxTreeList) : String;
// This saves all the TreeList's Root nodes and their subkeys
// in the format show in the Q's screenshot
function RootNodeFromName(TreeList : TcxTreeList; AName : String) : TcxTreeListNode;
// Finds the RootNode having a given name or NIL if not found
function ChildNodeFromName(RootNode : TcxTreeListNode; const AName : String) : TcxTreeListNode;
// Finds the ChildNode (of a RootNode) having a given name or NIL if not found
function TreeListNodesToString(TreeList : TcxTreeList) : String;
// This saves all the TreeList's Root nodes and their subkeys
// in the format show in the Q's screenshot
function RootNodeFromName(TreeList : TcxTreeList; AName : String) : TcxTreeListNode;
// Finds the RootNode having a given name or NIL if not found
function ChildNodeFromName(RootNode : TcxTreeListNode; const AName : String) : TcxTreeListNode;
// Finds the ChildNode (of a RootNode) having a given name or NIL if not found
procedure ClearChecks(TreeList : TcxTreeList; ClearChildren : Boolean);
// Clears all the checkmark in a cxTreeList
Надеюсь, все они говорят сами за себя. В разделе «Реализация» данного примера:
const
iCheckCol = 0; // the number of the checkbox column
iNameCol = 1; // the number of the name column
function RootNodeToString(RootNode : TcxTreeListNode) : String;
// This saves a Root node and its subkeys in the format show in the Q's screenshot
// Note: This does NOT save the RootNode's checked state because the q did not define
// whether it should
var
j : Integer;
ANode : TcxTreeListNode;
begin
Result := '[' + RootNode.Values[iNameCol] + ']';
for j := 0 to RootNode.Count - 1 do begin
ANode := RootNode.Items[j];
if ANode.Values[iCheckCol] then
Result := Result + ',' + ANode.Values[iNameCol];
end;
end;
function TreeListNodesToString(TreeList : TcxTreeList) : String;
// This saves all the TreeList's Root nodes and their subkeys
// in the format show in the Q's screenshot
var
i : Integer;
begin
Result := '';
for i := 0 to TreeList.Count - 1 do begin
if Result <> '' then
Result := Result + ',';
Result := Result + RootNodeToString(TreeList.Items[i]);
end;
end;
function RootNodeFromName(TreeList : TcxTreeList; AName : String) : TcxTreeListNode;
// Finds the RootNode having a given name or NIL if not found
var
i : Integer;
begin
// First remove the square brackets, if any
if AName[1] = '[' then
Delete(AName, 1, 1);
if AName[Length(AName)] = ']' then
Delete(AName, Length(AName), 1);
// Next, look for AName in TreeList
for i := 0 to TreeList.Count - 1 do begin
Result := TreeList.Items[i];
if CompareText(Result.Values[iNameCol], AName) = 0 then exit; //CompareText is case-insensitive
end;
Result := Nil; // if we get to here, we didn't find it
end;
function ChildNodeFromName(RootNode : TcxTreeListNode; const AName : String) : TcxTreeListNode;
// Finds the ChildNode (of a RootNode) having a given name or NIL if not found
var
i : Integer;
begin
for i := 0 to RootNode.Count - 1 do begin
Result := RootNode.Items[i];
if CompareText(Result.Values[iNameCol], AName) = 0 then exit; //CompareText is case-insensitive
end;
Result := Nil; // if we get to here, we didn't find it
end;
procedure ClearChecks(TreeList : TcxTreeList; ClearChildren : Boolean);
// Clears all the checkmark in a cxTreeList
var
i,
j : Integer;
RootNode,
ANode : TcxTreeListNode;
begin
// This clears the checkmarks from all the Root nodes and, optionally,
// their children
TreeList.BeginUpdate;
try
for i := 0 to TreeList.Count - 1 do begin
RootNode := TreeList.Items[i];
RootNode.Values[iCheckCol] := False;
for j := 0 to RootNode.Count - 1 do begin
ANode := RootNode.Items[j];
ANode.Values[iCheckCol] := False;
end;
end;
finally
TreeList.EndUpdate;
end;
end;
procedure LoadTreeListChecksFromString(TreeList : TcxTreeList; const Input : String);
// This clears the TreeList's checkmarks and then sets the checkmarks
// from the Input string.
var
RootKey,
SubKey : String;
RootNode,
ChildNode : TcxTreeListNode;
TL : TStringList;
i : Integer;
begin
TreeList.BeginUpdate;
try
// First, clear the treelist's checkmarks
ClearChecks(TreeList, True);
// Next load the Input string into a TStringList to split it into a series
// of Root keys and Child keys
TL := TStringList.Create;
try
TL.CommaText := Input;
// The i variable will be used to iterate through the contents of the StringList
i := 0;
while i <= TL.Count - 1 do begin
// The first string in TL should be Root key
RootKey := TL[i];
RootNode := RootNodeFromName(TreeList, RootKey);
Assert(RootNode <> Nil); // will raise exception if RootNode not found
// The question does not say what should happen about the checkmark on the root nodes
Inc(i);
// Now, scan down the entries below the Root key and process retrive each if its sub-keys;
// stop when we get to the next Root key or reach the end of the Stringlist
while (i <= TL.Count - 1) and (Pos('[', TL[i]) <> 1) do begin
SubKey := TL[i];
ChildNode := ChildNodeFromName(RootNode, SubKey);
ChildNode.Values[iCheckCol] := True;
Inc(i);
end;
end;
finally
TL.Free;
end;
finally
TreeList.EndUpdate;
end;
end;
procedure TForm1.SetUpTreeList;
// This sets up the form' cxTreeList with some Root nodes and Child nodes
// Some of the ChildNode's checkmarks are set to save having to click around
// to set things up manually
var
i,
j : Integer;
RootNode,
ANode : TcxTreeListNode;
begin
for i := 0 to 3 do begin
RootNode := cxTreeList1.Add;
RootNode.AssignValues([Odd(i), 'RT' + IntToStr(i + 1)]);
for j := 0 to 4 do begin
ANode := RootNode.AddChild;
ANode.AssignValues([Odd(i + j), Char(j + Ord('A'))]);
end;
RootNode.Expand(True);
end;
edSavedKeys.Text := TreeListNodesToString(cxTreeList1);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
SetUpTreeList;
end;
procedure TForm1.btnClearClick(Sender: TObject);
begin
ClearChecks(cxTreeList1, True);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetNodeChecked(cxTreeList1.FocusedNode, not cxTreeList1.FocusedNode.Values[iCheckCol]);
end;
procedure TForm1.SetNodeChecked(Node : TcxTreeListNode; Value : Boolean);
begin
if Node = Nil then exit; // do nothing
Node.Values[iCheckCol] := Value;
end;
procedure TForm1.btnLoadClick(Sender: TObject);
begin
ClearChecks(cxTreeList1, True);
LoadTreeListChecksFromString(cxTreeList1, edSavedKeys.Text);
end;
end.
Оригинальный ответ
Самый простой способ установить столбец флажка несвязанного cxTreeList - просто установить значение в этот столбец в True или False. Итак, предполагая, что столбец CheckBox вашего cxTreeList равен столбцу 0, вы можете просто сделать это
procedure TForm1.SetNodeChecked(Node : TcxTreeListNode; Value : Boolean);
begin
if Node = Nil then exit; // do nothing
Node.Values[0] := Value;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
// toggle the checkbox of the focused node using code
SetNodeChecked(cxTreeList1.FocusedNode, not cxTreeList1.FocusedNode.Values[0]);
end;
Я предполагаю, что вы можете встроить это в существующий код. Я на самом деле не изучал это, но подозреваю, что вы могли бы значительно упростить это.