0

このアプリケーションは、最初は Windows 環境を対象としています。

以下のリンクの最初のコードのみを使用しましたが、TabControls/TabItems (FMX) を受け入れるようにコードを置き換え、下のリンクの PageControls/TabSheet (VCL) を使用しないようにする必要がありました。TabItem 内のコンテンツを再構築する機能を備えた Frame を作成する意図があります (それ自体を解放し、プロシージャ内でオブジェクトの構築/作成アプローチを使用します)。

embarcadero.com (TabSheets をフレームに置き換える - Dan Miser 著)

Delphi Seattle 10 からフレームを使用しているときに tiframe1 を使用するたびに、フレームを動的に使用できることに慣れてきました。これはアプローチの1つです。(frame.Free; で問題が発生します) このアプローチにより、アプリケーションは、ウィンドウの移動、終了/閉じる、またはウィンドウ レイヤー (メニュー バーを含む) に関係するものに応答しなくなります。

これは、TFrame がもともと VCL 用に作成されたという事実と関係がありますか?

Project1.dpr

program Project1;

uses
  System.StartUpCopy,
  FMX.Forms,
  Unit1 in 'Unit1.pas' {Form1},
  frame1 in 'frame1.pas' {tiframe1: TFrame};

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

Unit1.pas

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.TreeView,
  FMX.Layouts, FMX.Controls.Presentation, FMX.StdCtrls, FMX.TabControl, FMX.Edit;

type
  TForm1 = class(TForm)
    TabControl1: TTabControl;
    TabItem1: TTabItem;
    TabItem2: TTabItem;
    procedure FormCreate(Sender: TObject);
    procedure RefreshFrame();

  private
    { Private declarations }
    procedure CreateFrame(ATabitem: TTabItem);

    function GetFrame(ATabitem: TTabItem): TFrame;
  public
    { Public declarations }

  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

uses frame1;

type
  TFrameClass = class of TFrame;

procedure TForm1.FormCreate(Sender: TObject);
begin
  TabItem1.Tag := Integer(Ttiframe1);
  CreateFrame(TabItem1);
end;

function TForm1.GetFrame(ATabitem: TTabItem): TFrame;
begin
  if not Assigned(ATabitem) then
    ATabitem := TabControl1.ActiveTab;
  Result := nil;
  if Assigned(ATabitem) and (ATabitem.ControlsCount > 0) and (ATabitem.Controls[0] is TFrame) then
    Result := TFrame(ATabitem.Controls[0]);
end;

procedure TForm1.CreateFrame(ATabitem: TTabItem);
var
  frame: TFrame;
begin
  if GetFrame(ATabitem) = nil then
    if ATabitem.Tag <> 0 then
    begin
      frame := TFrameClass(ATabitem.Tag).Create(Self);
      frame.Parent := ATabitem;
    end;
end;

procedure TForm1.RefreshFrame();
var
  frame: TFrame;
begin
  if Assigned(FindComponent('tiframe1')) then // 
  begin
    frame := FindComponent('tiframe1') as TFrame;
    frame.Free;  //This is the cause of all the problems
    frame := Ttiframe1.Create(Self);
    frame.Parent := TabControl1;
  end;
end;

end.

また、フレームを作成し、Construct/Create を使用して下部 (「end.」の前) で RegisterClass も作成することを忘れないでください。

unit frame1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.TabControl, FMX.Forms, FMX.Layouts, FMX.Dialogs,
  FMX.StdCtrls, FMX.Graphics, FMX.Controls.Presentation, FMX.Memo, FMX.Edit;

type
  Ttiframe1 = class(TFrame)
    Button1: TButton;

    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }

  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
  end;

implementation

{$R *.fmx}

uses Unit1;

procedure Ttiframe1.Button1Click(Sender: TObject);
begin
  Form1.RefreshFrame();
end;

constructor Ttiframe1.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

initialization
  RegisterClass(Ttiframe1);

end.

現在、フレーム内のコンストラクターと同様の方法で、TLabel などの要素に影響を与えることができるように、TabItems を再レンダリングして新しいものまたは更新されたものを表示できるかどうかを確認しています (Refresh または Application.ProcessMessages アプローチのようなもの)。 .Text またはおそらく TEdit.Text です。コンストラクト内で、データベースから動的にデータをフェッチします。

置換の理由は、Frame 内、TabItem 内、またはその他の方法で (TTreeView) を使用しているときに、RefreshFrame を使用する必要がある場合に MainForm ウィンドウから注意/フォーカスをそらす既知の原因がなくても、同様の発生が発生するためです。

4

1 に答える 1

1

これは問題を示すための単なるコードであることを理解しています。そのため、コードの他の奇妙な部分には触れませんが、説明した問題に焦点を当てます。

問題はOnClick、ボタンのハンドラーがフレームを解放し、ボタンとハンドラーが存在しないボタンに戻ることです。

これを回避するには、次のいずれかを実行できます

  • OnClickハンドラーがフレーム (およびボタン) を解放しないように再設計します。
  • ボタンがフォームに投稿し、フォームが受信したときに呼び出す独自の定義の Windows メッセージ (プラットフォームは Windows であるため) を使用します。RefreshFrame
  • TTimerボタンが有効にし、タイマーも無効になっているイベントRefreshFrameから呼び出す1ミリ秒を使用しますOnTimer

OnClickフレームとボタンが破棄される前に、ボタンハンドラーが完了することができるという考えです。

于 2016-01-21T22:28:09.563 に答える