AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

EditLinks für TVirtualStringTree erstellen

Ein Thema von djmasi · begonnen am 28. Aug 2004 · letzter Beitrag vom 28. Aug 2004
Antwort Antwort
djmasi

Registriert seit: 9. Jun 2004
Ort: Leipzig
105 Beiträge
 
Delphi 7 Enterprise
 
#1

EditLinks für TVirtualStringTree erstellen

  Alt 28. Aug 2004, 13:31
Hallo Leute,

langsam verstehe ich den VST. Habe mir für die Bearbeitung eine ComboBox gebastelt und sie nach Anleitung der Hilfe von VST eingebunden. Allerdings bin ich in der Komponentenentwicklung noch "unterentwickelt", heißt ich habe nch gar keine Erfahrungen damit.

Als erstes: es läuft alles wie's soll, aber:
  • ich musste den Sourcecode direkt in die VirtualTrees.pas einbinden, da ich sonst nicht auf alle Eigenschaften (da protected) zugreifen konnte. Eigentlich wollte ich dafür ne eigene Unit erstellen
  • Ich musste, um die ComboBox zu füllen, bei dem Vorfahren IVTEditLink eine Procedure einfügen. Das ist bestimmt nicht im Sinne des Erfinders.

So, wenn ihr Zeit und Lust habt schaut euch das bitte mal an und sagt mir bitte, wie ich die obigen Punkte "beheben" kann.


Als erstes muss halt die Procedur SetItems eingefügt werden:
Delphi-Quellcode:
  IVTEditLink = interface
    ['{2BE3EAFA-5ACB-45B4-9D9A-B58BCC496E17}']
    function BeginEdit: Boolean; stdcall; // Called when editing actually starts.
    function CancelEdit: Boolean; stdcall; // Called when editing has been cancelled by the tree.
    function EndEdit: Boolean; stdcall; // Called when editing has been finished by the tree.
    function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
                                                           // Called after creation to allow a setup.
    function GetBounds: TRect; stdcall; // Called to get the current size of the edit window
                                                           // (only important if the edit resizes itself).
    procedure ProcessMessage(var Message: TMessage); stdcall;
                                                           // Used to forward messages to the edit window(s)-
    procedure SetBounds(R: TRect); stdcall; // Called to place the editor.
    procedure SetItems(List: TStringList); stdcall;
  end;
Dann hab ich mir die ComboBox erstellt:
Delphi-Quellcode:
  TVTComboBox = class(TCustomComboBox)
  private
    FRefLink: IVTEditLink;
    FLink: TComboBoxEditLink;
    procedure CMAutoAdjust(var Message: TMessage); message CM_AUTOADJUST;
    procedure CMExit(var Message: TMessage); message CM_EXIT;
    procedure CMRelease(var Message: TMessage); message CM_RELEASE;
    procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
    procedure WMChar(var Message: TWMChar); message WM_CHAR;
    procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY;
    procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
    procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
  protected
    procedure AutoAdjustSize;
    procedure CreateParams(var Params: TCreateParams); override;
  public
    constructor Create(Link: TComboBoxEditLink); reintroduce;
    procedure Release; virtual;
    property AutoComplete;
    property CharCase;
    property Items;
    property MaxLength;
    property Sorted;
    property Style;
  end;
Und als nächstes den EditLink:
Delphi-Quellcode:
  TComboBoxEditLink = class(TInterfacedObject, IVTEditLink)
  private
    FList: TStringList;
    FEdit: TVTComboBox;
    FTree: TCustomVirtualStringTree;
    FNode: PVirtualNode;
    FColumn: TColumnINdex;
    FAlignment: TAlignment;
    FTextBounds: TRect;
    FStopping: Boolean;
    FStartIndex: Integer;
    procedure SetEdit(const Value: TVTComboBox);
  public
    constructor Create;
    destructor Destroy; override;

    function BeginEdit: Boolean; virtual; stdcall;
    function CancelEdit: Boolean; virtual; stdcall;
    property ComboBoxEdit: TVTComboBox read FEdit write SetEdit;
    function EndEdit: Boolean; virtual; stdcall;
    function GetBounds: TRect; virtual; stdcall;
    function PrepareEdit(Tree: TBaseVirtualTree;
                         Node: PVirtualNode;
                         Column: TColumnIndex): Boolean; virtual; stdcall;
    procedure ProcessMessage(var Message: TMessage); virtual; stdcall;
    procedure SetBounds(R: TRect); virtual; stdcall;
    procedure SetItems(List: TStringList); virtual; stdcall;
  end;
