Einzelnen Beitrag anzeigen

Assertor

Registriert seit: 4. Feb 2006
Ort: Hamburg
1.296 Beiträge
 
Turbo C++
 
#12

Re: Problem mit der Sortierung im VST

  Alt 1. Apr 2009, 13:31
Hi Richard,

Zitat von richard_boderich:
"(korrekte Nummerierung, davor oder dahinter eingefügt)" bedeutet was genau?

Ich gehe mal davon aus das du damit den Node index meinst?
Richtig, damit meine ich den NodeIndex.

Zitat von richard_boderich:
Funktioniert das auch wenn ich gerade im Baum sagen wir mal nach Strings oder nach einen Datum korrekt einsortieren muss?

Wenn ja, könnte man dies ins offfizielle VST zu integrieren?
Leider nein, wenn die Daten nicht vorhersagbar sind - also wie in Deinem Beispiel verschiedene Datumsangaben oder beliebige Strings - geht es nicht.

Prinzipiell sind alle nötigen Funktionen für das Einfügen schon im VST. Es handelt sich bei meiner Nutzung um einen Sonderfall, der hierbei sehr viel Zeit spart.

Als Anregung mal mein Code (Auszugsweise).

Gruß Assertor

Delphi-Quellcode:
//
// die üblichen Verdächtigen des VST...
//

procedure TfrmMain.vstTestGridGetNodeDataSize(Sender: TBaseVirtualTree;
  var NodeDataSize: Integer);
begin
  inherited;
  TVirtualStringTree(Sender).NodeDataSize := SizeOf(TGridNodeData);
end;

procedure TfrmMain.vstTestGridInitNode(Sender: TBaseVirtualTree; ParentNode,
  Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
var
  NodeData: PGridNodeData;
begin
  inherited;
  NodeData := Sender.GetNodeData(Node);
  if Assigned(NodeData) then
    NodeData^ := Node.Index + 1; // Anzeige startet bei 1, nicht 0
end;

procedure TfrmMain.vstTestGridGetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: String);
var
  NodeData: PGridNodeData;
  DatabaseRecord: PDatabaseRecord;

  function GetDBRecord: Boolean;
  begin
    // hier wird der Eintrag aus der Datenbank geholt
   ...
    Result := Assigned(DatabaseRecord);
  end;

begin
  inherited;
  NodeData := Sender.GetNodeData(Node);
  if Assigned(NodeData) then
  begin
    CellText := '-'; // default for invalid data
    case Column of
      0: CellText := IntToStr(NodeData^);
      1: if GetDBRecord then
            CellText := DatabaseRecord^.MeinDatenbankFeld1;
      2: if GetDBRecord then
            CellText := DatabaseRecord^.MeinDatenbankFeld2;
      4: if GetDBRecord then
            CellText := DatabaseRecord^.MeinDatenbankFeld3;
     ...
    end;
  end;
end;

procedure TfrmMain.vstTestGridHeaderClick(Sender: TVTHeader;
  Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  inherited;
  // handle sorting changes
  if Button = mbLeft then
  begin
    vstTestGrid.BeginUpdate;
    try
      with Sender do
      begin
        if SortColumn <> Column then
           SortColumn := Column;
        if SortDirection = sdAscending then
          SortDirection := sdDescending
        else
          SortDirection := sdAscending;
        QuickSortTree(True);
      end;
    finally
      vstTestGrid.EndUpdate;
    end;
  end;
end;

//
// jetzt wird es interessant
//

procedure MyUpdateGrid;
begin
  BeginUpdate;
  try
    if (DBCount > 0) then
    begin
      if (Header.SortDirection = sdAscending) then
        RootNodeCount := DBCount // Aufsteigend, wir müssen nichts machen
      else
      begin
        if (DBCount > VSTCount) then
        begin
          for i := VSTCount+1 to DBCount do
          begin
            Node := vstTestGrid.InsertNode(nil, amInsertBefore); // vorher einfügen
            if Assigned(Node) then
            begin
              vstTestGrid.ReinitNode(Node, False); // Node Initialisierung erzwingen
              Int64(vstTestGrid.GetNodeData(Node)^) := i; // korrekten Wert zuweisen (wäre sonst 1, wegen vstTestGridInitNode)
            end;
          end;
        end;
      end;
      end
      else
        ...
  finally
    vstTestGrid.EndUpdate;
  end;
end;

//
// was noch fehlt: die "Sortierung"
//

procedure TfrmMain.QuickSortTree(ForceSort: Boolean = False);
var
  Grid: TVirtualStringTree;
  Node: PVirtualNode;
  sd: TSortDirection;
  IndexNo: Int64;

  procedure SwapSelection;
  begin
    // hier gehe ich alle Nodes durch, um die Auswahl (Selection)
   // des Benutzers umzukehren
   
   LeftNode := Grid.GetFirst;
    RightNode := Grid.GetLast;

    if not (Assigned(LeftNode) and Assigned(RightNode)) then
      Exit;

    // get starting values
    LeftValue := Int64(Grid.GetNodeData(LeftNode)^);
    RightValue := Int64(Grid.GetNodeData(RightNode)^);

    // swap values if needed
    if LeftValue > RightValue then
    begin
      i := RightValue;
      RightValue := LeftValue;
      LeftValue := i;
    end;

    // Note: We use LeftValue and RightValue to sort only up to the first half
    // of the tree (otherwise we would reset our own swap)

    // iterate through the tree nodes
    while (Assigned(LeftNode) and Assigned(RightNode)) and
      ((RightNode <> LeftNode) and (LeftValue < RightValue)) do
    begin
      // get current selection states
      LeftSelected := vsSelected in LeftNode.States;
      RightSelected := vsSelected in RightNode.States;
      // swap selection
      if (LeftSelected <> RightSelected) then
      begin
        Grid.Selected[LeftNode] := RightSelected;
        Grid.Selected[RightNode] := LeftSelected;
      end;
      // get next nodes
      LeftNode := LeftNode.NextSibling;
      RightNode := RightNode.PrevSibling;
      // adjust iteration helper
      Inc(LeftValue);
      Dec(RightValue);
    end;
  end;

begin
  Grid := vstTestGrid;
  Assert(Assigned(Grid));
  
  // set sorting options
  sd := Grid.Header.SortDirection;
  if (sd = sdAscending) and (not ForceSort) then
    Exit;

  if sd = sdAscending then
    IndexNo := 1
  else
    IndexNo := Grid.RootNodeCount;

  // assign new index values
  Node := Grid.GetFirst;
  while Assigned(Node) do
  begin
    Int64(Grid.GetNodeData(Node)^) := IndexNo;
    if sd = sdAscending then
     Inc(IndexNo)
    else
     Dec(IndexNo);
    Node := Grid.GetNext(Node);
  end;

  // swap node selection
  if (Grid.SelectedCount > 0) then
    SwapSelection;
end;
Das war jetzt nur der Entwurf, die Zuweisung der Selection kann man natürlich über logische Operatoren viel schöner machen. Wichtig war einen Code, der zum Testzeitpunkt verständlich ist (Fehlersuche).

Der Boolean ForceSort der Prozedur QuickSortTree steuert die Vollständigkeit der Sortierung (wird nur im HeaderClick benötigt).
Frederik
  Mit Zitat antworten Zitat