Delphi cxtreelist перебирает узлы

У меня есть tcxTreeList с 3 столбцами, первый столбец имеет установленное свойство Node.CheckGroupType := ncgCheckGroup;, а второй столбец содержит ключ первого корневого узла, а третий столбец содержит ключи всех дочерних узлов под корневым узлом. Как я могу получить ключ корневого узла независимо от того, проверен он или нет, и ключи всех проверенных дочерних узлов в 2 переменные для вставки в БД и загрузки элементов из ключей, которые мы получаем из БД введите здесь описание изображения

Мой код для добавления элементов, как показано ниже

 APNode := tv.Add;
 APNode.CheckGroupType := ncgCheckGroup;
 APNode.Values[0] := define;
 ApNode.Values[1] := dCode;

определить - содержит текст, такой как Created, Released,In-Active и т.д.. все корневые узлы dcode - содержит ключевое значение каждого корневого узла, например E,F,I,P,R

Вот как я добавил дочерние узлы для каждого корневого узла

procedure TF_Form1.addPStatsToTreeList(tl: TcxTreeList; const dcode, define: string);
  function AddTreeListNode(TreeList: TcxTreeList; APNode: TcxTreeListNode; const AValues: Array of Variant; AImageIndex: Integer): TcxTreeListNode;
  begin
    Result := TreeList.AddChild(APNode);
    Result.AssignValues(AValues);
    Result.Imageindex := AImageIndex;
  end;
var
  grpnode,chNode, ANode: TcxTreeListNode;
  icnt : integer;
begin
  icnt := tl.Count;
  if Assigned(tl) then
  begin
    ANode := tl.TopNode;
    while ANode <> nil do
    begin
      ANode :=  AddTreeListNode(tl, ANode, [define, '', dcode], 0);
      ANode := TcxTreeListNode(ANode.GetNext);
    end;
  end;
end;

ОБНОВЛЕНИЕ

dcode — это одна буква, а Definition — строка, Dcode — это ключ для строки в определении. Подобно паре ключ-значение, Dcode — это ключ, а определение — это значение. В корневых узлах списка дерева, таких как Created, Released, In Active, Checked и Reactivated, есть другой ключ, который находится в столбце 1, а ключ для значений подузлов, таких как Sample, Development, Production и т. д., находится в 3-м столбце. В БД сохраняются только ключевые значения, ключи корневого узла сохраняются напрямую независимо от того, отмечены они или нет. Ключ каждого корневого узла будет сохранен в разных строках и попадет только в подузлы. Ключи проверенных узлов сохраняются в БД через запятую. Например . Если проверяются корневой узел Created и элементы под ним, такие как Sample , Development , то ключ корневого узла E является одним столбцом [DEFCODE (Primarykey)], а ключи подузлов M,E (DEFINITION) с разделителями-запятыми находятся в другом столбце.


person userhi    schedule 22.11.2019    source источник
comment
Ключ корневого узла никогда не меняется, у меня есть 2 столбца в БД: один идентификатор для сохранения code, а другой для define. code должен содержать все ключи корневых узлов в каждой строке, где define содержит ключи проверенных узлов под корневым узлом.   -  person userhi    schedule 22.11.2019
comment
Я не уверен, понимаете ли вы, но и TcxDBTreeList, и TcxTreeList являются потомками TcxCustomTreeList, а TcxDBTreeList специально разработан для сохранения данных дерева в наборе данных и его перезагрузки. Возможно, вам будет проще использовать TcxDBTreeList, чем пытаться самостоятельно изобретать колесо.   -  person MartynA    schedule 22.11.2019
comment
В соответствии с требованиями я не могу использовать dbtreelist. Можем ли мы сделать это с помощью cxtreeList?   -  person userhi    schedule 22.11.2019
comment
В этом случае вам нужно добавить минимальный воспроизводимый пример в ваш q, который включает весь код, необходимый для сборки пример дерева, потому что я боюсь, что ваше описание недостаточно ясно.   -  person MartynA    schedule 22.11.2019
comment
Хорошо, посмотрим на проблему по-другому: предположим, вы вызываете SaveToFile для древовидного списка, затем очищаете его и вызываете LoadFromFile. Чего же тогда не хватает в дереве, которое вам нужно?   -  person MartynA    schedule 22.11.2019
comment
Есть такие свойства, как Node.Parent и Node.Haschildren и Node.ChildCount. Вы можете достичь своих целей, используя предоставленные свойства объекта.   -  person nolaspeaker    schedule 22.11.2019
comment
Я писал ответ на ваш вопрос, но есть несколько вещей, которые я хочу проверить: во-первых, dcode — это одна буква, а define — это строка, верно? Кроме того, в первом блоке кода вы присваиваете dcode второму столбцу, т. е. ApNode.Values[1], но при вызове AddTreeListNode значение dcode передается как третий столбец. значение столбца. Почему такая разница или это ошибка?   -  person MartynA    schedule 23.11.2019
comment
@MartynA, я обновил вопрос, пожалуйста, проверьте   -  person userhi    schedule 25.11.2019


Ответы (1)


В приведенном ниже коде показано, как сохранить в TClientDataSet состояние Checked корневого узла вместе с его ключом и разделенным запятыми списком ключей его дочерних элементов, которые проверяются с помощью метода SaveTreeState.