Hier die Funktionen/Procedure für die TVTComboBox
Delphi-Quellcode:
//******************************************************************************
//******************************************************************************
//******************************************************************************

constructor TVTComboBox.Create(Link: TComboBoxEditLink);
begin
  inherited Create(nil);
  ShowHint := False;
  ParentShowHint := False;
  FRefLink := Link;
  FLink := Link;
end;

//******************************************************************************

procedure TVTComboBox.CMAutoAdjust(var Message: TMessage);
begin
  AutoAdjustSize;
end;

//******************************************************************************

procedure TVTComboBox.CMExit(var Message: TMessage);
begin
  if Assigned(FLink) and NOT FLink.FStopping then
    with FLink, FTree do
    begin
      if (toAutoAcceptEditChange in TreeOptions.StringOptions) then
        DoEndEdit
      else
        DoCancelEdit;
    end;
end;

//******************************************************************************

procedure TVTComboBox.CMRelease(var Message: TMessage);
begin
  Free;
end;

//******************************************************************************

procedure TVTComboBox.CNCommand(var Message: TWMCommand);
begin
  if Assigned(FLink) and
     Assigned(FLink.FTree) and
     (Message.NotifyCode = EN_UPDATE) and
      NOT (toGridExtensions in FLink.FTree.FOptions.FMiscOptions) and
      NOT (vsMultiLine in FLink.FNode.States) then
    if False and IsWinNT then
      AutoAdjustSize
    else
      PostMessage(Handle, CM_AUTOADJUST, 0, 0);
end;

//******************************************************************************

procedure TVTComboBox.WMChar(var Message: TWMChar);
begin
  if NOT (Message.CharCode in [VK_ESCAPE, VK_TAB]) then
    inherited;
end;

//******************************************************************************

procedure TVTComboBox.WMDestroy(var Message: TWMDestroy);
begin
  if Assigned(FLink) and NOT FLink.FStopping then
  begin
    with FLink, FTree do
    begin
      if (toAutoAcceptEditChange in TreeOptions.StringOptions) and DroppedDown then
        Text[FNode, FColumn] := FEdit.Text;
    end;
    FLink := nil;
    FRefLink := nil;
  end;
  inherited;
end;

//******************************************************************************

procedure TVTComboBox.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  inherited;
  Message.Result := Message.Result or
                    DLGC_WANTALLKEYS or
                    DLGC_WANTTAB or
                    DLGC_WANTARROWS;
end;

//******************************************************************************

procedure TVTComboBox.WMKeyDown(var Message: TWMKeyDown);
var
  Shift: TShiftState;
  EndEdit: Boolean;
  Tree: TBaseVirtualTree;
begin
  case Message.CharCode of
    VK_ESCAPE:
      begin
        Tree := FLink.FTree;
        FLink.FTree.DoCancelEdit;
        Tree.SetFocus;
      end;
    VK_RETURN:
      begin
        EndEdit := NOT (vsMultiLine in FLink.FNode.States);
        if NOT EndEdit then
        begin
          Shift := KeyDataToShiftState(Message.KeyData);
          EndEdit := ssCtrl in Shift;
        end;
        if EndEdit then
        begin
          Tree := FLink.FTree;
          FLink.FTree.InvalidateNode(FLink.FNode);
          FLink.FTree.DoEndEdit;
          Tree.SetFocus;
        end;
      end;
    VK_UP:
      begin
        if NOT (vsMultiLine in FLink.FNode.States) then
          Message.CharCode := VK_LEFT;
        inherited;
      end;
    VK_DOWN:
      begin
        if NOT (vsMultiLine in FLink.FNode.States) then
          Message.CharCode := VK_RIGHT;
        inherited;
      end;
  else
    inherited;
  end;
end;

//******************************************************************************

procedure TVTComboBox.AutoAdjustSize;
var
  DC: HDC;
  Size: TSize;
  LastFont: THandle;
begin
  if NOT (vsMultiLine in FLink.FNode.States) then
  begin
    SendMessage(Handle, WM_SETREDRAW, 0, 0);
    DC := GetDC(Handle);
    LastFont := SelectObject(DC, Font.Handle);
    try
      GetTextExtentPoint32(DC, PChar(Text), Length(Text), Size);
      Inc(Size.cx, 2 * FLink.FTree.FTextMargin);

      if Size.cx < Width then
        FLink.FTree.InvalidateNode(Flink.FNode);
      if FLink.FAlignment = taRightJustify then
        FLink.SetBounds(Rect(Left + Width - Size.cx, Top, Left + Width, Top + Height))
      else
        FLink.SetBounds(Rect(Left, Top, Left + Size.cx, Top + Height));
    finally
      SelectObject(DC, LastFont);
      ReleaseDC(Handle, DC);
      SendMessage(Handle, WM_SETREDRAW, 0, 0);
    end;
  end;
