Limitations in native iOS components for Firemonkey - ios

I am very attracted to the idea of using native components for iOS development, so I am testing the two options currently available: TMS iCL and D.P.F iOS Native Components. Unfortunately I found that both of them have limitations that make them cumbersome or impossible to use, though I still hope that I just overlooked something and therefore I ask here.
Limitation I found:
TMS iCL: it requires all native components in the whole application to be on the same form!
D.P.F.: there is no FMX wrapper that allows you to combine it with FMX forms/components.
Here is a simplified edition of what I need. I have 3 forms, a main form with the main menu (as buttons) and two forms I want to slide in. This is the component structure:
MainForm
UINavigationController
UIButtonA
UIButtonB
UIViewController1
FMXwrapper that wraps Form3 (only in TMS iCL)
Form2
UIViewController2
UIButton2
Form3
Various Firemonkey custom controls
Implementation with TMS iCL: FMXwrapper makes it possible to slide in Form3 (which has FMX components), using the command UINavigationController.PushViewController(UIViewController1). I can also slide in UIViewController2, but the components on this form (UIButton2) is not shown, which seem to happen because it is on another form. If TMS iCL really requires all components to be on the same form, then it is useless, unless you make very small apps, but maybe there is a solution to this?
Implementation with D.P.F.: You can actually embed forms from other units, so here I can slide in Form2, but it will only show DPF components on those forms. Therefore sliding in Form3 does not show any components. Is there any solution or workaround to make that work?
Any suggestions how to solve the limitations in either of the component sets?

Use a UITabBarController on Form1 with multiple tabs (instead of Form2). You can slide between the tabs for native controls.
To get the FMX Form3 to slide in you could set TForm.Transparent := True;. Then use Form3.Show; to show the form. Have a TPanel/TRectangle in Form3 that contains your controls. Set TPanel.Position.X := Screen Width; and then animate sliding it in from the right after TForm.Show;

I contacted TMS to solve the problem with showing components from other forms. The components simply needs to be initialized on the form first. The simple solution is to quickly show and hide Form2 in MainForm.FormShow. However, with many "hidden" forms it might cause flickering so TMS suggested to make a small function (see below)
As a bonus, here is my evaluation of the two componentsets:
TMS iCL: Simple but stable
They implement very few of the native properties as published properties in the FMX control. It is not a big problem as you can still access the native object directly and modify its properties, but it requires a more knowledge about the iOS classes and how they work.
It does not include a working Windows target userinterface.
It has the FMX wrapper, which allows you, to some extend, place FMX components inside native components. (normally when you mix native components with FMX components on a form, the native are always in front, so you cannot use native navigation components because they take up the full screen and covers the FMX components)
D.P.F native controls: Comprehensive but less stable
They implement a lot more native properties as published properties in the FMX control. It makes it a lot faster to work with, especially if you are not familiar with the iOS native controls and their properties.
It does allow you to test your program on Windows (which is much faster than running it on the iOS simulator), as the controls actually works in Windows. Of course the graphics is simplified, but the purpose of this is to test functionality and not the user interface.
There is no way to mix FMX and native components, though you can place native components on a form with FMX components with the limitation as mentioned in TMS point 3.
Conclusion: In the end I decided to buy TMS iCL, for two reasons:
I have a lot of custom controls that I don't want to convert to iOS custom controls, so the FMX wrapper is indispensable for me.
I can get support. For a company this is much cheaper than a free solution without support where you have to spend hours to figure out everything yourself.
The procedure suggested by TMS:
TMainForm
...
procedure InitializeControl(AControl: TControl);
...
implementation
...
procedure TMainForm.InitializeControl(AControl: TControl);
var I: Integer;
begin
if not Assigned(AControl) then
Exit;
if AControl is TTMSFMXNativeUIBaseControl then
begin
(AControl as TTMSFMXNativeUIBaseControl).Initialize;
for I := 0 to AControl.ControlsCount - 1 do
InitializeControl(AControl.Controls[I]);
end;
end;
...
InitializeControl(Form2.TMSFMXNativeUIViewController2);

Related

Is there any way to add a hint or tooltip with FireMonkey?