Метод LoadTreeState очищает состояние Checked каждого узла в ctTreeList, а затем повторно загружает сохраненные состояния Checked из CDS.

Чтобы использовать этот код, вам нужно добавить в проект TClientDataSet с именем CDS1, а также TDataSource и TDBGrid, подключенные обычным образом. Затем добавьте постоянные поля в CDS, как показано в коде, скомпилируйте и запустите.

Я надеюсь, что понял, как правильно настроен ваш cxTreeList, но если нет, надеюсь, код должен быть довольно простым, чтобы адаптироваться к тому, что вы на самом деле делаете.

type
  TForm1 = class(TForm)
    cxTreeList1: TcxTreeList;
    CDS1: TClientDataSet;
    btnLoad: TButton;
    cxTreeList1Column1: TcxTreeListColumn;
    cxTreeList1Column2: TcxTreeListColumn;
    cxTreeList1Column3: TcxTreeListColumn;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    CDS1RootKey: TStringField;    // String[1]
    CDS1CheckedChildKeys: TStringField;  //  String[20]
    CDS1RootNodeChecked: TBooleanField;
    btnClear: TButton;
    procedure btnClearClick(Sender: TObject);
    procedure btnLoadClick(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    procedure SaveTreeState;
    procedure ClearChecks;
    procedure LoadTreeState;
  end;

[...]
procedure TForm1.ClearChecks;
var
  i,
  j : Integer;
begin
  for i := 0 to cxTreeList1.Count - 1 do begin
    cxTreeList1.Items[i].Checked := False;
    for j := 0 to cxTreeList1.Items[i].Count - 1 do begin
      cxTreeList1.Items[i].Items[j].Checked := False;
    end;
  end;
end;

procedure TForm1.SaveTreeState;
var
  i,
  j : Integer;
  RootNode,
  ChildNode : TcxTreeListNode;
  RootKey,
  ChildKeys : String;
begin
  CDS1.DisableControls;
  try
    CDS1.EmptyDataSet;

    for i := 0 to cxTreeList1.Count - 1 do begin
      RootNode := cxTreeList1.Items[i];
      RootKey := RootNode.Values[1];
      ChildKeys := '';
      for j := 0 to RootNode.Count - 1 do begin
        ChildNode := RootNode.Items[j];
        if ChildNode.Checked then begin
          if ChildKeys <> '' then
            ChildKeys := ChildKeys + ',';
          ChildKeys := ChildKeys + ChildNode.Values[2];
        end;
      end;
      CDS1.InsertRecord([RootKey, ChildKeys, RootNode.Checked]);
    end;
  finally
    CDS1.EnableControls;
  end;
end;

procedure TForm1.LoadTreeState;
var
  RootKey,
  ChildKey : String;
  ChildKeys : TStringList;
  i : Integer;
  RootNode,
  ChildNode : TcxTreeListNode;

  function FindRootNodeByKey(const Key : String) : TcxTreeListNode;
  var
    i : Integer;
  begin
    for i := 0 to cxTreeList1.Count - 1 do begin
      Result := cxTreeList1.Items[i];
      if CompareText(Result.Values[1], Key) = 0 then
        Exit;
    end;
    Result := Nil;
  end;

  function FindChildNodeByKey(ParentNode : TcxTreeListNode; const Key : String) : TcxTreeListNode;
  var
    i : Integer;
  begin
    for i := 0 to ParentNode.Count - 1 do begin
      Result := ParentNode.Items[i];
      if CompareText(Result.Values[2], Key) = 0 then
        Exit;
    end;
    Result := Nil;
  end;

begin
  cxTreeList1.BeginUpdate; // prevent treelist from updating while we load its state
  ClearChecks;
  try
    //  ChildKeys is a TStringList that we'll use to parse the list of child keys into individual values
    ChildKeys := TStringList.Create;
    try
      CDS1.DisableControls;
      try
        CDS1.First;
        while not CDS1.Eof do begin
          RootKey := CDS1RootKey.AsString;
          RootNode := FindRootNodeByKey(RootKey);
          Assert(RootNode <> Nil);  // check that we found the root node
          RootNode.Checked := CDS1RootNodeChecked.AsBoolean;
          ChildKeys.CommaText := Trim(CDS1CheckedChildKeys.AsString);  // Loading ChildKeys 
          //  by this assignment is what causes it to be parsed into individual keys
          for i := 0 to ChildKeys.Count - 1 do begin
            ChildKey := ChildKeys[i];
            ChildNode := FindChildNodeByKey(RootNode, ChildKeys[i]);
            Assert(ChildNode <> Nil);
            ChildNode.Checked := True;
          end;
          CDS1.Next;
        end;
      finally
        CDS1.EnableControls;
      end;
    finally
      ChildKeys.Free;
    end;
  finally
    cxTreeList1.EndUpdate;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  CDS1.CreateDataSet;
  ClearChecks;
end;

procedure TForm1.btnClearClick(Sender: TObject);
begin
  ClearChecks;
end;

procedure TForm1.btnLoadClick(Sender: TObject);
begin
  LoadTreeState;
end;

procedure TForm1.btnSaveClick(Sender: TObject);
begin
  SaveTreeState;
end;

end.
person MartynA    schedule 25.11.2019