end;

//******************************************************************************

procedure TVTComboBox.CreateParams(var Params: TCreateParams);
begin
  inherited;
  with Params do
  begin
    Style := Style or ES_MULTILINE;
    if (vsMultiLine in FLink.FNode.States) then
      Style := Style and NOT (ES_AUTOHSCROLL or WS_HSCROLL) or WS_VSCROLL or ES_AUTOVSCROLL;
    if (tsUseThemes in FLink.FTree.FStates) then
    begin
      Style := Style and NOT WS_BORDER;
      ExStyle := ExStyle or WS_EX_CLIENTEDGE;
    end
    else
    begin
      Style := Style or WS_BORDER;
      ExStyle := ExStyle and NOT WS_EX_CLIENTEDGE;
    end;
  end;
end;

//******************************************************************************

procedure TVTComboBox.Release;
begin
  if HandleAllocated then
    PostMessage(Handle, CM_RELEASE, 0, 0);
end;

//******************************************************************************
//******************************************************************************
//******************************************************************************
Und zum Schluss das ganze für den TComboBoxEditLink:
Delphi-Quellcode:
//******************************************************************************
//******************************************************************************
//******************************************************************************
constructor TComboBoxEditLink.Create;
begin
  inherited;
  FEdit := TVTComboBox.Create(Self);
  with FEdit do
  begin
    Visible := False;
    AutoSize := False;
    AutoComplete := False;
    Style := csDropDownList;
    Sorted := True;
  end;
end;

//******************************************************************************

destructor TComboBoxEditLink.Destroy;
begin
  FEdit.Release;
  inherited;
end;

//******************************************************************************

function TComboBoxEditLink.BeginEdit: Boolean;
begin
  Result := NOT FStopping;
  if Result then
  begin
    FEdit.Show;
    FEdit.SetFocus;
  end;
end;

//******************************************************************************

procedure TComboBoxEditLink.SetEdit(const Value: TVTComboBox);
begin
  if Assigned(FEdit) then
    FEdit.Free;
  FEdit := Value;
end;

//******************************************************************************

function TComboBoxEditLink.CancelEdit: Boolean;
begin
  Result := NOT FStopping;
  if Result then
  begin
    FStopping := True;
    FEdit.Hide;
    FTree.CancelEditNode;
    FEdit.FLink := nil;
    FEdit.FRefLink := nil;
  end;
end;

//******************************************************************************

function TComboBoxEditLink.EndEdit: Boolean;
begin
  Result := NOT FStopping;
  if Result then
  try
    FStopping := True;
    if FEdit.ItemIndex <> FStartIndex then
      FTree.Text[FNode, FColumn] := FEdit.Text;
    FEdit.Hide;
    FEdit.FLink := nil;
    FEdit.FRefLink := nil;
  except
    FStopping := False;
  end;
end;

//******************************************************************************

function TComboBoxEditLink.GetBounds: TRect;
begin
  Result := Fedit.BoundsRect;
end;

//******************************************************************************

function TComboBoxEditLink.PrepareEdit(Tree: TBaseVirtualTree;
                                       Node: PVirtualNode;
                                       Column: TColumnIndex): Boolean;
var
  Text: WideString;
  i: Integer;
begin
  FStartIndex := -1;
  Result := Tree is TCustomVirtualStringTree;
  if Result then
  begin
    FTree := Tree as TCustomVirtualStringTree;
    FNode := Node;
    FColumn := Column;
    FTree.GetTextInfo(Node, Column, FEdit.Font, FTextBounds, Text);
    FEdit.Font.Color := clBlack;
    FEdit.Parent := Tree;
    FEdit.RecreateWnd;
    FEdit.HandleNeeded;
    if Assigned(FList) then
    begin
      for i := 0 to FList.Count-1 do
      begin
        FEdit.Items.Add(FList.Strings[i]);
        if FEdit.Items.Strings[i] = Text then
          FEdit.ItemIndex := i;
      end;
      FStartIndex := FEdit.ItemIndex;
    end;
    if Column <= NoColumn then
    begin
      FEdit.BiDiMode := FTree.BiDiMode;
      FAlignment := FTree.Alignment;
    end
    else
    begin
      FEdit.BiDiMode := FTree.Header.Columns[Column].BiDiMode;
      FAlignment := FTree.Header.Columns[Column].Alignment;
    end;

    if FEdit.BiDiMode <> bdLeftToRight then
      ChangeBidiModeAlignment(FAlignment);
  end;
