2009-06-07 16 views
9

私のアプリケーションには、ユーザーが何をしているかに応じて異なる「状態」を持ついくつかのフォームがあります。例えば、彼のファイルをリストするとき、フォームはそのファイルに関するいくつかのデータをグリッドに表示するが、何らかのボタンをクリックすると、グリッドはそれに関連するグラフに置き換えられる。簡単に言えば、フォーム内のコントロールは、ユーザーが何をしたいかによって異なります。複数ページのフォームには、デルファイのTフレームを使用する必要がありますか?

もちろん、それを行う明白な方法は、必要に応じてコントロールを表示/隠していましたが、小さな数字の魅力のように機能しますが、状態ごとに10/15 +コントロールに達すると使用できません。

私は今、TFramesを使って実験しています:すべての状態のフレームを作成し、それぞれのフォーム上の各フレームのインスタンスを作成し、Visibleを使用して表示します - whileそれらのすべてがそれらを共有しているので、フレームの上にいくつかのコントロールがあります。

これは正しい方法ですか、途中で何かを逃しましたか?私は1つのtframeインスタンスしか作成できないと思って、それにどのインスタンスを表示するかを選択しましたが、それはそのようには見えません。

ありがとうございました

答えて

17

このシナリオでは、フレームのように見えます。ベースフレームとビジュアル継承を使用して共通のインターフェイスを作成できると付け加えたいと思います。

2番目の部分:フォームのようにフレームをデザインしますが、コントロールのようにそれを使いますが、ほとんど制限はありません。 Show/Hideの代わりにCreate/Freeを簡単に使用することもできます。彼らがどれだけリソースが重いかによって、より良いものが得られます。

10

メモリをほとんど使用しないフレームを扱うより良い方法があります。フレームを動的に作成することは、非常に洗練されたソリューションになります。私は過去に何をしたのですか?フォームで

は、財産やフォーム上での配置を扱うセッターを追加します。

TMyForm = class(TForm) 
private 
    FCurrentFrame : TFrame; 
    procedure SetCurrentFrame(Value : TFrame); 
public 
    property CurrentFrame : TFrame read FCurrentFrame write SetCurrentFrame; 
end; 

procedure TMyForm.SetCurrentFrame(Value : TFrame) 
begin 
    if Value <> FCurrentFrame then 
    begin 
    if assigned(FCurrentFrame) then 
     FreeAndNil(FCurrentFrame); 
    FCurrentFrame := Value; 
    if assigned(FCurrentFrame) then 
    begin 
     FCurrentFrame.Parent := Self; // Or, say a TPanel or other container! 
     FCurrentFrame.Align := alClient; 
    end; 
    end; 
end; 

次に、それを使用するために、あなたは、単にフレームの作成したインスタンスにプロパティを設定し、

MyFrame1.CurrentFrame := TSomeFrame.Create(nil); 

あなたは、フレームを取り除きたい場合は、単純に、currentFrameプロパティにnilを割り当てる:OnCreateのイベントで例えば

MYFrame1.CurrentFrame := nil; 

非常にうまく動作します。

+0

+1ですが、このコードではメモリがリークしていることに注意してください。以前にMYFrame1.CurrentFrameが明示的にnilに設定されていない場合、またはMYFrame1が破棄された場合は解放されません。 MyFrame1を所有者としてコンストラクタに渡し、VCLで自動ライフタイム管理を利用する方がよいでしょう。 – mghie

+0

@mghie:IIRCコントロールの親もまた生涯管理を引き継ぐので、Timのコードではメモリリークが発生しません。 –

+0

実際には、TSomeFrame.Create(nil)を呼び出すのではなく、TSomeFrame.Create(Self)を呼び出してフォームを所有者のフォームにし、フォームが破棄されたときにそのフォームを解放すると、私は思っています。また、OnDestroyイベントでCurrentFrameをnilに設定することもできます。あるフレームから別のフレームに変更しても、セッターは別のフレームに設定する前にFCurrentFrameを解放するため、メモリーリークは発生しません。 –

2

私はあなたのための単語を持っています:TFrameStack。単にその名前が示唆しているもの。

いくつかの方法があります:PushFrame(AFrame)、PopFrame、PopToTop(AFrame)、PopToTop(Index)、 といくつかのプロパティ:StackTop;フレーム[インデックス:整数];カウント;

  • 自己説明する必要があります。

Frame at StackTopは目に見えるものです。 Back/Previousのような操作をしているときに、現在のフレームよりも前にあったフレームを知る必要はありません:) フレームを作成するときには、FrameStack.Push(TAFrame。Create)などを使用してBeforeShow procを呼び出して可視にし、スタック内のインデックスを返します:)

しかし、共通の祖先からフレームを継承することに大きく依存します。これらのフレームはすべて(私のケースでは)手続きを持っています:BeforeShow; BeforeFree; BeforeHide; BeforeVisible。 これらは、push、pop、およびtopの間にFrameStackオブジェクトによって呼び出されます。

メインフォームから、FrameStack.Stacktop.whateverにアクセスするだけです。私はスタックをグローバルにしました:)追加のダイアログやウィンドウなどからアクセスするのはとても簡単です。

Freeメソッドオーバーライドを作成して、所有者がいない場合はすべてを解放することを忘れないでください。アプリがシャットダウンされたときにスタックすることができます。明示的にトラッキングする必要がない別の利点があります。

TFrameStack Listオブジェクトの作成にはわずかな作業しかかかりませんでした。私のアプリでは、夢のように動作します。

チンボ

0

私もいくつか追加して@Timサリバンで説明したアプローチを使用します。すべてのフレームで、フレーム初期化の手順を定義します。つまり、コンポーネントのデフォルトプロパティを設定します。

TAnyFrame = class(TFrame) 
    public 
    function initFrame() : boolean; // returns FALSE if somesthing goes wrong 
    ... 
end; 

フレームが作成された後、私はこの手順を呼び出します。

aFrame := TAnyFrame.Create(nil); 
if not aFrame.initFrame() then 
    FreeAndNil(aFrame) 
else 
    ... // Associate frame with form and do somthing usefull 

また、表示フレームを変更すると、有効なデータが含まれている可能性があるため、以前のフレームを破棄する必要はありません。最初のフレーム/ページに何らかのデータを入力してから次のページに移動し、最初のページのデータを再度変更すると決めたとします。前のフレームを破棄した場合、そのフレームに含まれていたデータが失われ、復元する必要があります。解決策は、作成されたすべてのフレームを保持し、必要なときにのみ新しいフレームを作成することです。

page_A : TFrameA; 
page_B : TFrameB; 
page_C : TFrameC; 
current_page : TFrame; 

// User click button and select a frame/page A 
if not assigned(page_A) then begin 
    // create and initialize frame 
    page_A := TFrameA.Create(nil); 
    if not page_A.initFrame() then begin 
    FreeAndNil(page_A); 
    // show error message 
    ... 
    exit; 
    end; 
    // associate frame with form 
    ... 
end; 
// hide previous frame 
if assigned(current_page) then 
    current_page.hide(); 
// show new page on the form 
current_page := page_A; 
current_page.Show(); 
関連する問題