我应该将delphi tframe用于多页表单吗?

时间:2009-06-07 17:17:48

标签: delphi tframe

我的应用程序中有一些表单具有不同的“状态”,具体取决于用户的操作;例如,当通过他的文件列出时,表单会在网格中显示有关该文件的一些数据,但如果他点击某个按钮,则网格会被与其相关的图表替换。简单地说,表单中的控件取决于用户想要做什么。

当然,显而易见的方法是根据需要显示/隐藏控件,就像小数字的魅力一样,但一旦你达到每个状态10/15 +控件(或者实际上超过3个状态)它就无法使用。

我正在尝试使用TFrames:我为每个状态创建一个框架,然后我在表单上创建每个框架的实例,然后我只使用Visible显示我想要的那个 - 同时拥有由于它们都共享它们,所以在它的顶部有一些控件。

这是做我想做的正确方法,还是我错过了一路?我以为我只能创建一个tframe实例,然后选择在其中显示哪一个,但它看起来不那样。

由于

4 个答案:

答案 0 :(得分:17)

看起来Frames是这种情况的绝佳选择。我想补充一点,您可以使用Base Frame和Visual Inheritance来创建一个通用接口。

第二部分:你设计一个像Form一样的Frame,但你像控件一样使用它,很少有限制。请注意,您可以轻松使用“创建/自由”而不是“显示/隐藏”。什么是更好的取决于他们是如何资源丰富。

答案 1 :(得分:10)

有一种更好的方法来处理不会占用几乎相同内存的帧。动态创建框架可以是一个非常优雅的解决方案。以下是我过去的做法。

在表单上,​​添加一个属性和一个setter,用于处理它在表单上的位置:

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;

效果非常好。

答案 2 :(得分:3)

我有话要说:TFrameStack。简单地说就是这个名字。

它有几个方法:PushFrame(AFrame),PopFrame,PopToTop(AFrame),PopToTop(索引), 和一些属性:StackTop;框架[索引:整数];计数;

  • 应该是自我解释的。

StackTop上的Frame是可见的。在执行像Back / Previous这样的操作时,您不需要知道当前帧之前的帧是什么:) 在创建框架时,您可以一次创建并推送它FrameStack.Push(TAFrame.Create)等,这会创建它调用BeforeShow proc并使其可见,并在堆栈中返回其索引:)

但它确实非常依赖于从共同的祖先继承您的帧。这些框架(在我的案例中)都有程序:BeforeShow; BeforeFree; BeforeHide; BeforeVisible。 这些是在push,pop和top期间由FrameStack对象调用的;

从主表单中,您只需要访问FrameStack.Stacktop.whatever。我使我的堆栈成为全局:)所以从其他对话框/窗口等访问它真的很容易。

另外,当应用程序关闭时,不要忘记创建一个Free方法覆盖以释放堆栈中的所有帧(如果所有者为nil) - 另一个优点是您不需要显式跟踪它们:)< / p>

创建TFrameStack List对象只需要少量工作。在我的应用程序工作就像一个梦想。

廷博

答案 3 :(得分: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();