end;

//******************************************************************************

procedure TComboBoxEditLink.ProcessMessage(var Message: TMessage);
begin
  FEdit.WindowProc(Message);
end;

//******************************************************************************

procedure TComboBoxEditLink.SetBounds(R: TRect);
var
  Offset: Integer;
begin
  if NOT FStopping then
  begin
    with R do
    begin
      if Left < 0 then
        Left := 0;
      if Right - Left < 30 then
      begin
        if FAlignment = taRightJustify then
          Left := Right - 30
        else
          Right := Left + 30;
      end;
      if Right > FTree.ClientWidth then
        Right := FTree.ClientWidth;
      FEdit.BoundsRect := R;

      R := FEdit.ClientRect;
      Offset := 2;
      if (tsUseThemes in FTree.FStates) then
        Inc(Offset);
      InflateRect(R, -FTree.FTextMargin + Offset, Offset);
      if NOT (vsMultiLine in FNode.States) then
        OffsetRect(R, 0, FTextBounds.Top - FEdit.Top);
      SendMessage(FEdit.Handle, EM_SETRECTNP, 0, Integer(@R));
    end;
  end;
end;

//******************************************************************************

procedure TComboBoxEditLink.SetItems(List: TStringList);
var
  i: Integer;
begin
  FList := TStringList.Create;
  for i := 0 to List.Count - 1 do
  begin
    FList.Add(List.Strings[i]);
  end;
end;

//******************************************************************************


//******************************************************************************
//******************************************************************************
//******************************************************************************

Eingebunden habe ich das dann über das OnCreateEditor-Ereignis des VST:
Delphi-Quellcode:
procedure TFMain.VSTLibraryCreateEditor(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink);
begin
  case Column of
    3:
      begin
        EditLink := TComboBoxEditLink.Create;
        EditLink.SetItems(GenreList);
      end;
    else EditLink := TStringEditLink.Create;
  end;
end;
GenreList ist übrigens vom Typ TStringList


So, ich hoffe ich hab euch jetzt nicht mit Code erschlagen
Thomas Maßmann
"...ihr würdet selbst den lieben Gott einbetonieren, wenn eure Datenbank ihn eines Tag's erfasst..."
H.-R.-Kunze
Auch Delphi 9 Preview-Inhaber bin
  Mit Zitat antworten Zitat
Benutzerbild von APP
APP

Registriert seit: 24. Feb 2003
Ort: Graz (A)
705 Beiträge
 
Delphi 7 Enterprise
 
#2

Re: EditLinks für TVirtualStringTree erstellen

  Alt 28. Aug 2004, 16:28
Hallo Thomas,
ich habe Deinen Code jetzt nicht durchgesehen, aber es gibt bei den VirtualTree-Demos unter "Advanced" die PropertiesDemo.


Delphi-Quellcode:
// Virtual Treeview sample form demonstrating following features:
// - Property page like string tree with individual node editors.
// - Incremental search.
// Written by Mike Lischke.
Dabei demonstriert Mike z.B. einen NodeEditor mit einer ComboBox, vielleicht wirst Du ja dort fündig.
Das Patchen der VirtualTrees.pas würde ich nicht empfehlen.
Armin P. Pressler

BEGIN
...real programmers are using C/C++ - smart developers Delphi;
END;
  Mit Zitat antworten Zitat
djmasi

Registriert seit: 9. Jun 2004
Ort: Leipzig
105 Beiträge
 
Delphi 7 Enterprise
 
#3

Re: EditLinks für TVirtualStringTree erstellen

  Alt 28. Aug 2004, 16:50
Das hab ich mir auch schon angesehen. Als ich es so probiert habe, ist mein ganzes Projekt gecrashed. Zum Glück hatte ich ein Backup

Am besten lernt man durch probieren...

PS: Anbei mal ein Bild wie's aussieht
Miniaturansicht angehängter Grafiken
tvtcombobox.jpg  
Thomas Maßmann
"...ihr würdet selbst den lieben Gott einbetonieren, wenn eure Datenbank ihn eines Tag's erfasst..."
H.-R.-Kunze
Auch Delphi 9 Preview-Inhaber bin
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:54 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz