FMX: Handle of controls - delphi

I'm working with DirectShow in firemonkey, and i have a problem with outputting Video.
iVideoWindow.Put_Owner(Panel1.Handle);
I need handle of TPanel, to display video at it. But FMX controls have no handle. I know, that Firemonkey is not based on traditional windows and FMX do not provide this, but how to solve this problem? I have no idea, please, help me.

If you want to get a window handle as an HWND (Win32 API) type, you can now call this function:
WindowHandleToPlatform(form1.Handle).wnd
Put this in your uses clause:
uses
FMX.Platform.Win;
Note that just calling WindowHandleToPlatform(form1.Handle) will not work, you have to access its .Wnd property to obtain the Win32 handle.
Since this makes an application less portable, it is also a good idea to put {$IFDEF MSWINDOWS} around the code whenever doing this, and if you ever port to MacOS, you'll have to write separate code for that platform. Or, put this code into a separate unit that deals only with MSWindows-related stuff, and IFDEF that unit into your uses.

FmxHandleToHWND is marked deprecated now.
WindowHandleToPlatform will convert given FireMonkey handle to its platform dependent window handle (in your case a Windows handle).

Use Timage control, then you can assign your output to Image1.Bitmap.Handle. Its the only component that provides window Handle under FMX

To get handle of a panel, try this :
uses
FMX.Platform.Win;
var
Handle : HWND;
begin
Handle := TWinWindowHandle (Panel1).Wnd;
end;

Related

Create Firemonkey form and populate by code

I am porting over a VCL component to FMX. 99% of of the code is pure object pascal, so that works just fine - but i have a method which creates a form, poulates it with buttons and a text-box, and this quite simply doesnt work under FMX.
The whole point to creating the form manually and then populating it from code was to make sure it compiled under both VCL, LCL and FMX; and that it also displays just fine under iOS, Android and whatever platform is used.
But i keep getting "Resource /classname/ not found", where /classname/ is whatever classname i give my temporary form class.
Something as simple as this produces the error:
type
TMyDialogForm = Class(TForm);
procedure TForm1.Button1Click(Sender: TObject);
var
LDialog: TMyDialogForm;
begin
LDialog := TMyDialogForm.Create(application.MainForm);
try
LDialog.Caption := 'Yahoo!';
finally
LDialog.Free;
end;
end;
Since the error involves resource, I suspect that it is looking for some type of layout data. I have just started playing around with FMX, and i did notice that different platforms allow for different layouts. But I must admit I expected it to fall-back to the default theme, no matter what platform you target.
So -- how exactly do i create a form by code, populate it and display ut using Firemonkey without running into this kind of bug? It works perfectly fine under VCL and LCL, but FMX keeps going on about resources.
Please dont tell me all forms MUST be designed?
As #RemyLebeau answered a similar question in the delphi forum (How to create a TForm at runtime?):
You are calling the TForm constructor that invokes DFM streaming. The reason
it does not fail in non-FMX apps is because TCustomForm.Create() filters
out TForm specifically so it won't try to stream. In FMX, TCommonCustomForm.Create()
filters out TCommonCustomForm instead of TForm, which is why your TForm in
FMX is trying to stream itself.
Since you know that there is no DFM, you should be using the non-DFM constructor
instead, in both VCL and FMX:
FRM := TForm.CreateNew(Application);

How to make an explorer like file manager in Delphi FMX?

