Ich habe versucht einen Editor für einen VirtualStringTree auf example von Lazarius Basis zu implementierenZugriffsverletzung nach TStringEditLink erhalten zerstört (TVirtualStringTree) - Lazarus Beispiel
Können Sie mir sagen, warum habe ich eine Zugriffsverletzung erhalten, nachdem TStringEditLink
zerstört wird ?
Es ist verrückt, dass Fehler nur erscheinen, wenn ich ESCAPE oder ENTER drücke. Wenn ich von einer Zelle auf eine andere klicke, gibt es keinen Fehler.
Wie eine Beobachtung säte ich, dass, wenn ich den FEdit.Free
Code von destructor TStringEditLink.Destroy
entferne der Fehler verschwinden.
Haben Sie eine Lösung dafür?
Bellow den vollständigen Code:
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, EditorLink, Vcl.StdCtrls,
Vcl.ExtCtrls, Vcl.Imaging.jpeg;
type
TTreeData = record
Fields: array of String;
end;
PTreeData = ^TTreeData;
const
SizeVirtualTree = SizeOf(TTreeData);
type
TForm2 = class(TForm)
VirtualTree: TVirtualStringTree;
procedure FormCreate(Sender: TObject);
procedure VirtualTreeClick(Sender: TObject);
procedure VirtualTreeCreateEditor(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink);
procedure VirtualTreeEditing(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; var Allowed: Boolean);
procedure VirtualTreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
procedure VirtualTreeGetNodeDataSize(Sender: TBaseVirtualTree;
var NodeDataSize: Integer);
procedure VirtualTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
procedure VirtualTreeNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; NewText: string);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.FormCreate(Sender: TObject);
var
Node: PVirtualNode;
LTreeData: PTreeData;
begin
VirtualTree.Clear;
VirtualTree.BeginUpdate;
//node 1
Node:= VirtualTree.AddChild(nil,nil);
VirtualTree.ValidateNode(Node,False);
LTreeData:= VirtualTree.GetNodeData(Node);
SetLength(LTreeData^.Fields,3);
LTreeData^.Fields[0]:= 'John';
LTreeData^.Fields[1]:= '2500';
LTreeData^.Fields[2]:= 'Production';
//node 2
Node:= VirtualTree.AddChild(nil,nil);
VirtualTree.ValidateNode(Node,False);
LTreeData:= VirtualTree.GetNodeData(Node);
SetLength(LTreeData^.Fields,3);
LTreeData^.Fields[0]:= 'Mary';
LTreeData^.Fields[1]:= '2100';
LTreeData^.Fields[2]:= 'HR';
VirtualTree.EndUpdate;
end;
procedure TForm2.VirtualTreeClick(Sender: TObject);
var
VT: TVirtualStringTree;
Click: THitInfo;
begin
VT:= Sender as TVirtualStringTree;
VT.GetHitTestInfoAt(Mouse.CursorPos.X-VT.ClientOrigin.X, Mouse.CursorPos.Y-VT.ClientOrigin.Y, True, Click);
VT.EditNode(Click.HitNode,Click.HitColumn);
end;
procedure TForm2.VirtualTreeCreateEditor(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink);
begin
EditLink := TStringEditLink.Create;
end;
procedure TForm2.VirtualTreeEditing(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
begin
Allowed:= True;
end;
procedure TForm2.VirtualTreeFreeNode(Sender: TBaseVirtualTree;
Node: PVirtualNode);
var
LTreeData: PTreeData;
begin
LTreeData:= Sender.GetNodeData(Node);
Finalize(LTreeData^);
end;
procedure TForm2.VirtualTreeGetNodeDataSize(Sender: TBaseVirtualTree;
var NodeDataSize: Integer);
begin
NodeDataSize:= SizeVirtualTree;
end;
procedure TForm2.VirtualTreeGetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string);
var
LTreeData: PTreeData;
begin
if Assigned(Node) and (Column > NoColumn) then
begin
LTreeData:= Sender.GetNodeData(Node);
CellText:= LTreeData^.Fields[Column];
end;
end;
procedure TForm2.VirtualTreeNewText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; NewText: string);
var
LTreeData: PTreeData;
begin
LTreeData:= Sender.GetNodeData(Node);
LTreeData^.Fields[Column]:= NewText;
end;
end.
und die EditorLink
Einheit
unit EditorLink;
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs,
VirtualTrees, Messages, Windows, StdCtrls, Vcl.ExtCtrls;
type
TStringEditLink = class(TInterfacedObject, IVTEditLink)
private
FEdit: TWinControl;
FTree: TVirtualStringTree;
FNode: PVirtualNode;
FColumn: Integer;
FStopping: Boolean;
protected
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
uses unit2;
destructor TStringEditLink.Destroy;
begin
FEdit.Free; //--> seems that due to this I get the access violation
inherited;
end;
procedure TStringEditLink.EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
case Key of
VK_ESCAPE:
begin
FTree.CancelEditNode;
Key := 0;
FTree.setfocus;
end;
VK_RETURN:
begin
PostMessage(FTree.Handle, WM_KEYDOWN, VK_DOWN, 0);
Key := 0;
FTree.EndEditNode;
FTree.setfocus;
end;
end; //case
end;
function TStringEditLink.BeginEdit: Boolean;
begin
Result := not FStopping;
if Result then
begin
FEdit.Show;
FEdit.SetFocus;
end;
end;
function TStringEditLink.CancelEdit: Boolean;
begin
Result := True;
FEdit.Hide;
end;
function TStringEditLink.EndEdit: Boolean;
var
s: String;
begin
Result := True;
s := TComboBox(FEdit).Text;
FTree.Text[FNode, FColumn] := s;
FTree.InvalidateNode(FNode);
FEdit.Hide;
FTree.SetFocus;
end;
function TStringEditLink.GetBounds: TRect;
begin
Result := FEdit.BoundsRect;
end;
function TStringEditLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean;
var
FCellText: String;
FCellTextBounds: TRect;
FCellFont: TFont;
begin
Result := True;
FTree := Tree as TVirtualStringTree;
FNode := Node;
FColumn := Column;
FCellFont:= TFont.Create;
FTree.GetTextInfo(FNode, FColumn, FCellFont, FCellTextBounds, FCellText);
FEdit := TComboBox.Create(nil);
with FEdit as TComboBox do
begin
Visible := False;
Parent := Tree;
Items.Add('Google');
Items.Add('Yahoo');
Items.Add('Altavista');
OnKeyDown := EditKeyDown;
Text:= FCellText;
end;
end;
procedure TStringEditLink.ProcessMessage(var Message: TMessage);
begin
FEdit.WindowProc(Message);
end;
procedure TStringEditLink.SetBounds(R: TRect);
var
Dummy: Integer;
begin
FTree.Header.Columns.GetColumnBounds(FColumn, Dummy, R.Right);
FEdit.BoundsRect := R;
end;
end.
Jetzt, seit ich deine Antwort säen, erinnere ich mich, dass ich diesen Code vor einigen Monaten säen. Ich werde es testen und ich werde mit einem Feedback zurückkommen. – REALSOFO
löst das Problem nicht. Das Steuerelement wird zerstört, nachdem 'FTree' und Formular zerstört wurden. Es ist dasselbe, wenn ich 'FEdit.Free' nicht lege. Um zu sehen, wann das 'FEdit' zerstört wird, benutzte ich einen Wrapper' TAltComboBox = class (TComboBox); ... procedure WMDestroy (var Msg: TWMDestroy); Nachricht WM_DESTROY; ' – REALSOFO
Warum benutzen Sie die ziemlich alte V5.3.0? Ist das Problem in der aktuellen V6.3.0 noch vorhanden? –