I've earched for it but couldn't find anything. Is there any way to add a hint or tooltip with FireMonkey? Are there any components available that enable this?
Ideally I am looking for something like this (a callout type tooltip):
To the moderators who have placed this question on hold: I am looking for lines of source code on how to achieve this, not a software to buy/use. There are currently (AFAIK) no source code components that enable doing this, so there is no risk of "opinionated anwers or spam".
This is how I finally did it: to create a hint for a Button that looks like this:
Add a button to a form. Then add a TPopup. Drop a CalloutPanel inside it and optionally set the align to AlClient. The drop a TLabel on that CalloutPanel and write your hint text.
Your structure should look like this:
Then go to the TPopup and set PlacementTarget to Button1 (your button). Next, go to Placement and select BottomCenter:
Next add a handler for the MouseEnter and MouseLeave events on the button:
procedure TForm1.Button1MouseEnter(Sender: TObject);
begin
Popup1.IsOpen := True;
end;
procedure TForm1.Button1MouseLeave(Sender: TObject);
begin
Popup1.IsOpen := False;
end;
That should do it.
You can use FloatAnimation and Opacity property to make a hint.
Add a button to a form. Then add CalloutPanel (or any shape) inside.
Next drop a TLabel on the CalloutPanel to write your hint text. I set CalloutPanel.Visible property to False at the Form Creating moment. Then attach a TFloatAnimation to a CalloutPanel.Opacity property.
Next set some TFloatAnimation properties:
Because of Duration Hint appears smoothly.
Then create Button events OnMouseEnter and OnMouseLeave .
procedure TForm1.Button1MouseEnter(Sender: TObject);
begin
CalloutPanel1.Visible := true;
end;
procedure TForm1.Button1MouseLeave(Sender: TObject);
begin
CalloutPanel1.Visible := false;
end;
That's it
I am new to Delphi and FireMonkey. And I also wanted tool tips. And here is what I figured out: FireMonkey has no provision for tool tips, and this is deliberate and for good reason.
I think the big idea with FireMonkey is that you develop one and only one program. Then, without changing even one line of code, you compile a version to run on Windows, another version to run on Android, another version to run on Mac OS, etc. So without changing even one line of code, you have a version for Desktop and a version for Smartphones that work exactly the same way with the same user interface.
Therefore, FireMonkey is only going to support features that are common to both smartphones and desktops. On smartphones, there is no such thing as hovering a mouse, a finger, or anything else. Therefore, Firemonkey does not support hovering on desktops. Because there is no hovering, there can be no tooltips ('hints' in Delphi nomenclature).
So you have to decide: Do you want an app that works exactly the same in Windows and on smartphones, without changing the code and without having separate code? Or do you want all the desktop features? If you want all the desktop features, including tooltips (hints) and all the rest, then you should be using Embarcadero's VCL (Visual Component Library). Using VCL will allow you to get tooltips (hints) by just setting the 'hint' property of text boxes, buttons, and all the other controls--and without writing code.
But if you want an app that works on smartphones, you will have to use FireMonkey. VCL won't work for that.
As I mentioned, I'm still new to Delphi. So, of course, I appreciate corrections
from experienced Delphi developers.

Looking for a 3rd party tabcontrol in Delphi FireMonkey

