通过TFireMonkeyContainer在VCL应用程序中的FMX表单-应用程序冻结
我正在使用 TFireMonkeyContainer
控件将Firemonkey表单嵌入VCL应用程序中.最初,一切正常.但是,每当我执行触发TChangeTabAction
的操作(在TTabControl
中的选项卡之间来回滑动)时,整个应用程序就会冻结并停止响应.甚至Windows也无法检测到它没有响应-标题栏也被冻结了,我必须从IDE或任务管理器中终止该过程.当完全在Firemonkey应用程序中运行时,相同的形式也可以很好地工作.
I'm using the TFireMonkeyContainer
control to embed a Firemonkey form inside a VCL application. Initially, everything works fine. However, whenever I do something which triggers a TChangeTabAction
(to slide back and forth between tabs in a TTabControl
), the entire application freezes up and stops responding. Even Windows is unable to detect that it's not responding - the title bar is even frozen as well, and I have to either terminate the process from the IDE or from the Task Manager. The same form works perfectly when run purely in a Firemonkey application.
重现该问题的内容不多,根本没有代码,仅是表单设计.
There's not much to it to reproduce the issue, no code at all, just form design.
- 将
TFireMonkeyContainer
控件安装到IDE中(或动态使用) - 创建新的VCL表单应用程序
- 仅在VCL主窗体上拖放一个
TFireMonkeyContainer
控件 - 在同一应用程序中创建新的FMX表单
- 将FMX表单分配给容器
- 在FMX表单中,放置
TTabControl
并添加一些标签页 - 在FMX表单中,放置一个新的
TActionList
- 在操作列表中添加多个
TChangeTabAction
,每个选项卡一个 - 将每个标签分配给相应的操作之一
- 在FMX表单中,放置一个新按钮
- 将
TChangeTabAction
之一分配给按钮 - 运行应用程序
- 请注意,当您将鼠标移到按钮上时,UI会很好地响应
- 注意如何在没有问题的情况下手动切换选项卡
- 单击FMX表单上的按钮
- 请注意,UI如何不再响应,应用程序将继续运行
- Install
TFireMonkeyContainer
control into IDE (or use dynamically) - Create new VCL Forms Application
- Drop only one
TFireMonkeyContainer
control on VCL main form - Create new FMX Form within same application
- Assign the FMX form to the Container
- In the FMX form, drop a
TTabControl
and add a few tabs - In the FMX form, drop a new
TActionList
- Add multiple
TChangeTabAction
s into the Action List, one for each tab - Assign each tab to one of the corresponding actions
- In the FMX form, drop a new button
- Assign one of the
TChangeTabAction
s to the Button - Run the application
- Note how when you move the mouse over the button, the UI responds well
- Note how you can switch between tabs manually with no problem
- Click the button on the FMX form
- Note how the UI no longer responds and the application seizes to continue
将表单嵌入到此容器中时,如何使FMX TChangeTabAction
正常工作?
How can I make the FMX TChangeTabAction
work as expected while embedding my form in this container?
编辑
仅因为上面的解释可能还不够,下面是这两种形式的表单设计:
Just because the above explanation may not be enough for some, here's the form design of both forms:
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消息循环从未运行,因此它们将永远不会被调用.
TFireMonkeyContainer
prevents the FMX application message loop from running, deferring to the VCL application message loop. The replacement Windows app service did nothing for the methods HandleMessage
(and returned false) or WaitMessage
, incorrectly assuming that since the FMX message loop never ran, they would never be called.
但是,当然可以手动调用FMX的Application.ProcessMessages
方法,并且该方法调用Windows应用程序服务方法,并运行while循环,该循环立即结束.选项卡转换代码将调用ProcessMessages
直到转换完成,并且由于HandleMessage
不执行任何操作但也未处理任何消息,因此转换从未继续进行,从而导致无限循环,直到它完成为止.
However, FMX's Application.ProcessMessages
method can be manually called, of course, and that calls into the Windows app service methods, running a while loop, which ended instantly. The tab transition code calls ProcessMessages
until the transition is complete, and since HandleMessage
did nothing but also processed no messages, the transition never continued, causing an infinite loop while it waited until it was done.
Github中的最新提交可以解决此问题,并修复了一些相关的应用程序服务行为类似于默认的FMX应用程序服务.
The latest commit in Github fixes this, as well as fixes a couple of related app service methods to behave more like the default FMX application service.