Lazarus多窗体

一、双窗体

我们实现一个弹窗功能,Form1(主窗体)+ Form2(弹窗)

1. 操作步骤

  1. 新建项目,Form1 拖入 Button1,修改 Caption = Open Form2,生成 OnClick 事件(可以直接在设计窗体双击按钮也可以快速创建点击事件);
  2. 顶部菜单 File → New Form,创建 Form2;
  3. Form2 放 Button1,Caption = Close,生成 OnClick
  4. 切换窗体快捷键:Shift+F12 窗体列表 / F12 切换设计/代码;
  5. Unit1 引用 Unit2:在 interface uses 添加 Unit2

Unit1(主窗体)

主要有两处要注意,Unit2; //引入Unit2

还有一个地方就是在点击函数里面,已模态框的方式打开窗口2,Form2.ShowModal; // 模态弹出Form2

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Unit2; //引入Unit2 

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.ShowModal; // 模态弹出Form2
end;

end.

Unit2(子窗体)

在文件中添加第二个窗体

添加完后,编辑框中会多出一个选项卡

一个是主窗口的,一个是窗口2的的后台代码

如果你想设置窗口2,只需要选择Unit2,然后按F12就可以。就可以打开窗体2的设计窗口

然后像前面的课程一样,添加一个按钮,修改名字为Close,然后添加关闭功能。前面的课程学过,读者可以自己完成。

unit Unit2;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm2 }

  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private

  public

  end;

var
  Form2: TForm2;

implementation

{$R *.lfm}

procedure TForm2.Button1Click(Sender: TObject);
begin
  Close; // 关闭当前Form2
end;

end.

二、Show 与 ShowModal 核心区别(对比示例)

界面改造

Form1 添加两个按钮:

  • btnShow:Caption = Show
  • btnShowModal:Caption = ShowModal
// 非模态 Show
procedure TForm1.btnShowClick(Sender: TObject);
begin
  Form2.Show;
  ShowMessage('Form2 已打开,主窗体可操作');
end;

// 模态 ShowModal
procedure TForm1.btnShowModalClick(Sender: TObject);
begin
  Form2.ShowModal;
  ShowMessage('必须关闭Form2才会弹出此提示');
end;Code language: JavaScript (javascript)

差异说明

  1. Show(非模态)
  • 打开子窗体后代码继续往下执行;
  • 主窗体可拖动、点击其他按钮;
  • 等价 Form2.Visible := True;,且自动置顶。
  1. ShowModal(模态弹窗)
  • 代码暂停,直到子窗体关闭才继续执行;
  • 主窗体锁定,无法操作;
  • 是函数,可返回 ModalResult 判断关闭方式。

一句话概括就是,模态框模式打开的话,子窗口必须关闭了才可以操作主窗口的任何东西,而非模态框打开子窗口后,还可以操作主窗口。

三、窗体互相调用:解决循环引用报错

需求:Form1 打开 Form2,Form2 打开 Form1
直接在 interface uses 互相引用会报循环单元错误,解决方案:把引用写到 implementation 段

Unit1

unit Unit1;

interface
uses Forms,StdCtrls;

type
  TForm1=class(TForm)
    Button1:TButton;
    procedure Button1Click(Sender:TObject);
  end;
var Form1:TForm1;

implementation
uses Unit2; // 引用放此处
{$R *.lfm}

procedure TForm1.Button1Click(Sender:TObject);
begin
  Form2.Show;
end;
end.

Unit2

unit Unit2;

interface
uses Forms,StdCtrls;

type
  TForm2=class(TForm)
    Button1:TButton;
    procedure Button1Click(Sender:TObject);
  end;
var Form2:TForm2;

implementation
uses Unit1; // 互相引用放实现区
{$R *.lfm}

procedure TForm2.Button1Click(Sender:TObject);
begin
  Form1.Show;
end;
end.

四、窗体之间传值(公用成员变量示例)

功能:主窗体点击打开子窗体时计数,子窗体可查看打开次数

Unit2 定义公共整型变量

type
  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
  public
    Count: Integer; // 公共变量,Unit1可访问
  end;

Unit1 点击按钮自增计数

procedure TForm1.Button1Click(Sender: TObject);
begin
  Inc(Form2.Count); // 计数+1
  Form2.ShowModal;
end;Code language: JavaScript (javascript)

Unit2 弹窗显示次数

procedure TForm2.Button1Click(Sender: TObject);
begin
  ShowMessage('此窗体已打开 '+IntToStr(Count)+' 次');
end;Code language: JavaScript (javascript)

规范建议:尽量少用全局/公共变量,推荐使用属性 Property 传参。

五、动态创建窗体

不依赖项目自动生成全局Form变量

方式1:动态创建设计好的Form2

  1. 打开 Project.lpr,删除 Application.CreateForm(TForm2, Form2);
  2. Form1按钮代码:
procedure TForm1.Button1Click(Sender: TObject);
var
  frm2: TForm2;
begin
  frm2 := TForm2.Create(nil); // 手动创建
  frm2.ShowModal;
  FreeAndNil(frm2); // 释放内存,防止泄漏
end;Code language: JavaScript (javascript)

方式2:完全代码生成窗体(无需提前设计)

点击按钮生成全新窗体+内置关闭按钮

unit Unit1;

interface

uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure DynamicBtnClick(Sender: TObject); // 自定义按钮点击事件
  public
  end;

var Form1: TForm1;

implementation
{$R *.lfm}

procedure TForm1.DynamicBtnClick(Sender: TObject);
begin
  ShowMessage('即将关闭动态窗体');
  TForm(TButton(Sender).Parent).Close;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  MyForm: TForm;
  MyBtn: TButton;
begin
  MyForm := TForm.Create(nil);
  MyForm.SetBounds(100,100,220,150);
  MyForm.Caption := '动态生成窗体';

  // 创建按钮,所有者为MyForm,释放时自动销毁按钮
  MyBtn := TButton.Create(MyForm);
  MyBtn.SetBounds(10,10,200,30);
  MyBtn.Caption := '关闭窗体';
  MyBtn.Parent := MyForm;
  MyBtn.OnClick := @DynamicBtnClick;

  MyForm.ShowModal;
  FreeAndNil(MyForm);
end;
end.

出现Choose Debug Information format

设置一下调试格式就可以。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注