Einzelnen Beitrag anzeigen

Benutzerbild von Jens Hartmann
Jens Hartmann

Registriert seit: 11. Jan 2009
Ort: Wilnsdorf
1.439 Beiträge
 
Delphi XE2 Professional
 
#17

AW: VirtualTreeView Editfelder, ComboBox und andere

  Alt 2. Apr 2016, 07:02
Also das Ding bringt mich noch zur Verzweiflung. Es muss doch möglich sein, eine Komponente wie das VST mit der Tastatur annähernd wie Excel bedienen zu können.

Das mit dem "Enter" führt übrigens mittlerweile (nach dem Übernehmen der Daten in den Node) auch zu einer Exception.

Hier mal der aktuelle Editor...

Delphi-Quellcode:
unit TreeEditors;

interface

uses
  VirtualTrees, Vcl.StdCtrls, Winapi.Windows, System.SysUtils, Winapi.Messages, System.Classes, Vcl.Controls,
  Vcl.Forms, Vcl.Dialogs;

//Eigener Type für die verschiedenen Editfelder (
type
  TEditValueType =
    (evtNone { Kein Editiern möglich },
     evtNumber { Nur Zahlen - Ein TEdit mit "NumbersOnly = true },
     evtString { Text - Ein TEdit },
     evtPickString { Text mit fester Auswahlmöglichkeit - TComboBox }
     );

//Eigene Klasse zur Haltung der Daten
type
  TOMyClass = class
    private
      FAInt : integer; //Spalte 1 im VST - eine Zahl
      FAPickString : string; //Spalte 2 im VST - Eine Text mit fester Auswahlmöglichkeit
      FAString : string; //Spalte 3 im VST - Eine Text
      FBString : string; //Spalte 4 im VST - Eine Text
      FBPickString : string; //Spalte 5 im VST - Eine Text mit fester Auswahlmöglichkeit
    public
      property AInt: integer read FAInt write FAInt;
      property APickString : string read FAPickString write FAPickString;
      property AString : string read FAString write FAString;
      property BString : string read FBString write FBString;
      property BPickString : string read FBPickString write FBPickString;
end;

//Der Datenrecord für das VST
type
  PMyData = ^TMyData;
  TMyData = record
    FValueType: array[0..4] of TEditValueType; //Die Var für den Typ des Editierfeld
    FObject : TObject; //Das Objekt der Daten
    FChanged : Boolean;
end;

//Die Interface-Klasse für den Editor
type
  TEditEditLink = class (TInterfacedObject, IVTEditLink)
  private
    FEdit: TWinControl; //FEdit als TWinControl für die verschiedenen Editormöglichkeiten (TEdit, TComboBox etc.)
    FTree : TVirtualStringTree; //Das VST
    FNode : PVirtualNode; //Das Node
    FColumn : Integer; //Der Column
  protected
    procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); //Für die Steuerung der Editorfelder über Tastatur
    procedure EditKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); //Für die Steuerung der Editorfelder über Tastatur
  public
    destructor Destroy; override; //Zur Freigabe der Editor-Controls beim beenden

    function BeginEdit: Boolean; virtual; stdcall; //Start Editorvorgang
    function CancelEdit: Boolean; virtual; stdcall; //Abbruch Editorvorgang
    function EndEdit: Boolean; virtual; stdcall; //Ende Editorvorgang
    function GetBounds: TRect; virtual; stdcall; //Größe ermitteln
    function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; //Erstellen der jeweiligen Editor - Controls
    procedure ProcessMessage(var Message: TMessage); virtual; stdcall; //Für die Übergabe der Nachrichten des VST an den Editor
    procedure SetBounds(R: TRect); stdcall; //Größe der Editorfelder setzen
  end;

implementation

uses
  fMain;

{ TEditEditLink }

function TEditEditLink.BeginEdit: Boolean;
begin
  //Prüfung um welches Control es sich handelt und entsprechend aktivieren
  if FEdit is TEdit then
      begin
        FEdit.Show; //Anzeigen
        FEdit.SetFocus; //Focus zuweisen
        TEdit(FEdit).SelectAll; //Text im TEdit komplett selektieren
      end
  else if FEdit is TComboBox then
      begin
        FEdit.Show; //Anzeigen
        FEdit.SetFocus; //Focus zuweisen
        TComboBox(FEdit).SelectAll; //Text im TEdit komplett selektieren
      end;
