2011-01-31 78 views
3

這個例子當然是簡化,但基本上我有觸發另一種形式(frmSettings)與德爾福:存儲正確的方式對象獲取從TObjectList

function Execute(var aSettings: TSettings):Boolean 

TSettings是我自己的對象主要創建一個主要形式用於跟蹤設置的表單。

在這個新打開的窗體(frmSettings)中,我獲取TMyObjectList,它是TObjectList的後裔。 填上TMyObj

然後我用來自該TMyObjectList的值填充TListBox

代碼:

... 

FMyObjectList : TMyObjectList; 
property MyObjectList: TMyObjectList read getMyObjectList; 

... 

function TfrmSettings.getMyObjectList: TMyObjectList ; 
begin 
    If not Assigned(FMyObjectList) then FMyObjectList := TMyObjectList.Create(True) 
    Result := FMyObjectList; 
end; 

function TfrmSettings.Execute(var aSettings: TSettings): Boolean; 
begin 

    //Fill myObjectList 
    FetchObjs(myObjectList); 

    //Show list to user 
    FillList(ListBox1, myObjectList); 

    //Show form   
    ShowModal; 

    Result := self.ModalResult = mrOk; 

    if Result then 
    begin 
     // Save the selected object, but how?? 

     // Store only pointer? Lost if list is destroyed.. no good 
     //Settings.selectedObj := myObjectList.Items[ListBox1.ItemIndex]; 

     // Or store a new object? Have to check if exist already? 
     If not Assigned(Settings.selectedObj) then Settings.selectedObj := TMyObj.Create; 
     Settings.selectedObj.Assign(myObjectList.Items[ListBox1.ItemIndex];); 
    end; 

end; 

procedure TfrmSettings.FillList(listBox: TListBox; myObjectList: TMyObjectList); 
var 
    i: Integer; 
begin 
    listBox.Clear; 
    With myObjectList do 
    begin 
     for i := 0 to Count - 1 do 
     begin 
      //list names to user 
      listBox.Items.Add(Items[i].Name); 
     end; 
    end; 
end; 

procedure TfrmSettings.FormDestroy(Sender: TObject); 
begin 
    FreeAndNil(FMyObjectList); 
end; 

存儲只是指針似乎不是一個好主意呢,因爲觸發設置再次形成,重新創建列表和原來的對象將丟失即使用戶點擊「取消「

因此,存儲副本似乎更好,使用assign來獲取所有屬性的正確性。首先檢查我是否已經有一個對象。

 If not Assigned(Settings.selectedObj) then Settings.selectedObj := TMyObj.Create; 
     Settings.selectedObj.Assign(myObjectList.Items[ListBox1.ItemIndex];); 

如果我這兩條線移動到一個方法,而不是像Settings.AssignSelectedObj(aMyObj:TMyObj)

這是否看起來是正確的還是我執行這個錯誤的方式? 需要更多/更少的東西?

我需要一些指導方針,所以我覺得更安全,我不打開內存泄漏和其他麻煩。

除了回顧一下代碼,真正的問題是:這是將我的SelectedObject存儲在settings類中的正確方法嗎?

+0

如果沒有被定義(FMyObjectList)然後FMyObjectList.Create(真);是不正確的 - 你應該寫:如果沒有分配(FMyObjectList),那麼FMyObjectList:= TMyObjectList.Create(True); – 2011-01-31 16:09:18

+0

@ A.Bouchez:的確如此。如上所述,它是示例代碼,所以有時候你會很難點擊刪除按鈕。感謝您指出它,編輯! – Bulan 2011-01-31 16:17:30

回答

1

這是將所選對象存儲在設置中的正確方法嗎?

可能不是。您的設置類不應以任何方式依賴於表單。如果您決定每次用戶打開設置時動態創建並銷燬表單,會怎樣?在這種情況下,您的設置將保存無效的對象引用。

恕我直言,最好將對象列表與所選對象的索引一起存儲在設置中。表單應該只是訪問設置,填充列表框並在用戶確認OK後修改所選對象索引。

您正在代碼中產生內存泄漏。你創建一個 TObjectList作爲一個局部變量,但你永遠不會釋放它。如果釋放本地變量,則列表框中的對象引用將無效。你有兩個選擇:

  • 存儲對象列表,表單的成員變量,創建於FromCreate事件處理程序,並在FormDestroy事件處理摧毀它。然後,您可以在列表框中安全地使用對象引用。

  • 商店之外的某處的對象列表,並將其傳遞到表單作爲Execute方法的參數。在這種情況下,您也可以安全地使用對象引用。

+0

對不起,我在嘗試中丟失了一些代碼,所以簡化了它。事實上,我有一個財產,保持對象列表。 郵政現在編輯 – Bulan 2011-01-31 14:27:05

+0

我想我做的Settings.Assign,與設置對象跳過這個問題無關與形式。 存儲整個列表,而不是需要更多的內存? 總之,列表需要每次frmSettings打開時進行更新,因爲它是從數據庫得到的值,和值可以更改。 – Bulan 2011-01-31 14:48:06

0

我將myObjectList重命名爲GlobalObjectList,並將它移出類。它可以在表單中聲明,但是在初始化/結束部分中創建/釋放。在初始化期間,創建列表後,從ini文件(或存儲它的任何位置)填充它。現在,您可以從任何使用您單位的地方訪問它。

0

什麼TSettings的序列化?把你的設置,在一些出版的屬性,然後讓RTTI保存其內容:

type 
    TSettings = class(TPersistent) 
    public 
    function SaveAsText: UTF8String; 
    end; 

function TSettings.SaveAsText: UTF8String; 
begin 
var 
    Stream1, Stream2: TMemoryStream; 
begin 
    Stream1 := TMemoryStream.Create; 
    Stream2 := TMemoryStream.Create; 
    try 
    Stream1.WriteComponent(MyComponent); 
    ObjectBinaryToText(Stream1, Stream2); 
    SetString(result,PAnsiChar(Stream2.Memory),Stream2.Size); 
    finally 
    Stream1.Free; 
    Stream2.Free; 
    end; 
end; 

那麼你的設置可以存儲在一個文本文件或文本字符串。

這只是一個解決方案。但將設置存儲爲文本非常方便。我們在我們的框架中使用這種方法,to store settings via a code-generated user interface。從TPersistent實例樹中創建設置樹。