2010-06-02 58 views
4

這可能看起來有點新手,但我真的有問題。我有一個表單(不是主要的),用於從用戶獲取許多不同的數據,我想將它傳遞給管理員類來創建一個具有這些數據的對象。問題是我不能讓這個類使用其他單元(獲得循環使用),也不能訪問管理類實例(主要是以形式存在)。如何在Delphi中的表單之間傳遞數據?

那麼,我該怎麼辦?我已經考慮過使用公共變量,但我對它有不好的感覺(關於OOD模式)。

+0

你能否詳細說明你的表格位。我不確定我是否瞭解了你擁有什麼樣的形式,誰發起了他們,誰需要創建對象,並將其傳遞給誰。 – Ivan 2010-06-02 08:55:44

+0

整個程序是這樣的: 啓動屏幕啓動一個窗體(form1)從用戶獲取數據。並且當用戶單擊form1上的OK時,它需要將捕獲的數據發送到另一個類(管理器)以使用這些數據創建一個對象並使用它。 splash和form1都應該關閉,發送後我不再需要它們了。 – Mahm00d 2010-06-02 09:08:56

回答

6

我的建議是從去耦GUI的數據,因爲這會導致你的問題。 如果你有一個從用戶收集數據的表單,那麼你應該區分表單中的數據(TForm)。

例如,我們假設您有一些TForm的實例和一個從三個字段(用戶名,年齡和位置)構建的表單。你希望用戶輸入那些樹的東西,但是當用戶關閉表單時,你應該將插入的數據傳遞給某個對象。表單關閉,它被釋放,但對象仍然存在。然後你將這個對象傳遞給你的經理對象。

簡單的例子:

這是您的記錄將保存數據

type 
    TGatheredData = record 
    Name: String[40]; 
    Age: Byte; 
    Location: String[40]; 
end; 

你TForm1可能有一個aditional的構造函數:

constructor TForm1.Create(AOwner: TComponent; var GatheredData: TGatheredData); 
begin 
    inherited Create(AOwner); 
    FGatheredData := GatheredData; 
    //you may want to deserialize GatheredData here and show the data in your form controls 
end; 

你叫它,通過GatheredData然後你正在展示你的表格。

接下來,在關閉表單時,您從表單控件中選取更新數據。

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
    if Self.ModalResult = mrOk then 
    begin 
    //serialize your object 
    FGatheredData.Name := '';//name taken from control f.e. TEdit 
    FGatheredData.Age := '';//name taken from control f.e. TSpinButton 
    FGatheredData.Location := '';//name taken from control f.e. TEdit 
    end; 
end; 

有了這個記錄的數據,你現在可以以相同的方式將它傳遞給你的管理器對象。 以這種方式從GUI中分離數據,並且可以輕鬆地將記錄插入到多種不同的表單中。

只記得在外部單位申報你的記錄類型,並在你的經理單位和形式單位使用該單位。

希望這會有所幫助。

+0

非常感謝您的詳細和精彩的回答。 也許我問過這個問題,或者沒有提供好的細節。我已經解耦了代碼(我的經理類在不同的單元中)並且與表單無關。 問題是,即使我使用記錄進行存儲,如何將其傳遞給經理?它在表單類中,表單無法訪問管理器類(我更喜歡它不是!)。那麼,你如何傳遞它呢? 我希望經理有權訪問各種表格,而不是反之亦然。 – Mahm00d 2010-06-02 10:25:36

+0

也許我不明白。你應該有至少三個單位。 1 - 僅包含數據的定義,2 - 一個單元,包含將數據作爲參數的Manager類和3 - 將數據作爲參數的表單。你的經理到底在幹什麼? – Wodzu 2010-06-02 10:56:45

+0

就是這樣。我也有一個不同於接收數據的主窗體。如果你知道OOD模式,我的經理是一個UI的主管,他管理表單之間的數據並進行修改。 管理者究竟做什麼並不重要。 我用不同的方式問我的問題: 有沒有辦法將數據傳遞給一個類的實例,而無需直接訪問它(不需要在界面中使用「...」)? – Mahm00d 2010-06-02 11:22:51

1

要解決循環引用錯誤,請在實現部分中使用該單元。

implementation 
{$R *.DFM} 

Uses <Your Unit>; 

end. 
+0

我知道這種方法,但我期待着其他的可能性。 無論如何,謝謝。 – Mahm00d 2010-06-02 09:13:45

3

「經理級」不應該是任何一種形式的單位,而應該是它自己的單位。通過從商業邏輯中分離GUI代碼,可以避免類似這樣的問題。

2

[編輯:我最初把這個答案放在評論中,但決定將它移出到完整答案。在Delphi中,TDatamodules太重要,太常見了,不會強調它們,它們提供了內置的易於使用的從邏輯和數據中分離gui的方法。]