end;

function TEditEditLink.CancelEdit: Boolean;
begin
  Result := True; //Abbruch erfolgt
  FEdit.Hide; //Control auf Visible false
end;

destructor TEditEditLink.Destroy;
begin
  FEdit.Free; //Control nach beenden des Editors wieder freigeben
  inherited;
end;

procedure TEditEditLink.EditKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  ANode : PVirtualNode;
  CanAdvance : Boolean;
  AColumn : TColumnIndex;
begin
  case Key of
    VK_ESCAPE:
      begin
        Key := 0;
      end;
    VK_RETURN:
      begin
        if FEdit is TEdit then
          begin
            FTree.InvalidateNode(FNode);
            if (ssShift in Shift) then
              ANode := FTree.GetPreviousVisible(FNode, True)
            else
              ANode := FTree.GetNextVisible(FNode, True);
            FTree.EndEditNode;
            if ANode <> nil then FTree.FocusedNode := ANode;
            Key := 0;
            if FTree.CanEdit(FTree.FocusedNode, FTree.FocusedColumn) then
              FTree.EditNode(FTree.FocusedNode, FTree.FocusedColumn);
          end
        else
        if FEdit is TComboBox then
          begin
            FTree.InvalidateNode(FNode);
            if (ssShift in Shift) then
              ANode := FTree.GetPreviousVisible(FNode, True)
            else
              ANode := FTree.GetNextVisible(FNode, True);
            FTree.EndEditNode;
            if ANode <> nil then FTree.FocusedNode := ANode;
            Key := 0;
            if FTree.CanEdit(FTree.FocusedNode, FTree.FocusedColumn) then
              FTree.EditNode(FTree.FocusedNode, FTree.FocusedColumn);
          end;
      end;
    VK_TAB:
      begin

      end;
    VK_LEFT,
    VK_RIGHT:
      begin

      end;
    VK_UP,
    VK_DOWN:
      begin
        if FEdit is TEdit then
          begin
            FTree.InvalidateNode(FNode);
            if Key = VK_UP then
              ANode := FTree.GetPreviousVisible(FNode, True)
            else
              ANode := FTree.GetNextVisible(FNode, True);
            FTree.EndEditNode;
            if ANode <> nil then FTree.FocusedNode := ANode;
              Key := 0;
            if FTree.CanEdit(FTree.FocusedNode, FTree.FocusedColumn) then
              FTree.EditNode(FTree.FocusedNode, FTree.FocusedColumn);
          end
        else
        if FEdit is TComboBox then
          begin
            TComboBox(FEdit).DroppedDown := True;
          end;

      end;
  end;
end;

procedure TEditEditLink.EditKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of
    VK_ESCAPE:
      begin
        FTree.CancelEditNode;
        Key := 0;
      end;
  end;
end;

function TEditEditLink.EndEdit: Boolean;
var
  Data: PMyData;
  Buffer: array[0..1024] of Char;
  S: UnicodeString;
  I: Integer;
begin
  Result := True;
  Data := FTree.GetNodeData(FNode);
  case FColumn of
    0:
    begin
      S := TEdit(FEdit).Text;
      if S <> IntToStr(TOMyClass(Data.FObject).FAInt) then
        begin
          TOMyClass(Data.FObject).FAInt := StrToInt(S);
          Data.FChanged := True;
        end;
    end;
    1:
    begin
      S := TComboBox(FEdit).Text;
      if S <> TOMyClass(Data.FObject).FAPickString then
        begin
          TOMyClass(Data.FObject).FAPickString := S;
          Data.FChanged := True;
        end;
    end;
    2:
    begin
      S := TEdit(FEdit).Text;
      if S <> TOMyClass(Data.FObject).FAString then
        begin
          TOMyClass(Data.FObject).FAString := S;
          Data.FChanged := True;
        end;
    end;
    3:
    begin
      S := TEdit(FEdit).Text;
      if S <> TOMyClass(Data.FObject).FBString then
        begin
          TOMyClass(Data.FObject).FBString := S;
          Data.FChanged := True;
        end;
    end;
    4:
    begin
      S := TComboBox(FEdit).Text;
      if S <> TOMyClass(Data.FObject).FBPickString then
        begin
          TOMyClass(Data.FObject).FBPickString := S;
          Data.FChanged := True;
        end;
    end;
  end;
  if Data.FChanged then
    begin
      FTree.InvalidateNode(FNode);
      { z.B. zusätzlich Update Datenbank }
    end;
  FEdit.Hide;
