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.