其他人對於將gui從邏輯中解耦和數據。令人驚訝的是,我不認爲有人提到在Delphi中,TDatamodules是做這件事的一個主要手段。您將數據和邏輯放在Datamodule上,然後使用這兩種形式「使用」Datamodule來訪問其數據和方法。這裏是簡短的介紹:http://delphi.about.com/od/database/l/aa101601a.htm

您的表單(和其他形式)都可以訪問Datamodule單元中/上的數據集或其他數據/數據結構。應該有一個簡單的示例項目來說明設置,因爲它是(或者至少是)構建Delphi應用程序的標準方式。

+0

+1爲您的良好解決方案。這似乎很容易設置和使用大而難以理解的數據庫的好替代品。 這是將日期與其他組件分開的好方法。 謝謝。 – Mahm00d 2010-06-06 10:07:48

+0

@菲歐姆 - 很高興聽到。要清楚的是,使用Datamodule本身與存儲數據的方式無關。你的datamodule可以包含訪問數據庫中數據的組件,帶有表單組件(如TStringList)的數據結構,或完全用代碼創建的數據結構。無論你在做什麼,將共享數據放在數據模塊中並讓所有需要訪問數據的表單都使用數據模塊單元是一個好主意。 – 2010-06-07 00:48:57

0

有了這個3個單元: FormMain FormEdit UnitMyClass

您在FormMain創建對象,並把它傳遞給FormEdit的功能,如:

class function FormEdit.EditMyObject(AObject: TMyClass): boolean; 

此功能會的ShowModal形式。表單將對對象進行更改,如果用戶按下確定,則最終返回True。

正如你可以看到UnitMyClass沒有提及FormMain或FormEdit

2

如果我理解你的問題正確,那麼你想要的經理來管理形式(不訪問管理器的形式)。對?您不能關閉主窗體,就好像您關閉應用程序一樣,但您可以隱藏它。 (除非你創建一個控制檯應用程序)。但它提出了一個可愛的小問題:)

所以...飛濺的形式(主要形式)是:

。 。 。

uses 
    ManagerU; 

type 
    TFormSplash = class(TForm) 
    procedure FormPaint(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    Manager: TManager; 
    end; 

var 
    FormSplash: TFormSplash; 

implementation 


{$R *.dfm} 

procedure TFormSplash.FormCreate(Sender: TObject); 
begin 
    Manager := TManager.Create; 
end; 

procedure TFormSplash.FormDestroy(Sender: TObject); 
begin 
    Manager.Free; 
end; 

procedure TFormSplash.FormPaint(Sender: TObject); 
begin 
    if Visible then 
    begin 
    Manager.GetData(Self); 
    Hide; 
    Manager.DoDataStuff; 
    Close; 
    end; 
end; 

end. 

DaaObject是:

unit DataObjectU; 

interface 

uses classes; 

type TDataObject = class(TObject) 
    Data: string; 
end; 

implementation 

end. 

Manager是:

interface 

uses DataObjectU; 

type 
    TManager = Class(Tobject) 
    MyData: TDataObject; 
    constructor Create; virtual; 
    destructor Destroy; override; 
    procedure GetData(OwnerForm: TForm); 
    procedure DoDataStuff; 
    end; 

implementation 

uses DataFormU; 

{ TManager } 

constructor TManager.Create; 
begin 
    inherited Create; 
    MyData := TDataObject.Create; 
end; 


destructor TManager.Destroy; 
begin 
    MyData.Free; 
    inherited; 
end; 

procedure TManager.DoDataStuff; 
begin 
    // do stuff with data here 
end; 

procedure TManager.GetData(OwnerForm: TForm); 
var 
    MyDataForm: TDataForm; 
begin 
    MyDataForm := TDataForm.Create(OwnerForm); 
    try 
    if MyDataForm.ShowModal = mrOK then 
    begin 
    MyData.Data := MyDataForm.Data; 
    end; 
    finally 
    MyDataForm.Free; 
    end; 
end; 

end. 

數據形:

type 
    TDataForm = class(TForm) 
    btnOK: TButton; 
    procedure btnOKClick(Sender: TObject); 
    private 
    function GetData: String; 
    { Private declarations } 
    public 
    { Public declarations } 
    MyData: TDataObject; 
    property Data: String read GetData; 
    end; 

var 
    DataForm: TDataForm; 

implementation 

{$R *.dfm} 

procedure TDataForm.btnOKClick(Sender: TObject); 
begin 
    MyData := TDataObject.Create; 
    ModalResult := mrOk; 
end; 

function TDataForm.GetData: String; 
begin 
    Result := MyData.Data; 
end; 

您需要填寫單位代碼的其餘部分並釋放一些東西,但本質上是這樣的:

啓動方案(創建飛濺)

飛濺創建管理器調用它從數據形獲取數據,然後把自己隱藏

呼叫管理器來管理數據

當經理完成它,然後關閉。

有沒有其他的方式來關閉它現在除了通過任務管理器!)