end;

function TEditEditLink.GetBounds: TRect;
begin
  Result := FEdit.BoundsRect; //Größe ermitteln
end;

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

  FEdit.Free;
  FEdit := nil;

  Data := FTree.GetNodeData(FNode);

  FValueType := Data.FValueType[FColumn];

  case FValueType of
    evtNumber:
      begin
        FEdit := TEdit.Create(FTree);
        TEdit(FEdit).OnKeyDown := EditKeyDown;
        TEdit(FEdit).OnKeyUp := EditKeyUp;
        TEdit(FEdit).Text := IntToStr(TOMyClass(Data.FObject).FAInt);
        FEdit.Visible := False;
        FEdit.Parent := FTree;
      end;
    evtString:
      begin
        FEdit := TEdit.Create(FTree);
        TEdit(FEdit).OnKeyDown := EditKeyDown;
        TEdit(FEdit).OnKeyUp := EditKeyUp;
        case FColumn of
          2: TEdit(FEdit).Text := TOMyClass(Data.FObject).FAString;
          3: TEdit(FEdit).Text := TOMyClass(Data.FObject).FBString;
        end;
        FEdit.Visible := False;
        FEdit.Parent := FTree;
      end;
    evtPickString:
      begin
        FEdit := TComboBox.Create(FTree);
        TComboBox(FEdit).OnKeyDown := EditKeyDown;
        TComboBox(FEdit).OnKeyUp := EditKeyUp;
        FEdit.Visible := False;
        FEdit.Parent := FTree;
        case FColumn of
          1:
            begin
              TComboBox(FEdit).Text := TOMyClass(Data.FObject).FAPickString;
              TComboBox(FEdit).Items.Add('Listenauswahl Text 1');
              TComboBox(FEdit).Items.Add('Listenauswahl Text 2');
              TComboBox(FEdit).Items.Add('Listenauswahl Text 3');
              TComboBox(FEdit).Items.Add('Listenauswahl Text 4');
              TComboBox(FEdit).Items.Add('Listenauswahl Text 5');
            end;
          4:
            begin
              TComboBox(FEdit).Text := TOMyClass(Data.FObject).FBPickString;
              TComboBox(FEdit).Items.Add('Zweite Auswahl Text 1');
              TComboBox(FEdit).Items.Add('Zweite Auswahl Text 2');
              TComboBox(FEdit).Items.Add('Zweite Auswahl Text 3');
            end;
        end;
      end
    else
      begin
        Result := False;
      end;
  end;
end;

procedure TEditEditLink.ProcessMessage(var Message: TMessage);
begin
  if Assigned(FEdit) then
    FEdit.WindowProc(Message);
end;

procedure TEditEditLink.SetBounds(R: TRect);
var
  Dummy : Integer;
begin
  FTree.Header.Columns.GetColumnBounds(FColumn, Dummy, R.Right);
  R.Left := Dummy;// + FTree.Margin * 2;
  FEdit.Width := R.Width;
  R.Bottom := Abs(R.Top) + Abs(FTree.NodeHeight[FTree.FocusedNode]);
  InflateRect(R, 0, 1);
  FEdit.BoundsRect := R;
end;

end.
Ich will ja eigendlich nur folgende Funktionen:

VK_ENTER - eine Zeile nach unten
VK_ENTER/SHIFT - eine Zeile nach oben
VK_TAB -eine Spalte nach Links
VK_TAB/Shift - eine Spalte nach Rechts
VK_UP - eine Zeile nach oben
VK_DOWN - eine Zeile nach unten
VK_LEFT - eine Spalte nach links
VK_RIGHT - eine Spalte nach links
Jens Hartmann
Das Leben selber ist zu kurz, also nutze jeden Tag wie er kommt.
  Mit Zitat antworten Zitat