Schnelles Scrollen in Delphis virtuellem Baumview
-
19-09-2019 - |
Frage
Dies ist eine aktualisierte Version einer zuvor veröffentlichten Frage, der vorherige Titel war Auswählen des Knotens nach Index in Delphis virtuellem Baumview.]
Nach dem größten Teil eines Tages glaube ich, dass ich die virtuelle Treeview -Komponente (leistungsstark, aber komplex) in einer einfachen zwei Tabellendaten bearbeitet habe.
Jetzt versuche ich einfach den 1.512. (zum Beispiel) der obersten Knoten auszuwählen. Ich kann keinen anderen Weg sehen, als den ersten Knoten auf der obersten Ebene zu bekommen und dann GetNextsibling 1.511 in einer Schleife zu rufen.
Dies scheint unnötig zu beteiligt. Gibt es einen einfacheren Weg?
AKTUALISIEREN
Da die Initialisierung der Knoten in meinem Baum Datenbankzugriff erfordert, ist die Initialisierung aller Knoten beim Start nicht möglich. Wenn der Benutzer mit einem bereits ausgewählten Datensatz startet, ist das in Ordnung. Wenn der Benutzer um den Baum rollt, werden genügend Knoten besiedelt, um das aktuelle Fenster in den Baum anzuzeigen, und die Leistung ist in Ordnung.
Wenn der Benutzer das Formular im Dialogmodus mit einem bereits ausgewählten Datenbankdatensatz startet, muss ich den Baum zu diesem Knoten vorantreiben, bevor der Benutzer das Formular sieht. Dies ist ein Problem, denn wenn die Aufzeichnung gegen Ende des Baumes liegt, kann es zehn Sekunden dauern, wenn ich den Baum vom ersten Knoten gehe. Jedes Mal, wenn ich GetNextSsibling () kann, wird ein Knoten initialisiert, obwohl die überwiegende Mehrheit dieser Knoten nicht dem Benutzer angezeigt wird. Ich würde es vorziehen, die Initialisierung dieser Knoten bis zu dem Punkt zu verschieben, an dem sie für den Benutzer sichtbar werden.
Ich weiß, dass es einen besseren Weg geben muss. ohne die Knoten initialisieren zu müssen, die ich übersprungen habe.
Dies ist der Effekt, den ich beim Öffnen des Baumes mit einem ausgewählten Datensatz erwerben möchte. Ich kenne den Index des Knotens, zu dem ich gehen möchte, aber wenn ich nicht mit dem Index dort gelangen kann Mitte des Baumes).
Alternativ gibt es vielleicht eine staatliche Einstellung, die ich für die Baumansicht vornehmen kann, die die Zwischenknoten uneinheitlich lässt, wenn ich das Netz durchquere. Ich habe versucht, Start/End -Update zu erzielen, und das scheint den Trick nicht zu tun.
Lösung
Um das Geschwister eines Knotens zu erhalten, ohne es zu initialisieren, verwenden Sie einfach das NextSibling
Zeiger (siehe Erklärung von TVirtualNode
).
Andere Tipps
Die Baumsteuerung ist wie klassische Bäume strukturiert, über die Sie in einer Computer-Science-Klasse erfahren würden. Die einzige Möglichkeit, von der Wurzel des Baumes zum 1512. Kind zu gelangen, besteht darin, die Links einzeln zu wandeln. Egal, ob Sie es selbst tun oder eine Methode der Baumsteuerung verwenden, es muss immer noch so getan werden. Ich sehe nichts, was in der Steuerung selbst bereitgestellt wird, sodass Sie diese Funktion verwenden können:
function GetNthNextSibling(Node: PVirtualNode; N: Cardinal;
Tree: TBaseVirtualTree = nil): PVirtualNode;
begin
if not Assigned(Tree) then
Tree := TreeFromNode(Node);
Result := Node;
while Assigned(Result) and (N > 0) do begin
Dec(N);
Result := Tree.GetNextSibling(Result);
end;
end;
Wenn Sie das oft tun, möchten Sie sich vielleicht zu einem Index machen. Es könnte so einfach sein wie eine Reihe von einer Reihe von PVirtualNode
Zeiger und Speichern aller Werte der obersten Ebene darin, sodass Sie einfach den 1512. Wert daraus lesen können. Die Baumsteuerung ist für eine solche Datenstruktur selbst nicht erforderlich, sodass sie nicht beibehält.
Sie könnten auch überdenken, ob Sie Benötigen Sie eine solche Datenstruktur. Tust du Ja wirklich Müssen Sie auf die Knoten nach Index so zugreifen? Oder könnte stattdessen a beibehalten PVirtualNode
Zeiger, seine Position relativ zum Rest der Knoten im Baum ist keine Rolle mehr (was bedeutet, dass Sie sie beispielsweise sortieren können, ohne den Bezug auf den gewünschten Knoten zu verlieren)?
Sie schreiben in Ihr Update:
Ich weiß, dass es einen besseren Weg geben muss. ohne die Knoten initialisieren zu müssen, die ich übersprungen habe.
Hier gibt es einen Unterschied, da vertikale Scrolling die logische y -Koordinate ändert, die an der Client -Position 0 angezeigt wird. Die Steuerung berechnet den Offset von der Bildlaufleisteposition und dem Bildlaufbereich und berechnet dann, welcher Knoten oben auf der Steuerung sichtbar ist. Knoten werden nur erneut initialisiert, wenn der Bereich, der in Sichtweise gescrollt wurde, gestrichen werden muss.
Wenn Sie die Y -Koordinate eines Knotens haben
function TBaseVirtualTree.GetNodeAt(X, Y: Integer; Relative: Boolean;
var NodeTop: Integer): PVirtualNode;
Die Y -Koordinate eines Knotens ist die Summe der Höhen aller früheren sichtbaren Knoten. Angenommen, Sie haben keine zusammengebrochenen Knoten (entweder handelt es sich also um eine flache Liste von Datensätzen, oder alle Knoten mit untergeordneten Knoten sind erweitert) und alle haben die Standardhöhe, dies ist einfach. Dieser Code sollte ein guter Ausgangspunkt sein:
procedure TForm1.SelectTreeNode(AIndex: integer; ACenterNodeInTree: boolean);
var
Y, Dummy: integer;
Node: PVirtualNode;
begin
Y := Round((AIndex + 0.5) * VirtualStringTree1.DefaultNodeHeight);
Node := VirtualStringTree1.GetNodeAt(0, Y, False, Dummy);
if Node <> nil then begin
Assert(Node.Index = AIndex);
VirtualStringTree1.ScrollIntoView(Node, ACenterNodeInTree);
VirtualStringTree1.Selected[Node] := True;
VirtualStringTree1.FocusedNode := Node;
end;
end;