I am looking for a alternative to Raize components' tab control.
I would like to have the ability to add close button at the top of each page and I want to use slanted tabs and colors on the tabs. Oh, and I'm using FireMonkey 2.
//I know that raize does not support firmonkey.
Firemonkey has it's own TTabControl in the Common Controls page (by default). You can style this using a TStylebook. For example, I'm quite confident it's possible to add a close button onto the tab itself.
After all, FMX is a vector-based framework and so all visual elements must exist within the style. You'll probably want to load a style into a TStylebook for this, as I'm unable to find a way to load the default style into one. Navigate down to tabitemstyle, and from there you'll be able to tweak the visual appearance of it. Simply add a close button as you'd like (alignment, layout, etc).
Back in your application code, you'll be looking to use the FindStyleResource routine in order to setup the code (XE2 uses FindBinding and as such you'd set the BindingName property instead). I'm going to assume your close button is called 'CloseButton' (without the quotes);
var
MyTab : TTabItem;
begin
MyTab := ((TabItem1 as TTabItem).FindStyleResource('CloseButton') as TButton).OnClick := TabClose;
end;
You'd want to add that code when you initially create the tab, or if creating all the tabs at design time, you'll want to run it at FormCreate. You're basically telling it that when CloseButton is clicked, that you want to call the notify event/procedure TabClose. This procedure is identical to a button click.
You could go so far as changing the StyleName property of the tab to be CloseButton+Index_of_tab.
Now, as for the code to close the tab itself, something like this untested example may work, though you'll want to iterate on it.
procedure TForm1.TabClose(Sender: TObject);
var
_mytab : Integer;
_activetab : Integer;
begin
_activetab := ((Sender as TTabItem).Parent as TTabControl).ActiveTab.Index;
_mytab := ((Sender as TTabItem).Parent as TTabControl).ActiveTab.Index;
((Sender as TTabItem).Parent as TTabControl).Tabs[_MyTab].Free;
((Sender as TTabItem).Parent as TTabControl).TabIndex := _activetab;
end;
Now, this is the clever part, and exploits the design of the framework. When you click on a style element that's inside another element, by default, it'll select the parent element. In this example, it'll select the tab that contains the close button the user clicked on. From this, it'll then close that tab (technically, it'll free it, I've not dealt with tabs much in development so you'll want to look into the proper method of 'closing' them).
There is one problem with this though; You'll probably want to find a better way of detecting the previously active tab if you wish to switch back to it. Right now, it'll simply open the tab that was after the tab you just closed (since the tabcount is now 1 less, the active tab index selects the next physical tab). You'll probably be able to do this by splitting the _activetab code off elsewhere.
I've done similar things with some of my own programs, and this is how I usually create 'hybrid' components. You're essentially exploiting the modular design of the framework to make it do what you want it to do, without having to rely on third party components.
Since FMX is a pretty young framework there aren't many 3rd party component vendors that support it yet.
I haven't seen any 3rd party TabControl component for FMX and a quick Google search suggests there aren't any. So you might be out of luck.
I know this is an old query but in case anyone is still looking for tabs with close buttons and slanted tab sides, check out TMSSoftware's TTMSFMXTabSet. I'm using it in a current development project and it is working fine.

define a page control as a jvcl dockserver.custom dock panel. is it possible?

I have a main form with a left panel and in the center of the form I have a page control..and I am trying to dock other forms on the page control, as I have seen on an example made by Alister Christie; the thing is that the dragging of forms into the pagecontrol is lazy; I've discovered that a JVCL dockserver and a JVCL dockclient will help me with this.. the thing is that I want to assign pagecontrol to JVCL dockserver as a custom dock panel, but i don't know how to do it: here is the code i wrote on the oncreate event of mainform
procedure Tform1.FormCreate(Sender: TObject);
begin
jvdockserver1.CustomDockPanel := jvpagecontrol1;
end;
could you please help me out?
Forgot to mention that I am a kind of a novice in programmning and I am using Delphi XE2;
The JVCL Docking server component can only accept a PANEL as a docking location, either one of the built in ones, or a custom TPanel that you place on your form at designtime. However the Jedi Docking library will create page controls for you if you want it to. However, it has to be the one that manages them, because those controls could get moved (by you or by some other jvdocking code).
So, if you want to have some tabs visible, you should not try to use your own page control, instead you should use the Docking In Code Demo as your sample, which comes with the JVCL, in the folder jvcl\examples\JvDocking\DockingInCode.
Here is what the tabs look like that the JvDocking system makes for you, using the CustomDockPanel where the custom dock panel is attached to a TPanel, and then JvDocking "creates a page control" automatically for you when you need it:
Note that the pages are created or destroyed by the docking system, and the underlying work of managing the tabs is done by the JvDocking library, not by you.
The main thing you need to do is use this code from MainFm.pas:
tabHost := ManualTabDock( ctrl, newDocFm1, newDocFm2);

Delphi buttons show white border on Aero glass

I have been trying to find a good-looking design using Aero in Delphi 2010. One of the obvious uses one sees, is where the glass frame is extended to include the OK/Cancel buttons at the bottom of the screen. I notice though that this doesn't look quite right in Delphi 2010 - there is a white border all around each button.
This image shows the problem: the top 3 buttons are from my app, the bottom two were taken from Paint.NET's Layer Properties dialog.
I tried various combinations of DoubleBuffered and a few combinations of placing the controls on other controls first, but the problem remains. Any ideas?
If no one has a clean solution, as a workaround use TBitBtn with DoubleBuffered = false.
It appears that the only workaround is owner-draw, or a third-party button control Check out the Glass Button by Roy Klever or, as stated in the QC entry linked below, TBitBtn with DoubleBuffered=false, which was the accepted answer above to this question.
This is a bug in Windows Aero DWM or else a bug in the windows common controls, or a bug in the way the VCL class hierachy handles common control window messages and painting when painting on glass. In short, windows common controls do not paint themselves properly on glass, or rather DWM composition (Aero) is broken. Surprise surprise.
The standard VCL button component uses the Window Class BUTTON from Windows Common Controls.
Note that TSpeedButton does not use the windows common control, and does not have this problem. however, it also does not accept focus.
It appears Embarcadero knows about this issue, it is QC # 75246, which is closed because it is really a bug in the common controls library, as Won't Fix, with the suggestion to use TBitBtn. Buttons are not alone, this is part of a group of QC reports including panels, and other common controls.
However I have a commercial TcxButton (part of developer express components) which accepts keyboard focus, and does not draw this glitch. Any code that uses the Win32 common control button control appears to have this problem. It may be possible that a low level Win32 API hacker might find a workaround for this. I am looking into it. This answer will be updated if I figure it out.
One interesting detail: TcxButton has three drawing styles, cxButton.LookAndFeel.Kind = {lfOffice11,lfFlat,lfStandard}. Selecting lfOffice11 adds this glitch back in. It looks like a strange interaction between the glass feature in aero in Vista/Win7 and the common control/xptheme button drawing code.
It may be that the only workaround is to use a completely app-drawn button control and to not use Windows common controls buttons, or any button control that relies upon the XP theme engine to draw buttons, on an aero glass pane.
Edit: July 28, someone at Embarcadero has closed the above QC Entry, which was a mistake. I am urging them to reopen it, if only to clarify if this is indeed a Windows bug in the common controls dll.
If you wish to play around, make a copy of the VCL source code for the TButton and TCustomButton classes from StdCtrls, as I have done here, modify CNCtlColorBtn, so that you force one of three things to happen - PerformEraseBackground, DrawParentBackground or inherited, and see the results. Interesting stuff.
procedure TCustomGlassButton.CNCtlColorBtn(var Message: TWMCtlColorBtn);
begin
PerformEraseBackground(Self, Message.ChildDC);
Message.Result := GetStockObject(NULL_BRUSH);
(*
with ThemeServices do
if ThemesEnabled then
begin
if (Parent <> nil) and Parent.DoubleBuffered then
PerformEraseBackground(Self, Message.ChildDC)
else
DrawParentBackground(Handle, Message.ChildDC, nil, False);
{ Return an empty brush to prevent Windows from overpainting we just have created. }
Message.Result := GetStockObject(NULL_BRUSH);
end
else
inherited;
*)
end;
Some interesting reading on Vista era glass/DWM/aero APIs (C++ developers blog)
Here I'm providing some code that makes TButton look right on Glass. Unfortunately it makes the form "click-throw", so I don't think it's a good idea. But maybe you can find a way to fix the form's "click-throw".
if you are able to use win32 api, try exploiting NM_CUSTOMDRAW notification (not ownerdraw), as i do (yes, buttons DO send it, including radio and checkboxes. For these it is best to use WM_CTLCOLORSTATIC though.). This is how it is done in C++, but the idea is the same. While my idea is good, it so happens that my buttons do DISAPPEAR once per program execution from the window, when they are customdrawn and i need to hover mouse over them so they are visible again. That's why i'm still looking for comments for this. Note that it is really difficult to reproduce disappearing buttons in one-form applications. I hovewer am experiencing this behaviour in every project.
case WM_NOTIFY:
switch(((LPNMHDR)lParam)->code){
case NM_CUSTOMDRAW:
{
NMHDR *nmh=(NMHDR*)lParam;
//these 6000 through 6004 are button identifiers assigned by me
if(nmh->idFrom >= 6000 && nmh->idFrom <= 6004){
switch(((LPNMCUSTOMDRAW)nmh)->dwDrawStage){
case CDDS_PREERASE:
//BackgroundBrush is a HBRUSH used also as window background
FillRect(((LPNMCUSTOMDRAW)nmh)->hdc, &((LPNMCUSTOMDRAW)nmh)->rc, BackgroundBrush);
break;
}
}
break;
}
break;

How do I make dockable forms like the IDE's without the very slow freezing movement of the dockable form?

How do I do the IDE method or eventually make the basic dock method without the very slow freezing movement of the dockable form?
When I Googled for dockable forms in Delphi and found a post by Zibadian on Programmers Heaven:
First off: The windows in the Delphi IDE aren't MDI forms, by SDI forms.
Now to create a dockable window.
Form2 will be dockable and Form1 will be the place to dock it to. Place a control (such as a TPanel) on Form1 to serve a DockSite. Make sure that you set the DockSite and the UseDockManager properties to true for that control.
For Form2 set the DragKind to dkDrop, the DragMode to dmAutomatic and UseDockManager to true.
That was the basic dock function. If you run your program, show the Form2 and drag that form over the docksite, it should dock at that site. You can even undock it by grabbing the "caption" as you have seen in the IDE.
For me, that method moves the dockable form very slowly. However, Zibadian's answer continues to describe how the IDE does it instead:
The dock-method of the IDE is a little more complex, since you don't see the docksite. I think, you need to write a Form1.OnDockOver or Form1.OnDockDrop to perform that. That (Those) event(s) need to show the docksite at the appropriate location.
Have a look at the Using the TDockTabSet component article by Jeremy North. It is a few years old but should give you some helpful pointers.
Try the JVCL Docking library

Resources