通过 TFireMonkeyContainer 在 VCL 应用程序中形成 FMX - 应用程序冻结

FMX form in VCL app via TFireMonkeyContainer - application freezing

我正在使用 TFireMonkeyContainer 控件在 VCL 应用程序中嵌入 Firemonkey 表单。最初,一切正常。但是,每当我执行触发 TChangeTabAction 的操作(在 TTabControl 中的选项卡之间来回滑动)时,整个应用程序都会冻结并停止响应。即使 Windows 也无法检测到它没有响应 - 标题栏甚至也被冻结,我必须从 IDE 或任务管理器中终止进程。当 运行 完全在 Firemonkey 应用程序中时,相同的表单可以完美工作。

重现问题并不多,根本没有代码,只是表单设计。

  1. TFireMonkeyContainer 控件安装到 IDE(或动态使用)
  2. 创建新的 VCL 表单应用程序
  3. 在 VCL 主窗体上只删除一个 TFireMonkeyContainer 控件
  4. 在同一应用程序中创建新的 FMX 表单
  5. 将 FMX 表单分配给容器
  6. 在 FMX 表单中,删除一个 TTabControl 并添加几个选项卡
  7. 在 FMX 表单中,放置一个新的 TActionList
  8. 将多个 TChangeTabAction 添加到操作列表中,每个选项卡一个
  9. 将每个选项卡分配给相应的操作之一
  10. 在 FMX 表单中,放置一个新按钮
  11. TChangeTabAction 之一分配给按钮
  12. 运行 申请
  13. 请注意当您将鼠标移到按钮上时,UI 响应良好
  14. 请注意如何在选项卡之间手动切换而不会出现问题
  15. 单击 FMX 表单上的按钮
  16. 请注意 UI 如何不再响应并且应用程序会占用以继续

如何使 FMX TChangeTabAction 在将我的表单嵌入此容器时按预期工作?

编辑

由于上面的解释可能对一些人来说还不够,下面是两种形式的形式设计:

VCL 表格:

object frmVcl: TfrmVcl
  Left = 0
  Top = 0
  Caption = 'frmVcl'
  ClientHeight = 405
  ClientWidth = 666
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object FireMonkeyContainer1: TFireMonkeyContainer
    Left = 40
    Top = 40
    Width = 577
    Height = 305
    FireMonkeyForm = frmFiremonkey.Owner
  end
end

FMX 表格:

object frmFiremonkey: TfrmFiremonkey
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 480
  ClientWidth = 640
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  DesignerMasterStyle = 0
  object TabControl1: TTabControl
    Position.X = 24.000000000000000000
    Position.Y = 72.000000000000000000
    Size.Width = 585.000000000000000000
    Size.Height = 289.000000000000000000
    Size.PlatformDefault = False
    TabIndex = 0
    TabOrder = 0
    TabPosition = PlatformDefault
    object TabItem1: TTabItem
      CustomIcon = <
        item
        end>
      IsSelected = True
      Size.Width = 67.000000000000000000
      Size.Height = 26.000000000000000000
      Size.PlatformDefault = False
      StyleLookup = ''
      TabOrder = 0
      Text = 'TabItem1'
    end
    object TabItem2: TTabItem
      CustomIcon = <
        item
        end>
      IsSelected = False
      Size.Width = 68.000000000000000000
      Size.Height = 26.000000000000000000
      Size.PlatformDefault = False
      StyleLookup = ''
      TabOrder = 0
      Text = 'TabItem2'
    end
    object TabItem3: TTabItem
      CustomIcon = <
        item
        end>
      IsSelected = False
      Size.Width = 68.000000000000000000
      Size.Height = 26.000000000000000000
      Size.PlatformDefault = False
      StyleLookup = ''
      TabOrder = 0
      Text = 'TabItem3'
    end
  end
  object Button1: TButton
    Position.X = 32.000000000000000000
    Position.Y = 16.000000000000000000
    Size.Width = 105.000000000000000000
    Size.Height = 41.000000000000000000
    Size.PlatformDefault = False
    TabOrder = 2
    Text = 'Button1'
    OnClick = Button1Click
  end
  object ActionList1: TActionList
    Left = 512
    Top = 24
    object ChangeTabAction1: TChangeTabAction
      Category = 'Tab'
      Tab = TabItem1
    end
    object ChangeTabAction2: TChangeTabAction
      Category = 'Tab'
      Tab = TabItem2
    end
    object ChangeTabAction3: TChangeTabAction
      Category = 'Tab'
      Tab = TabItem3
    end
  end
end

TFireMonkeyContainer 阻止 FMX 应用程序消息循环 运行,推迟到 VCL 应用程序消息循环。替换 Windows 应用服务对方法 HandleMessage(并返回 false)或 WaitMessage 没有做任何事情,错误地假设因为 FMX 消息循环从不 运行,它们永远不会打电话。

但是FMX的Application.ProcessMessages方法当然可以手动调用,调用到Windows应用服务方法,运行一个while循环,瞬间结束。选项卡 t运行sition 代码调用 ProcessMessages 直到 t运行sition 完成,并且由于 HandleMessage 什么也没做,也没有处理任何消息,因此 t运行 sition 从未继续,导致无限循环等待直到它完成。

latest commit in Github 修复了这个问题,并修复了一些相关的应用服务方法,使其表现得更像默认的 FMX 应用服务。