There is no any ShellListView/ShellTreeView component In Delphi FMX.
So, How to make an explorer like file manager in Delphi FMX?
Just simple as to count how many files/folders, certain type files..
and create text , read/write files.
How to deal file system in Delphi FMX?
I can not find System.IOUtils in Delphi FMX.
I think, maybe I totally mis-understand FMX framework.
Any hints?
Thanks!!!
Mitchell Hu
Firemonkey is a visual framework. People get so caught up on the way Embarcadero have marketed it that they often don't realize that much of what can be done with VCL can also be done with Firemonkey - it just requires a different approach and perspective.
With VCL, you'd deal with controls that are native to Windows itself. The VCL simply exposes these through the Delphi (and C++) languages.
With Firemonkey, the controls are created with vector shapes and so they're not native to a specific platform. Because of this, it's possible to create any sort of interface and run it on numerous platforms. At the same time as FMX was released, Embarcadero made their units crossplatform which means that most of the logic and data units included with Delphi can function on any platform which Firemonkey supports. Some functions are still platform specific but the majority is platform inclusive thanks to clever usage of IFDEFs.
With your example, the System.IOUtils isn't specific to a framework and it does work with Firemonkey. You do need to add it to your uses before you can work with it, but the unit includes everything you'd need to create a file manager. System.IOUtils.TDirectory contains routines for creating, renaming, deleting, traversing and manipulating the properties of directories. Many of the old example routines you can find on Google still work (you may want to look for 'recursive directory' examples). System.IOUtils.TFile provides a similar set of routines, but for files instead of directories while System.IOUtils.TPath provides them for paths instead.
System.IOUtils on XE3 Docwiki
System.IOUtils.TDirectory
System.IOUtils.TFile
Expansion 14 April 2013
Using the TTreeView with TTreeViewItem children would work to create the directory structure in the visual.
Using System.IOUtils.TDirectory.GetDirectories('C:\') would return a dynamic string array (TStringDynArray). Something like this may work (Note: Tested - Confirmed that the code example below works);
var
DirArraySize, i : Integer;
DirArray : TStringDynArray;
TreeItem : TTreeViewItem;
begin
DirArray := System.IOUtils.TDirectory.GetDirectories('C:\');
DirArraySize := Length(DirArray);
for i := 0 to DirArraySize-1 do
begin
TreeItem := TTreeViewItem.Create(TreeView1);
TreeItem.text := DirArray[i];
TreeItem.Parent := TreeView1;
end;
end;
I've now tested the code above and after a small correction (changing MyArray to DirArray on line 6 as it should have been) and can confirm that it outputs a list of folders/directories in C:\ into a TTreeView. Making it recursive wouldn't be too difficult and perhaps I'll expand on that in the near future.

How to register a component and property editor at run-time?

After much searching, it looks like I have to assign RegisterComponentsProc and RegisterPropertyEditorProc, which I have done.
However, I thought that I could call my design time Register function, i.e. <myComponentUnit>.Register();.
When I do I get stack overflow, because, well ...
procedure myComponentUnit.Regiter;
begin
RegisterPropertyEditor(TypeInfo(Integer),
TMyComponent, 'myProperty', TMyProperty);
end;
procedure RegisterPropertyEditor(PropertyType: PTypeInfo;
ComponentClass: TClass; const PropertyName: string;
EditorClass: TPropertyEditorClass);
begin
if Assigned(RegisterPropertyEditorProc) then
RegisterPropertyEditorProc(PropertyType, ComponentClass, PropertyName,
EditorClass);
end;
So, I call .Register();
which calls RegisterPropertyEditor()
which call RegisterPropertyEditorProc()
which calls RegisterPropertyEditor() <=== aaargh!!
So, what should I have in the body of my RegisterPropertyEditorProc ?
After further searching, it looks like I want to call DesignEditors.RegisterPropertyEditor() directly, but it is not in the interface section ...
There is no point in trying to register a property editor at run-time, as it is not usable at run-time to begin with. It is only usable within the IDE during design-time.
Delphi does not include the source for the DesignEditors unit; its implementation is provided solely in the DesignIDE package. That package has access to IDE internals, such as the list of registered property editors. The IDE assigns values to the RegisterComponentsProc and RegisterPropertyEditorProc callback functions. As you noticed, RegisterPropertyEditor calls RegisterPropertyEditorProc. The IDE provides its own function to handle that event.
If you want to register a property editor at run time, then your program plays the role of the IDE. You need to provide implementations for those callback functions to register the property-editor classes with your own property-editing framework. You could probably just keep everything in a simple list. Then, when you want to know what kind of editor to display for a certain type of property, consult the list to find the best match.
You're correct that you should call your units' Register procedures. But that's how you initiate the registration process, not how you implement it. That part's up to you; Delphi doesn't provide any of this for you.

Retrieving Delphi Window Handles

I am trying to get the window handles to a Delphi application from an external application. I can see that there are a few windows created (TApplication, TFrmMain and a few others), and I know that TApplication is the "controller", but never visible. However, can I read what the value for the real window is? I know that it is TFrmMain (for this specific application), but is it possible to actually figure this out somehow? Is the information stored in the window properties,or somewhere else? Thanks!
No, there is no documented way to discover which of the windows represents Application.MainForm from outside the application. In newer versions of Delphi, the main form's window handle isn't necessarily Application.MainForm.Handle anyway; applications can handle the OnGetMainFormHandle event to return whatever they want — that's used for choosing the parent window for modal dialogs.
You can guess by looking for windows with "main" in their class names, but even if you find one, there's no guarantee that there's only one instance of it. Applications can have multiple top-level windows, in which case it doesn't make much sense to designate any one of them as the "main" one.
The class name of any Delphi form is also the registered window classname of the underlying "Windows window". So you should be able to use the FindWindow() Windows API call to get the window handle of TFrmMain a little something like:
hWnd := FindWindow('TFrmMain', NIL);
If there are (potentially) multiple instances of a given form class name then you may be able to distinguish between them by using the 2nd parameter (Window Name, i.e. "caption" or title). If that still isn't enough then you may need to get a little bit more sophisticated and look at using the EnumWindows() function and checking the properties of the windows to find the one of interest.
To test the classname of an arbirary window handle (e.g. in your callback function that you use with EnumWindows()), use GetClassName(), e.g:
function GetWindowClassName(const aHWND: HWND): String;
var
buf: array[0..255] of Char; // Tip: Use a more appropriately sized array
begin
GetClassName(SomeHWND, #buf, Length(buf));
result := buf;
end;
...
if SameText(GetWindowClassName(hwnd), 'TFrmMain') then
...
etc
Without specific details of your particular implementation challenge it's difficult to say which is most likely to work best for you, but hopefully that should be enough pointers to get you heading down the right track.
I usually use WinDowse to help me get started, but then you have to use the API functions as described by Deltics.

Is possible to include files (linking) based on a component property?

Delphi 2007/2009 odd question here:
It's possible, based on a component property defined in design-time, to include files in linking or leave them ?
Example: If I leave SomeProperty true, when compiling, the unit SomeUnit will be included into my project. Otherwise it will not be included.
My second approach to this problem is to deploy a second component, which when dropped in the form (or not) will include the unit in uses clause. But if it can be done with a property, that'll be better.
I want to avoid conditional compilation via IFDEF because that forces the component to be built every time the projects are built. Or not?
I am trying to achieve an easy way of including some units in project, and then those units will provide support for specific databases. Having these into an option, at the connection component, will be ideally easy: Check support and that's done. Uncheck, and get some less KBs in your compiled APP.
edit: I'll stay with the component way for instance. I knew the IFDEF method and things, but that forces the component to be built everytime the projects are built. Or not?
I was trying to achieve an easy way of including some units in project, and then that units will provide support for specific databases. Having these into an option, at the connection component, will be ideally easy: Check support and that's done. Uncheck, and get some less KBs in your compiled APP.
No.
What are you trying to solve?
You could add a postcompiling step that would optionally include some resource based on a component property - but you'd have to do some coding to implement such a feature.
You can use the {$IFDEF youridentifier} optional code {$ENDIF} method to conditionally compile data in to your application and then to enable it just go to your project options and enter youridentifier into the appropriate option field. Another method of doing this is to add the following to the top of your unit (or in an include file):
{$DEFINE youridentifier}
which will force youridentifier on. To disable, just place a period right before the $:
{.$DEFINE youridentifier}
Using these techniques its easy to conditionally bring in code or replace code with each compile.
Write an IDE add-in. Handle the "before compile" notification and check whether any forms or data modules in the project have components of the type you're interested in, and then check their properties. Based on what you find there, you can try modifying the contents of a unit to use the other unit of your choice. It certainly doesn't sound easy, but it seems possible.
Your second idea is very easy. It's exactly what the TXPManifest component does, for example. Beware that removing such a component from a form does not "unuse" the associated unit.
To conditionally add support for different databases, you might consider using run-time packages. (That's how the IDE manages to support so many different kinds of components, after all.) Put each database's custom code into a different package. Then, the databases you support are simply whichever ones have packages available at run time. No compile-time or design-time configuration required. The obstacle to this, however, is to manage which packages are available, and determine which of them are the packages that provide database support.
Your second approach will not necessarily work the way you want it to. While Delphi will helpfully add the necessary unit to your uses list when you drop the component onto the form, it will not remove the unit when you delete the component. And even if you don't use the component or any other exported entitiy from that unit, it is possible that the unit will be linked to your application anyway, when there is code in the initialization or finalization part of the unit. This is unfortunately very often the case, even when it would be possible to initialize stuff on-demand.
There is no way to do what you are asking, but something you might not be aware of is that units which are included in your uses list but never referenced will have a minimal impact on the size of your executable. The smart linker that is in Delphi does a very good job of removing code which is never used. If you are careful about your "optional unit" which is referenced by the component, and don't have any code in it which is executed globally (everything is self contained in a class or classes) then it shouldn't matter if it is in the uses clause and not used, or not in the uses clause at all.
This would easily allow you to do what I think your wanting to do, which would be to drop a component on a form which includes a unit that then can be linked to your application. Removing the component would have the effect of not linking in the unit. I believe, however, that any resources (for example forms or other items included by the $R directive) which are in the used unit would still be included in the executable.
You could use DesignIntf.RegisterSelectionEditor to register a selection editor (see comments in Delphi source code about ISelectionEditor), then use the RequiresUnits procedure to include extra units in uses clause.
TMySelectionEditor = class(TSelectionEditor)
public
procedure RequiresUnits(Proc: TGetStrProc); override;
end;
procedure Register;
implementation
procedure TMySelectionEditor.RequiresUnits(Proc: TGetStrProc);
var
comp: TMyComponent;
I: Integer;
begin
inherited RequiresUnits(Proc);
Proc('ExtraUnit');
// might be a better way of doing the code from here onwards?
if (Designer=nil)or(Designer.Root=nil) then Exit;
for I := 0 to Designer.Root.ComponentCount - 1 do
begin
if (Designer.Root.Components[i] is TMyComponent) then
begin
comp := TMyComponent(Designer.Root.Components[i]);
if comp.SampleProperty = True then
Proc('ExtraUnit2');
Proc(comp.ObjProperty.UnitName);
end;
end;
end;
procedure Register;
begin
RegisterSelectionEditor(TMyComponent, TMySelectionEditor);
end;

Resources