我有一个表单,然后我在设计时放置了一个'TPageControl'对象(名为'MyPages')和一个'TButton'对象(名为'MyButton')。 然后我有了一个名为'TTab'的新类,它扩展了'TTabSheet'。 'TTab'类有一个'TButton'对象作为其成员变量之一,如下所示。
class TTab = class(TTabSheet)
private
m_btnCloseTab: TButton;
end;
当我点击'MyButton'时,它会创建一个新的'TTab'对象,初始化标签(比如实例化'm_btnCloseTab')并在运行时将其添加到'MyPages' 。
Procedure TForm1.MyButtonClick(Sender:TObject);
var
newTab: TTab;
newCaption: AnsiString;
begin
newCaption:= 'Tab' + IntToStr(count); //count is a global var
inc(count);
newTab:= TTab.Create(nil);
newTab.Init(newCaption);
newTab.Parent(MyPages);
end;
这就是TTab.Init(newCaption:AnsiString)程序的样子。
Procedure TTab.Init(newCaption: AnsiString);
begin
Self.Caption:= newCaption;
m_btnCloseTab:= TButton.Create(nil);
with m_btnCloseTab do begin
Parent:= Self;
Left:= 10;
Top:= 10;
Caption:= 'Close Tab';
Visible:= True;
OnClick:= @closeTab;
end;
end;
这会添加一个新选项卡。关闭按钮也显示在每个选项卡上。
如何点击每个标签上的“m_btnCloseTab”以关闭该特定标签?
如果我为TTab定义一个析构函数(通过覆盖TTabSheet的析构函数),如下所示,我可以从外面调用它。
Destructor TTab.Destroy;
begin
if m_btnCloseTab <> nil then begin
m_btnCloseTab.Destroy;
m_btnCloseTab:= nil;
end;
inherited;
end;
但是我无法从标签内部调用析构函数(好吧,你可以)。如果我这样做,我不能释放m_btnCloseTab对象,因为它会给出异常,因为我们仍然是它的事件处理程序。如果我不释放它,选项卡会很好地关闭,但内存会被泄露(因为我们没有释放m_btnCloseTab)。
我相信我必须触发一个事件,以便可以从'TTab'的外部调用析构函数。我不知道怎么做。
任何帮助将不胜感激。
感谢。
答案 0 :(得分:0)
您可以在整个LCL源中找到通知方法(当然也可以在Delphi中找到)。一个简单的例子是TLabeledEdit:这是某种包含TLabel的“TEdit”。如果Label被销毁,LabeledEdit会收到通知,因为它必须将对标签的引用设置为nil。否则TLabeledEdit的析构函数会再次尝试销毁标签 - BOOM。这里的方法是这样的(从ExtCtrls粘贴):
procedure TCustomLabeledEdit.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (AComponent = FEditLabel) and (Operation = opRemove) then
FEditLabel := nil;
end;
在这里,您可以看到您在案件中必须做的事情:
procedure TTab.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (AComponent = m_BtnCloseTab) and (Operation = opRemove) then
m_BtnCloseTab := nil;
end;
请注意,Notification是一个虚方法,必须在组件的受保护部分中使用属性“override”声明。
答案 1 :(得分:0)
我会用一个按钮完成这项任务。
从TTab中取出m_btnCloseTab声明并将其置于私有主窗体中。
然后在您的主要表单上找到FormCreate:
m_btnCloseTab:= TButton.Create(MyPages);
(以上假设MyPages是放在表单上的组件,如果不是,则必须先创建它。)
将按钮设置为顶部和左侧,这对您的TTab来说是有意义的。
现在释放MyPages时将释放m_btnCloseTab,当表单关闭时将释放它。
现在你要做的就是创建你喜欢的新标签,当一个人专注时,只需将该标签作为按钮的父标签即可。例如,您可以在MyPages OnChange方法或其他类似方法中执行此操作。
单击该按钮时,它会执行类似于TTab(父级).Free;
的操作但是,您可能需要将Parent存储在按钮的OnClick中的本地变量中,例如:
TempTab:TTab
然后只需设置TempTab:= TTab(Parent),将Button的父级设为nil,然后调用TempTab.Free;
我也会给你的标签一个所有者。这样,如果用户在标签仍然打开的情况下关闭表单(也就是说,您的按钮没有被点击),则所有者将释放它们。
请声明您的标签:
newTab:= TTab.Create(MyPages);
这应该可以解决你所有的问题,经过一些摆弄后,很容易管理。
最后一个建议我会使用方法.Free和/或FreeAndNil()而不是直接调用.destroy。