visual recorrido programacion programa podar nodo ejemplos codigo buscar binarios binario arboles arbol delphi pointers interface

delphi - recorrido - podar arbol en c



Almacenamiento del puntero de la interfaz dentro de nodos de vista de árbol (1)

Estoy intentando almacenar punteros de interfaz en una vista de árbol en propiedades TTreeNode.Data . Aunque puedo almacenar un puntero de interfaz ( Node.Data := Pointer(MyInterface); ) no parece funcionar al revés ( MyInterface := ISomeInterface(Node.Data); ). Siempre sale nil .

También intenté usar el conteo manual de referencias, como lo he visto requerido en otra pregunta . Sin embargo, sigue saliendo nil y ahora da pérdidas de memoria.

//Clears tree view and adds drive letters procedure TfrmMain.cmdRefreshBrowseClick(Sender: TObject); var Arr, O: ISuperObject; X: Integer; N, C: TTreeNode; begin //First clear all items and release their interface refs for N in tvBrowse.Items do begin O:= ISuperObject(N.Data); O._Release; end; tvBrowse.Items.Clear; Arr:= ListDirectory(''''); //Returns ISuperObject array listing drives for X := 0 to Arr.AsArray.Length-1 do begin O:= Arr.AsArray.O[X]; N:= tvBrowse.Items.Add(nil, O.S[''drive'']+'':/ [''+O.S[''type'']+'']''); //Add root node N.Data:= Pointer(O); // Assign interface pointer to node data O._AddRef; //Manually increment interface reference count C:= tvBrowse.Items.AddChild(N, ''''); //Add a fake child node end; end; procedure TfrmMain.tvBrowseExpanding(Sender: TObject; Node: TTreeNode; var AllowExpansion: Boolean); var N, C: TTreeNode; P, A, O: ISuperObject; X: Integer; begin //Check first node if it''s a fake node N:= Node.getFirstChild; if N.Text = '''' then begin //if first node is a fake node... P:= ISuperObject(Node.Data); // <-- P always comes out nil here??? N.Delete; //Delete first "fake" node //Get child files/folders if Node.Parent = nil then //If root (drive) node... A:= ListDirectory(P.S[''drive'']+'':/') //Returns ISuperObject array listing files/folders else A:= ListDirectory(P.S[''name'']); //Returns ISuperObject array listing files/folders for X := 0 to A.AsArray.Length-1 do begin O:= A.AsArray.O[X]; C:= tvBrowse.Items.AddChild(N, O.S[''name'']); //Add child node C.Data:= Pointer(O); //Assign interface pointer to node data O._AddRef; //Manually increment reference count end; end; end;

¿Cuál es la forma apropiada de hacer esto?


Esencialmente estás haciendo esto correctamente. Sus conversiones son razonables y comprende la necesidad de realizar un recuento manual de referencias ya que mantiene la referencia en un campo de tipo Pointer que no realiza recuentos de referencia.

P := ISuperObject(Node.Data);

Si a P se le asigna el valor nil significa que Node.Data es igual a nil . No hay nada más que decir. Es de suponer que hay una razón un tanto mundana para que Data sea nil , pero no tiene nada que ver con la forma en que estás emitiendo.

Al mirar tu código, lo criticaría por mezclar todas las preocupaciones juntas. Encontrará esta tarea mucho más fácil si puede mantener un grado de aislamiento entre los diferentes aspectos.

Una forma de simplificar la vida es evitar utilizar los Data puntero sin tipo. En su lugar, use un tipo de nodo personalizado que pueda realizar el recuento de referencias adecuado:

type TMyTreeNode = class(TTreeNode) private FIntf: IInterface; property Intf: IInterface read FIntf write FIntf; end;

Tendrá que manejar el evento OnCreateNodeClass de la vista de árbol para obtener el control para crear su clase de nodo.

procedure TForm1.TreeView1CreateNodeClass(Sender: TCustomTreeView; var NodeClass: TTreeNodeClass); begin NodeClass := TMyTreeNode; end;

Ahora, cada vez que el control tree view crea una instancia de nodo crea uno de tipo TMyTreeNode . Que tiene un campo para contener tu interfaz. Lo he escrito como IInterface aquí, pero usaría la interfaz más específica que se ajuste a sus necesidades. Y, por supuesto, puede agregar cualquier capacidad que desee a su tipo de nodo personalizado.

El enlace leve a esto es que necesita convertir las referencias de nodo de TTreeNode (como lo devuelve el control de vista de árbol subyacente) a TMyTreeNode para obtener acceso a la propiedad de interfaz. Sin embargo, este enlace vale la pena, desde mi punto de vista, ya que puede confiar en el compilador para el tiempo de vida administrado correctamente, y así olvidar todo acerca de ese aspecto del código. Esto le permitirá concentrarse en su programa en lugar de aburrido repetitivo. Continuar por el camino en el que se encuentra actualmente parece una receta para fugas de memoria y violaciones de acceso. Haga que el compilador administre las cosas y puede estar seguro de evitar tales trampas.