9

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

もちろん、それを行う明白な方法は、必要に応じてコントロールを表示/非表示にすることでした。少数の場合は魅力のように機能しますが、状態ごとに 10/15+ コントロール (または実際には 3 つ以上の状態) に達すると、使用できなくなります。

私は現在 TFrames を試しています: すべての状態のフレームを作成し、フォーム上に各フレームのインスタンスを作成し、Visible を使用して必要なもののみを表示します - いくつかのコントロールをオンにしながらそれらはすべてそれらを共有するため、どのフレームからでもその上に。

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

ありがとう

4

4 に答える 4

17

フレームは、このシナリオに最適な選択肢のようです。Base Frame と Visual Inheritance を使用して、共通のインターフェイスを作成できることを付け加えたいと思います。

そして 2 番目の部分: フレームをフォームのように設計しますが、コントロールのように使用します。制限はほとんどありません。Show/Hide の代わりに Create/Free を簡単に使用できることに注意してください。どちらが優れているかは、リソースがどれだけ重いかによって異なります。

于 2009-06-07T17:24:37.513 に答える
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;

次に、それを使用するには、たとえば OnCreate イベントで、プロパティをフレームの作成されたインスタンスに設定するだけです。

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

フレームを取り除きたい場合はnil、CurrentFrame プロパティに代入するだけです。

MYFrame1.CurrentFrame := nil;

それは非常にうまく機能します。

于 2009-06-08T01:13:20.903 に答える
3

TFrameStack という言葉があります。単に名前が示唆するもの。

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

  • 自明であるべきです。

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

ただし、共通の祖先からフレームを継承することに大きく依存しています。これらのすべてのフレーム (私の場合) には手順があります。ビフォアフリー; 前非表示; ビフォービジブル。これらは、プッシュ、ポップ、およびトップの間に FrameStack オブジェクトによって呼び出されます。

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

また、アプリのシャットダウン時にスタック内のすべてのフレーム (所有者が nil の場合) を解放するための Free メソッド オーバーライドを作成することも忘れないでください。明示的に追跡する必要がないもう 1 つの利点:)

TFrameStack List オブジェクトを作成するのに必要な作業はほんの少しでした。そして、私のアプリでは夢のように働きます。

ティンボ

于 2009-06-09T20:44:08.830 に答える
0

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

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();
于 2013-04-25T17:35:41.317 に答える