2011-01-31 3 views
3

이 예제는 물론 단순화에서 가져온 객체하지만 기본적으로 나는 내 자신의 개체 메인에 생성됩니다델파이 : 저장소에 올바른 방법은 TObjectList와

function Execute(var aSettings: TSettings):Boolean 

TSettings와 다른 형태 (frmSettings)을 트리거하는 기본 폼이 양식을 추적하기위한 양식.

새로 열린이 양식 (frmSettings)에서 나는 TObjectList의 자손 인 TMyObjectList을 가져옵니다. 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; 

설정을 트리거로, 단지 포인터가 좋은 생각으로 보이지 않는다 저장 다시 형성, "목록을 재현하고 원래 목적은 심지어 사용자의 조회수가 삭제 될 수 취소 "

그래서 복사본을 저장하면 할당을 사용하여 모든 속성이 올바로 표시됩니다. 먼저 객체가 있는지 먼저 확인하십시오.

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

나는이 올바른 보입니까 대신 Settings.AssignSelectedObj(aMyObj:TMyObj)

같은 방법으로 두 줄을 이동해야하거나 나는이 길을 잘못 구현 무엇입니까? 더/덜 필요한 것이 있습니까?

나는 메모리 누수 및 기타 문제가 발생하지 않도록보다 안전하다고 느끼기 위해 몇 가지 지침이 필요합니다.

코드를 검토하는 것 외에 다른 질문이 있습니다. 이 설정 방법은 SelectedObject를 설정 클래스에 저장하는 올바른 방법입니까?

+0

할당되지 않은 경우 (FMyObjectList) FMyObjectList.Create (True); 올바르지 않습니다 - 작성해야합니다 : 할당되지 않은 경우 (FMyObjectList) 다음 FMyObjectList : = TMyObjectList.Create (True); –

+0

@ A.Bouchez : 참. 명시된 바와 같이, 그것은 예제 코드이기 때문에 때로는 삭제 버튼을 너무 세게 치기도합니다. 그래도 그것을 지적 해 주셔서 고맙다, 편집! – Bulan

답변

1

선택한 개체를 설정에 저장하는 올바른 방법입니까?

아마도 그렇지 않습니다. 설정 클래스는 어떤 식 으로든 양식에 의존해서는 안됩니다. 사용자가 설정을 열 때마다 동적으로 양식을 작성하고 삭제하기로 결정하면 어떻게됩니까? 이 경우 설정에 잘못된 개체 참조가 포함됩니다.

이 개체 목록을 선택한 개체의 인덱스와 함께 설정에 저장하는 것이 좋습니다. 양식은 사용자가 OK로 확인한 후에 설정을 액세스하고 목록 상자를 채우고 선택한 개체 인덱스를 수정해야합니다.

코드에서 메모리 누수가 발생하고 있습니다. TObjectList을 로컬 변수로 만들지 만 결코 자유롭게 만들 수는 없습니다. 로컬 변수를 비우면 목록 상자의 객체 참조가 유효하지 않게됩니다. 양식의 멤버 변수로

  • 스토어 오브젝트 목록에서 FromCreate 이벤트 처리기에서 작성하고 FormDestroy 이벤트 처리기에서 파괴 : 당신은 두 가지 옵션이 있습니다. 그런 다음 목록 상자에서 안전하게 개체 참조를 사용할 수 있습니다.

  • 외부 개체 목록을 저장하고 Execute 메서드의 매개 변수로 양식에 전달하십시오. 이 시나리오에서는 안전하게 개체 참조를 사용할 수도 있습니다.

+0

죄송합니다. 제 코드를 일부 잃어 버려서 단순화했습니다. 사실 나는 개체 목록을 유지하는 속성이 있습니다. 게시물이 수정되었습니다 – Bulan

+0

Settings 개체가 해당 폼과 관련이 없으므로 Settings.Assign을 수행하여이 문제를 건너 뛰었습니다. 대신 전체 목록을 저장하면 더 많은 메모리가 필요하지 않습니까? 아무튼 frmSettings가 열릴 때마다 목록을 업데이트해야합니다. 데이터베이스에서 값을 가져오고 값이 변경 될 수 있기 때문입니다. – Bulan

+0

TSettings에서 TSettings에 새 객체를 만들었 기 때문에 TSettings가 양식과 관련이 없다는 의견이 있습니까? – Bulan

0

myObjectList의 이름을 GlobalObjectList로 바꾸고 클래스 외부로 옮깁니다. 그것은 형식으로 선언 될 수 있지만 초기화/종료 섹션에서 생성/해제됩니다. 초기화하는 동안 목록을 만든 후 ini 파일 (또는 사용자가 저장 한 곳)에서 채 웁니다. 이제는 사용중인 유닛이있는 곳 어디에서나 액세스 할 수 있습니다.

+0

죄송합니다. 시도를 위해 일부 코드를 잃어 버렸습니다. 사실 나는 개체 목록을 유지하는 속성이 있습니다. 포스트가 수정되었습니다 – Bulan

0

TSettings의 직렬화는 어떻게됩니까? 일부 published 속성에서 설정을 넣어, 다음 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 인스턴스의 트리에서 설정 트리가 생성됩니다.

+0

질문에 대한 질문 : 이것은 선택한 개체를 설정에 저장하는 올바른 방법입니까? TSettings 객체를 나중에 저장하는 방법은 아니지만 어쨌든 해당 코드를 공유해 주셔서 감사합니다. 다른 프로젝트에서도 사용할 수 있습니다. – Bulan

+0

@Bulan 네, 당신 문제를 이해했다고 생각합니다. 그러나 이러한 공유 TObjectList를 사용하면 TP 지속성 계층 구조보다 덜 바람직합니다. 목록을 사용하면 선형 목록 만 가질 수 있습니다. TP 지속 형 계층 구조를 사용하면 클래스 내에 임베드 된 클래스를 나열한 다음 목록으로 설정하지 않고 트리로 표시 할 수 있습니다.이 트리는 사용자 환경에 더 좋습니다 (IMHO). 텍스트 저장은 이것의 "보너스"부분 일뿐입니다. 물론 나는 당신의 코드 문제를 수정하지 않고 단지 아키텍처 변경을 제안한다. –

관련 문제