Showing posts with label fmx. Show all posts
Showing posts with label fmx. Show all posts

Monday, 12 May 2014

TFireMonkeyContainer bugfix for instances created at runtime

TFireMonkeyContainer is a small open-source VCL component that can host a FMX form, allowing you to embed FireMonkey forms inside your VCL application.  It works with XE3 and above.
A 3D FireMonkey form embedded in a VCL application,
using TFireMonkeyContainer

This post is to note a bugfix that handles the case where instances of TFireMonkeyContainer are freed in a different order to the order in which they were created.  This is most likely to occur if you create instances dynamically at runtime, such as in a tabbed multidocument application (like a web browser): creating one on a new tab, but freeing them in different order, such as if a user closes a different tab.

If running in debug, you would get an assert in this situation.  If running in release, you would notice focus issues, where the host form may not have drawn its title bar as though it was the active form when the FMX form inside it was focused.  If you only ever had one embedded FMX form per VCL form or if you never created an instance at runtime, ie only used it by placing a TFireMonkeyContainer on a form at designtime, you wouldn't run into this bug, although this update does clean up the code and you should use this latest version anyway.

The bug was due to the control needing to subclass the VCL form on which it sits.  In some slightly silly code the implications of which I overlooked, this was done once per TFireMonkeyContainer instance, but should have been done only once for a given VCL form no matter how many embedded FMX forms were on that host VCL form, and removed only when the last TFireMonkeyContainer instance was freed.

If you haven't used TFireMonkeyContainer before, and you want to make use of FMX in your VCL app, try it out!  You can find the project on Google Code, and check out or update the source from SVN.  Read more posts about it on the Code & Components page.

Sunday, 21 July 2013

TFireMonkeyContainer update: bugs fixed, features added

The example application showing a 3D FireMonkey form.
On the other tab is a standard 2D form.
On Wednesday I announced TFireMonkeyContainer, a VCL control that can host a FireMonkey form, allowing you to mix FireMonkey elements into your VCL app. It was (and is) a new project, and the announcement page listed several known bugs and possible future design changes.

Bugs: gone! Design changes: made! The current state is not quite perfect but is bug-free enough I feel happy about you using it in real applications, or at least trying it out. (With the caveat that I'm the only one who has tested it so far, and my entire QA department is me :) If you try it, please let me know how it goes.

 Bugs fixed

  • Focus now correctly follows the host VCL and hosted FMX forms
  • Window activation now correctly follows the host VCL and hosted FMX forms, when switching by clicking on the host VCL form, the hosted FMX form, via alt-tab, via the taskbar, and when there are several VCL forms and several hosted FMX forms in the one application.
  • The title bar of host VCL forms correctly changes when the form is active and inactive.
  • An exception is now thrown when two containers both try to host the same form.

Design changes

    This FireMonkey form embedded in the VCL form can't be
    edited in the VCL designer - it's a static preview. Switch
    to the FMX form tab to edit it.
  • Design-time (in the IDE): When a FireMonkey form is hosted in a VCL form in designtime, it shows an uneditable view of the hosted form. (This used to be an editable FireMonkey form, ie you could invoke the FireMonkey designer. This only partially worked and caused a lot of problems.) Switch tabs to the FireMonkey form's IDE design tab to edit the FireMonkey form. Changes will be reflected immediately when you switch back to the VCL form's design tab.
  • There are two new events you can use to control hosting the FireMonkey form. This means there are three ways to embed a FireMonkey form:
    1. Set the FireMonkeyForm property at design-time. (Not recommended, see 'Known problems' below.)
    2. Set the FireMonkeyForm property at runtime.
    3. Use the OnCreateFMXForm and OnDestroyFMXForm events.
      • OnCreateFMXForm fires when the component is first created. It has a var Form parameter which you can use to set the hosted FireMonkey form. If a form was specified at designtime, Form refers to it. If you change it, OnDestroyFMXForm will be called for the old value.
      • OnDestroyFMXForm fires when the component is destroyed. Much like a TForm's OnClose event, you can choose an action to apply to the hosted FMX form, eg to free it. The default is to do nothing, since it was probably created with an owner. The Destroy event also occurs when you change the Form parameter in the Create event (eg, when there was a FMX form set at design-time, but in the Create event you change it to another form.)

Known problems

  • When you set the FireMonkeyForm property at designtime, you can only set it to a FMX form that is open in a tab in the IDE - otherwise the IDE doesn't see it and won't show it in the dropdown in the Object Inspector. When the IDE tab is closed, the reference is invalid - and this means the FireMonkeyForm property is cleared. This might be due to problems mixing VCL and FMX forms in the one app, or (more likely) it might be due to a mistake I've made in how to correctly reference another form in a component. Suggested workaround: set the property at runtime, or use the OnCreateFMXForm and OnDestroyFMXForm events instead.

Notes, and getting the code

The component subclasses both the VCL form and the FMX form in order to catch the WM_NCACTIVATE (VCL form) and WM_ACTIVATE and WM_MOUSEACTIVATE (FMX form) messages. I'm not an expert in window activation and there may be bugs (or I might have just plain written bad code) in the  handlers. I'm also not certain I have hit on completely the right design for the events. I'd quite appreciate feedback if you use the component and feel that the events that occur are a bad design or force you to write ugly code. The same goes for any aspects of the component, really.

You can download the latest version from the Google code homepage and Subversion source checkout.

Wednesday, 17 July 2013

TFireMonkeyContainer - a VCL control for mixing VCL and FMX

I've created a small MPL-licensed component called TFireMonkeyContainer.  It's a VCL control that can host a FireMonkey form - 2D or 3D, it doesn't matter.

This will let you use FireMonkey's swishy graphics, animations, etc in an existing VCL application, either in a form among other controls, or if the host container is client-aligned then as though the whole window is a FireMonkey form (it just happens that the window chrome is a VCL form.)  As far as I know, while lots of people ask about mixing FireMonkey in a VCL app, there are no easy-to-use components which let you do so.  I hope, with some further development and bugfixes, this will do so.

Here's a screenshot from the example app:



How to use

  1. Drop a TFireMonkeyContainer control on a VCL form.
  2. Add a FMX form to your project if you haven't got one already (the IDE makes this difficult; you might need to create it in a separate FMX project and then add the unit to the VCL project.)
  3. At designtime, you can set the FireMonkeyForm property to an existing, auto-created FMX form. Note that for the IDE to see it, the form has to be open in a tab.
  4. At runtime, you can set the FireMonkeyForm property to a new instance of a FMX form.  Note that it doesn't take ownership of the form, so you will need to free the form yourself.  This is something that might change in future.

Known bugs

Yes, there definitely are known bugs.  This version is the result of only a couple of hours' work :)
  • The host form's title bar changes to paint as inactive when you click inside the hosted FMX form.  I plan to fix this by handling WM_NCACTIVATE and related messages; if you can think of a better way, by all means please let me know.
  • At designtime, you can't set the FireMonkeyForm property unless the FMX form is open in a tab in the IDE.
  • At designtime, the embedded FMX form draws a few pixels to the right and below where it should be.  You will see a border on the top and left sides of the controls.  I don't know why this is, and at runtime it is in the right place.
  • Designtime is fairly strange all around.  You can edit the hosted FMX control, such as by dragging a button around, but trying to do something like open a style editor causes lots of problems.  I'd recommend you regard it as view-only.

Possible future changes

This code is the result of one or two hours' work - it's early.  Please take that into account.  I thought it might be worth getting feedback on the component and see if it's useful before doing much more work.
That said, here are some possible future changes:
  • Make designtime view-only - don't let you edit the FMX form when it's displayed at designtime in the VCL editor, and just draw it there instead so you can see what it will look like.  This would probably make it a lot more stable.
  • Take ownership of the FMX form - set and forget.  (Currently, you have to delete the FMX form instance if you don't want a memory leak.)
  • Add two events for runtime form creation and deletion, so that when the component is created, you can handle an event and create a new FMX form, and when it is destroyed you can optionally do something with the FMX form before it is freed, or stop it being freed entirely.
I'm interested in other ideas too!

Credits

I saw some example code linked from this Delphi Sorcery post which inspired this component.  The code was DSharp.Windows.FMXAdapter.pas by Stefan Glienke.  My code is considerably expanded so I view it as a separate work - it solves some bugs (eg, removing flicker when the host VCL form is resized, hiding the phantom FMX application window, etc) and of course is a component.  Thanks go to those two pages for showing the basic technique!

Getting the code

You can grab the code via Subversion from Google Code here:
http://firemonkey-container.googlecode.com/svn/trunk/
or via the command line:
svn checkout http://firemonkey-container.googlecode.com/svn/trunk/ firemonkey-container-read-only

You will find two packages (one designtime, one runtime - both 32 and 64-bit) and one small example project.  It's only been tested with XE4 so far!

Have fun, and please contribute back any bugfixes you find.