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