How to encapsulate IVTEditLink from TVirtualStringTree inside a custom control?

69 Views Asked by At

I have been looking into the Properties demo of Virtual TreeView as I want to implement inplace editors into my application, Editors.pas and PropertiesDemo.pas are of particular interest here.

I will take an extract of the code from Editors.pas:

type
TPropertyEditLink = class(TInterfacedObject, IVTEditLink)
  private
    FEdit: TWinControl;        // One of the property editor classes.
    FTree: TVirtualStringTree; // A back reference to the tree calling.
    FNode: PVirtualNode;       // The node being edited.
    FColumn: Integer;          // The column of the node being edited.
  protected
    procedure EditKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);    
  public
    destructor Destroy; override;
    function BeginEdit: Boolean; stdcall;
    function CancelEdit: Boolean; stdcall;
    function EndEdit: Boolean; stdcall;
    function GetBounds: TRect; stdcall;
    function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
    procedure ProcessMessage(var Message: TMessage); stdcall;
    procedure SetBounds(R: TRect); stdcall;
  end;

implementation

function TPropertyEditLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean;
var
  Data: PPropertyData;
begin
  Result := True;
  FTree := Tree as TVirtualStringTree;
  FNode := Node;
  FColumn := Column;

  // determine what edit type actually is needed
  FEdit.Free;
  FEdit := nil;
  Data := Node.GetData();

  case Data.ValueType of
    vtString:
    begin
      //..
    end;

    vtPickString:
    begin
      FEdit := TComboBox.Create(nil);
      with FEdit as TComboBox do
      begin
        Visible := False;
        Parent := Tree;
        Text := Data.Value;
        Items.Add(Text);
        Items.Add('Standard');
        Items.Add('Additional');
        Items.Add('Win32');
        OnKeyDown := EditKeyDown;
        OnKeyUp := EditKeyUp;
      end;
    end;

    //..

  else
    Result := False;
  end;
end;

I have focused on the PrepareEdit method here as the demo code shows hard coded combo box values.

What I want, is to create a custom composite control that exposes my own public AddProperty methods, psuedo code I have so far looks like this:

type
  TVirtualInspectorTree = class(TWinControl, IVTEditLink)
  private
    FTree: TVirtualStringTree;
  protected
    procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure EditKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure TreeChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
    procedure TreeCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink);
    procedure TreeEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
    procedure TreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
    procedure TreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
    procedure TreeInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
    procedure TreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
    procedure TreePaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
    procedure WMStartEditing(var Message: TMessage); message WM_STARTEDITING;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    function BeginEdit: Boolean; stdcall;
    function CancelEdit: Boolean; stdcall;
    function EndEdit: Boolean; stdcall;
    function GetBounds: TRect; stdcall;
    function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
    procedure ProcessMessage(var Message: TMessage); stdcall;
    procedure SetBounds(R: TRect); stdcall;

    procedure AddProperty(AName: string; AValueType: TValueType);
  end;

{ TVirtualInspectorTree }

constructor TVirtualInspectorTree.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  FTree := TVirtualStringTree.Create(nil);
  FTree.Parent := Self;
  FTree.Align := alClient;
  FTree.Height := 320;
  FTree.Width := 320;    

  FTree.Header.Columns.Add.Text := 'Property';
  FTree.Header.Columns[0].Width := 160;

  FTree.Header.Columns.Add.Text := 'Value';
  FTree.Header.Columns[1].Width := 160;

  FTree.Header.Options := FTree.Header.Options + [hoAutoResize];
  FTree.Header.Options := FTree.Header.Options + [hoVisible];

  FTree.OnChange := TreeChange;
  FTree.OnCreateEditor := TreeCreateEditor;
  FTree.OnEditing := TreeEditing;
  FTree.OnFreeNode := TreeFreeNode;
  FTree.OnGetText := TreeGetText;
  FTree.OnInitChildren := TreeInitChildren;
  FTree.OnInitNode := TreeInitNode;
  FTree.OnPaintText := TreePaintText;

   //QUICK TESTING
  FTree.NodeDataSize := SizeOf(TPropertyData);
end;

destructor TVirtualInspectorTree.Destroy;
begin
  FTree.Free;
  inherited Destroy;
end;

I can't seem to get my head around this. For starters non of the calls to e.g TreeChange TreeCreateEditor etc fire and thus no nodes show at runtime, and secondly I don't even think what I am doing is correct and now I am at a loss.

Simply put I want to create my own custom control, that exposes a AddProperty method, this can then be called and add it's own property items to the Virtual Treeview and e.g, for combobox property types populate it within the TVirtualInspectorTree.

How may I design this and what changes are necessary?

0

There are 0 best solutions below