9

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

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

我现在正在尝试使用 TFrame:我为每个状态创建一个框架,然后在我的表单上创建一个每个框架的实例,然后我只显示我想要使用 Visible 的那个 - 同时有一些控件最重要的是,在任何框架之外,因为它们都共享它们。

这是做我想做的事情的正确方法,还是我在此过程中错过了什么?我以为我只能创建一个 tframe 实例,然后选择要在其中显示的实例,但看起来并非如此。

谢谢

4

4 回答 4

17

看起来框架是这种情况下的绝佳选择。我想补充一点,您可以使用 Base Frame 和 Visual Inheritance 来创建通用界面。

第二部分:你设计一个像窗体一样的框架,但你像一个控件一样使用它,很少有限制。请注意,您可以轻松地使用 Create/Free 而不是 Show/Hide。什么更好取决于它们的资源密集程度。

于 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;帧[索引:整数];数数;

  • 应该是不言自明的。

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

但它确实严重依赖于从一个共同的祖先那里继承你的框架。这些框架(在我的案例中)都有程序:BeforeShow;免费前;隐藏之前;可见之前。这些在 push、pop 和 top 期间由 FrameStack 对象调用;

从您的主窗体中,您只需要访问 FrameStack.Stacktop.whatever。我将我的 Stack 设为全局 :) 所以从其他对话框/窗口等访问它真的很容易。

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

创建 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 回答