2016-09-20 82 views
0

我有一個表單,然後我有一個'TPageControl'對象(名爲'MyPages')和一個'TButton'對象(名爲'MyButton')在它上面設計時間。 然後我有一個名爲'TTab'的新類,它擴展了'TTabSheet'。 'TTab'類有一個'TButton'對象作爲其成員變量之一,如下所示。如何將消息從對象傳遞到Free Pascal中的另一個對象

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

我不確定是否正確理解了一切。但是,如果您創建mbtnCloseTab並將Tab作爲其所有者(mbtn_CloseTab:= TButton.Create(self),而不是... Create(nil)),那麼該按鈕會隨選項卡一起自動銷燬。另外,TTab應該有一個Notification方法,當它的一個子節點被銷燬並且你可以使用它來設置mbtn_CloseTab爲零時,它會被調用:這樣可以避免Tab在按鈕被銷燬之前調用按鈕的析構函數一些原因。 –

+0

謝謝您的評論(我認爲沒有人再使用Free Pascal),但它對實際結果沒有影響。 通過使用create(nil),我必須在析構函數中釋放m_btnCloseTab。通過使用Create(Self),TTab類的析構函數會自動執行它。 什麼是通知方法?我如何實現一個?我認爲這是我需要做的事情,有點像C#中的Delegate函數。欣賞它,如果你能指向我的教程或文檔如何做到這一點。 –

+0

你錯了。訪問Lazarus論壇,查看活躍的Pascal社區。 –

回答

0

您可以在整個LCL源代碼(當然也可以在Delphi中)找到通知方法。一個簡單的例子是TLabeledEdit:這是一種包含TLabel的「TEdit」。如果標籤被銷燬,LabeledEdit會被通知,因爲它必須將對標籤的引用設置爲零。否則,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; 

請注意,通知是一個虛擬的方法和必須在組件的受保護部分中使用屬性「覆蓋」進行聲明。

+0

從m_BtnCloseTab的onClick事件處理程序調用Destroy時,它仍然崩潰。 我想了解什麼通知不完全。 什麼事件觸發對通知的調用?通知程序多次被調用,從我開始創建新標籤到實際查殺的時候。 m_BtnCloseTab:= nil; 只在碰撞前被調用。崩潰意味着,我得到以下錯誤: 項目project1引發異常類'外部:SIGSEGV'。 在地址40CDA8 –

+0

按鈕的所有者仍然是零?我可以想象一個被銷燬的對象必須通知其擁有者,因爲這是最終會毀掉它的對象。但是,如果業主沒有,就沒有人被通知...... - 通知深入到LCL(VCL)的核心,由TComponent引入。對於opRemove操作,只要TComponent被銷燬,就會調用它。 –

0

我會爲此任務使用一個按鈕。

從TTab中取出m_btnCloseTab聲明並將其放在私有主窗體中。

然後在你的主窗體的FORMCREATE:

m_btnCloseTab:= TButton的。創建(MyPages);

(以上假設MyPages是在窗體上放置一個組成部分,如果沒有則必須先創建。)

給按鈕頂部和左側,使您TTAB的感覺。

現在,當表單關閉時釋放MyPages時釋放m_btnCloseTab。

現在,您只需創建新標籤,然後只需將該標籤作爲按鈕的父級即可。例如,您可以在MyPages OnChange方法或任何類似方法中執行此操作。

當按鈕被點擊時,它執行類似TTab(Parent).Free;

但是,您可能需要存儲父在按鈕的OnClick一個局部變量,說:

TempTab:TTAB

然後,只需設置TempTab:= TTAB(家長),設置按鈕的母公司爲nil ,然後調用TempTab.Free;

我也會給你的標籤的所有者。這樣,如果用戶在標籤仍然打開的情況下關閉表單(也就是說,您的按鈕沒有被點擊),則所有者將釋放它們。

所以,聲明你的標籤,如:

NEWTAB:= TTab.Create(MyPages);

這應該可以解決您的所有問題,並且在稍微擺弄之後,很容易管理。

最後一個建議我會使用.Free和/或FreeAndNil()方法,而不是直接調用.destroy。

+0

這是一個好主意。當我有空閒時,我會嘗試一下。 目前,在我的實際項目中,我找到了解決方法。而不是釋放選項卡,我只是通過設置TTab.PageControl:= nil在Tabage關閉按鈕被點擊時從TPageControl中移除它們。 在我的應用程序中這不是一個大問題,因爲選項卡的數量是有限的,而且這些選項卡無論如何保存在列表中,當主窗體關閉時將被釋放。我試圖在「隱藏」標籤之前釋放盡可能多的內存,以使應用程序不會感到沉重。 –

相關問題