我有一個 TScrollBox,里面有一堆 TPanel 和一些在運行時生成的 TButton。單擊一個 TButton 時,我需要洗掉 TPanel,但在 OnClick 中這樣做會導致訪問沖突...
procedure TMainForm.ButanClick(Sender: TObject);
var
vParentPanel: TPanel;
begin
if (string(TButton(Sender).Name).StartsWith('L')) then
begin
TButton(Sender).Caption := 'YARE YARE DAZE';
end
else
begin
vParentPanel := TPanel(TButton(Sender).GetParentComponent());
TheScrollBox.RemoveComponent(vParentPanel);
vParentPanel.Destroy();
// access violation but the panel is removed
end;
end;
procedure TMainForm.Button3Click(Sender: TObject);
var
i: Integer;
vPanel: TPanel;
vButton: TButton;
begin
for i := 0 to 20 do
begin
vPanel := TPanel.Create(TheScrollBox);
vPanel.Align := alTop;
vPanel.Parent := TheScrollBox;
vButton := TButton.Create(vPanel);
vButton.Align := alLeft;
vButton.Parent := vPanel;
vButton.Name := 'L_butan' IntToStr(i);
vButton.OnClick := ButanClick;
vButton := TButton.Create(vPanel);
vButton.Align := alRight;
vButton.Parent := vPanel;
vButton.Name := 'R_butan' IntToStr(i);
vButton.OnClick := ButanClick;
end;
end;
uj5u.com熱心網友回復:
您不能從'事件中安全地銷毀父級TPanel(或TButton自身) 。在事件處理程式退出后,VCL 仍然需要訪問/ 。因此,您需要將銷毀延遲到處理程式退出之后。最簡單的方法是使用呼叫,例如:TButtonOnClickTPanelTButtonTThread.ForceQueue()TObject.Free()TPanel
procedure TMainForm.ButanClick(Sender: TObject);
var
vButton: TButton;
begin
vButton := TButton(Sender);
if vButton.Name.StartsWith('L') then
begin
vButton.Caption := 'YARE YARE DAZE';
end
else
begin
TThread.ForceQueue(nil, vButton.Parent.Free);
end;
end;
意志在其毀滅期間TPanel將自己從其中移除。TScrollBox您不需要手動處理該步驟。
uj5u.com熱心網友回復:
解決了Renate Schaaf的答案:
...
const
WM_REMOVEPANEL = WM_USER 9001;
procedure ButanClick(Sender: TObject);
procedure OnCustomMessage(var Msg: TMessage); message WM_REMOVEPANEL;
...
procedure TMainForm.ButanClick(Sender: TObject);
var
vParentPanel: TPanel;
begin
if (string(TButton(Sender).Name).StartsWith('L')) then
begin
TButton(Sender).Caption := 'YARE YARE DAZE';
end
else
begin
// SendMessage = access violation again because it wait the return
// while PostMessage return istantly
PostMessage(Handle, WM_REMOVEPANEL, 0, THandle(@Sender));
end;
end;
procedure TMainForm.OnCustomMessage(var Msg: TMessage);
var
vButton: TButton;
begin
if (Msg.Msg = WM_REMOVEPANEL) then
begin
vButton := TButton(Pointer(Msg.LParam)^);
ShowMessage(vButton.Name);
TheScrollBox.RemoveComponent(vButton.GetParentComponent());
TPanel(vButton.GetParentComponent()).Destroy();
Msg.Result := 1;
end
else
Msg.Result := 0;
end;
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/474101.html
