If in Delphi 2010 or XE Application.MainFormOnTaskbar is set to true then all secondary forms are always in front of the main window. It does not matter what the Popupmode or PopupParent properties are set to. However I have secondary windows that I want to be able to show behind the the main form.
If I set MainFormOnTaskbar to false it works, but then the Windows 7 features are broken (Alt-tab, Windows bar icon, etc).
How can I keep the Windows 7 features working while still allowing secondary forms to hide behind the main form?
Basically you can't. The whole point of MainFormOnTaskBar is to have Vista compatibility. If you don't set it, compatibility is gone.., if you set it, z-order is done. The following excerpt is from D2007's readme:
The property controls how Window's TaskBar buttons are handled by VCL. This property can be applied to older applications, but it affects the Z-order of your MainForm, so you should ensure that you have no dependencies on the old behavior.
But see this QC report, which describes the exact same problem (and closed as AsDesigned). The report states a workaround involving overriding CreateParams of a form to set the WndParent to '0'. It also describes a few problems which this workaround causes and a possible workaround for those problems too. Beware, it wouldn't be easy/possible to find and workaround all complications. See Steve Trefethen's article to have a feeling of what could be involved.
I would have thought that one approach would be to have a "behind-the-scenes" main form which serves only the following purposes:
To select and show one of the other forms as the main form and then perpetually hide itself (Visible:=FALSE) like the good old-fashioned "flash" screens.
To act as an application terminator when the form it selected as the main form is closed (just wire the appropriate OnClose events).
To open other forms on behalf of the designated pseudo-main-form such that the hidden real main form is the "owner" of the other forms, not the "pseudo-main-form". It appears that this will happen anyway if all your other forms have a 'non' pop-up style and are visible via Show calls rather than ShowModal.
This small restructuring of the application's behavior may then get you the kind user interaction that you are looking for.
unit FlashForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls;
type
TFlash = class(TForm)
lblTitle: TLabel;
lblCopyright: TLabel;
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
public
procedure CloseApp;
end;
var
Flash: TFlash;
implementation
{$R *.dfm}
uses Main;
procedure TFlash.CloseApp; // Call this from the Main.Form1.OnClose or CanClose (OnFormCloseQuery) event handlers
begin
close
end;
procedure TFlash.FormCreate(Sender: TObject); // You can get rid of the standard border icons if you want to
begin
lblCopyright.Caption := 'Copyright (c) 2016 AT Software Engineering Ltd';
Refresh;
Show;
BringToFront;
end;
procedure TFlash.Timer1Timer(Sender: TObject);
begin
Application.MainFormOnTaskBar := FALSE; // This keeps the taskbar icon alive
if assigned(Main.MainForm) then
begin
visible := FALSE;
Main.MainForm.Show;
Timer1.Enabled := FALSE;
end else Timer1.Interval := 10; // The initial time is longer than this (flash showing time)
end;
end.
// Finally, make this the FIRST form created by the application in the project file.
i found a way to solve this issue.
on *.dpr
change
Application.MainFormOnTaskbar := true;
to
Application.MainFormOnTaskbar := false;
this will allow you child form behind you main form.
Related
Have a main form (Form1) where is created a MDIForm (Form2) and a MDIChild (Form3) form respectivelly in execution time. In my tests the MDIForm (Form2) is show like expected but when try show the MDIChild (Form3) i get the following error that say:
Cannot create form. No mdi forms are currently active
Some idea about how fix this?
program Project1;
uses
Vcl.Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2},
Unit3 in 'Unit3.pas' {Form3};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Form:
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
Unit2, Unit3;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Form2 := TForm2.Create(Self);
Form2.Show;
Form3 := TForm3.Create(Form2);
Form3.Show;
end;
end.
The VCL (not the Win32 API) is hard-coded to allow only the Application.MainForm to be set to fsMDIForm for hosting fsMDIChild Forms. Your MainForm is not the fsMDIForm parent Form, which is why you are getting the error.
Using a secondary Form as the fsMDIForm parent is technically possible, but not out of the box. It requires a bit of manual work hacking up the VCL's internals to make it work, and even then there are holes and gotchas. See my Multiple MDI Parent Forms in a single Application submission on CodeCentral for an example (I haven't updated it in over a decade, so it may need some tweaking for modern VCL versions). The old Quality Central (not Quality Portal!) ticket it refers to can be found on archive.org: #12006: Hosting MDI child forms in non-MainForm forms.
That being said, MDI is a dead technology, Microsoft abandoned it a long time ago, and modern Windows versions have poor support for MDI, especially when Visual Styles are used. You are best off not even bothering with MDI in modern software, there are other/better UI design choices available.
I'm making use of a GDI+ canvas in Delphi 10.1 Berlin, using the built-in units GDIPAPI and GDIPOBJ. I have a thread which is performing drawing, and while looking for ways to improve the performance of the thread, one major drawback is the fact that I'm currently forced to instantiate an instance of this canvas (TGPGraphics), perform the drawing, and destroy the canvas, all together at the same time, at the moment I wish to draw. Instead, I would like to maintain a single constant instance of TGPGraphics.
Problem
The problem is that when I attempt to create a single global instance of TGPGraphics and use it in the future, for some reason it ends up drawing nothing onto the canvas. It results in just an empty unpainted canvas. It only works when I create/destroy the canvas at the exact moment I need to actually draw anything. I seem to be forced to create the instance, perform the painting, then destroy it, before I'm allowed to read that bitmap image.
The same problem happens elsewhere, not just inside the thread and not just on a TBitmap. I faced this issue in the past, but I was able to get away with constantly creating/freeing it for that project. This one though, it's not acceptable.
Question
How can I retain a single instance of TGPGraphics instead of creating/destroying it each time I need to draw?
Example
Here's a minimal test application which demonstrates the issue. Turn the GLOBAL_CANVAS conditional on and off - be sure to do a Build when changing, don't immediately go to Run. It's just a blank form with no components, just code:
unit uMain;
interface
{$DEFINE GLOBAL_CANVAS}
{$DEFINE FLUSH_SYNC}
{ $DEFINE FLUSH_BEFORE}
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
GDIPAPI, GDIPOBJ;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormResize(Sender: TObject);
private
FCan: TGPGraphics;
FPen: TGPPen;
FBmp: TBitmap;
function CreateCanvas: TGPGraphics;
procedure DoFlush;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FBmp:= TBitmap.Create;
FBmp.Width:= ClientWidth;
FBmp.Height:= ClientHeight;
{$IFDEF GLOBAL_CANVAS}
FCan:= CreateCanvas;
{$ENDIF}
FPen:= TGPPen.Create(MakeColor(255, 0, 0));
FPen.SetWidth(4.0);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FPen.Free;
{$IFDEF GLOBAL_CANVAS}
FCan.Free;
{$ENDIF}
FBmp.Free;
end;
function TForm1.CreateCanvas: TGPGraphics;
begin
Result:= TGPGraphics.Create(FBmp.Canvas.Handle);
Result.SetInterpolationMode(InterpolationMode.InterpolationModeHighQuality);
Result.SetSmoothingMode(SmoothingMode.SmoothingModeHighQuality);
Result.SetCompositingQuality(CompositingQuality.CompositingQualityHighQuality);
end;
procedure TForm1.DoFlush;
begin
{$IFDEF FLUSH_SYNC}
FCan.Flush(FlushIntention.FlushIntentionSync);
{$ELSE}
FCan.Flush(FlushIntention.FlushIntentionFlush);
{$ENDIF}
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
{$IFNDEF GLOBAL_CANVAS}
FCan:= CreateCanvas;
try
{$ENDIF}
{$IFDEF FLUSH_BEFORE}
DoFlush;
{$ENDIF}
FCan.DrawEllipse(FPen, 5, 5, 50, 50);
{$IFNDEF FLUSH_BEFORE}
DoFlush;
{$ENDIF}
{$IFNDEF GLOBAL_CANVAS}
finally
FCan.Free;
end;
{$ENDIF}
Caption:= 'Handle: ' + IntToStr(FBmp.Canvas.Handle);
Canvas.Draw(0, 0, FBmp);
end;
procedure TForm1.FormResize(Sender: TObject);
begin
FBmp.Width:= ClientWidth;
FBmp.Height:= ClientHeight;
end;
end.
The left is when I create/free the canvas at the time of painting, and the right is when I create/free the canvas at startup/shutdown.
EDIT
I just noticed something - when GLOBAL_CANVAS is enabled in the test above, and then you resize the form to complete minimal size, then make it bigger again, you can see little bits and pieces of the drawing, but not the entire thing.
EDIT 2
I tried the recommendation to use Flush, and I switched it from FlushIntentionFlush to FlushIntentionSync, and now I have about a 50/50 success rate. Sometimes I run the app and it shows, and other times, making no changes at all, I run the app and nothing draws. I tried many different combinations of using Flush, using both methods, before drawing and after drawing. The few times it does appear to work, I resize the form to hide it, and make it larger again, and I can only see a glitchy image...
EDIT 3
I discovered the cause of the problem: the canvas handle keeps getting recreated, so each time I go to draw, the canvas has a whole new handle. I get the same behavior with both TForm.Canvas.Handle and TBitmap.Canvas.Handle. I'm not sure what the appropriate solution is though. I can't find a way to pass the new handle into the canvas object. The reason why it sometimes draws a glitchy image is because sometimes it obtains the same handle, but most of the time, it's different.
I'm attempting to style a TPopup with several subcontrols, and then assign event handlers to those controls that need them (buttons primarily). I am using TPopup.IsOpen:=True.
When using TPopup.popup(True), input is detected and all mouse events work great, but I do not want the user to do anything more than "click" away from the popup window to close it.
Very similar issues found here, but there wasn't really a suitable answer other than using a modal popup.
Delphi XE5 FireMonkey TstringGrid cells don't accept keyboard input
and, this also has a somewhat acceptable answer, but my style has opaque areas that render black on a borderless form. I'd set the form's transparency, but this causes performance issues that I'd rather tackle on another day.
Allowing keyboard input to a FireMonkey TEdit nested inside a FireMonkey TPopup
Full process from start to finish:
1. set TPopup.StyleLookup:='MyStyle';
2. Assign event handlers to subcontrols
3. set TPopup.IsOpen:=True;
4. Attempt to press tab in any TNumberBox/Edit (No Keyboard input detected)
5. Attempt to click any button with assigned handler (No Mouse input detected)
Edit
After a lot of testing I was able to get mouse events to be fired for buttons, but I still cannot get user keyboard input. I've attached sample code from my tester app that opens a popup on right click
if just right click, opens standard popup with buttonstyle applied
if right click and shift, opens modal popup with buttonstyle applied
if right click and alt, opens standard popup with memostyle applied (This is the part not working)
The goal would be to allow the user to type in the popup. There is a TMemo on the form already for testing if my popup's "TMemo" will get focus after clicking the popup, and for verifying the stylenames of a standard TMemo. Also, there is a tlayout with a tmemo as a child. I used this to create a basic style that could be applied to my TPopup. (Please forgive any poorly named variables or unused code... I've tried a lot of different things with little luck.. I'm not really sure where to start and what to toss)
Unit 1 Code:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,System.Rtti,
FMX.Styles.Objects, FMX.Layouts, FMX.Memo;
type
TForm1 = class(TForm)
Memo1: TMemo;
StyleBook1: TStyleBook;
Layout1: TLayout;
Memo2: TMemo;
Popup1: TPopup;
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Single);
private
{ Private declarations }
public
{ Public declarations }
procedure DoButtonClick(Sender:TObject);
procedure DoMemoClick(Sender:TObject);
function FindRootStyleResource(const AObject: TFmxObject; const AStyleLookup: string):TFmxObject;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.DoButtonClick(Sender: TObject);
begin
showmessage('WoooHooo!');
end;
procedure TForm1.DoMemoClick(Sender: TObject);
begin
if Sender is TMemo then
Begin
Tmemo(Sender).SetFocus;
with FindRootStyleResource(TFmxObject(Sender),'background') as TActiveStyleObject do
Begin
CanFocus:=True;
HitTest:=True;
Locked:=False;
SetFocus;
End;
Self.Focused:=nil;//Removes the focus from the current form to TPopup (TCommonCustomForm)
End;
end;
function TForm1.FindRootStyleResource(const AObject: TFmxObject;
const AStyleLookup: string): TFmxObject;
var
SearchResult,Child:TFmxObject;
begin
Result:=nil;
//No object get out
if AObject=nil then
exit;
//No Style lookup, get out
if AStyleLookup='' then
exit;
//If Current object is what we're looking for, set result
if AObject.StyleName.ToLower=AStyleLookup.ToLower then
Result:=AObject;
//if Object has children need to check lower levels
if AObject.ChildrenCount>0 then
Begin
//Now Recurse the children
for Child in AObject.Children do
Begin
SearchResult:=FindRootStyleResource(Child,AStyleLookup);
if SearchResult<>nil then
Result:=SearchResult
End;
End;
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Single);
Var
O:TFmxObject;
begin
if (Button=TMouseButton.mbRight) and not ((ssShift in Shift) or (ssAlt in Shift)) then
Begin
Popup1.Width:=100;
Popup1.Height:=100;
Popup1.StyleLookup:='buttonstyle';
ApplyStyleLookup;
(*
O:= FindRootStyleResource(popup1,'background');
TButtonStyleObject(O).OnClick:=DoButtonClick;
TButtonStyleObject(O).HitTest:=True;
TButtonStyleObject(O).Locked:=False;
*)
Popup1.StylesData['background.OnClick']:=TValue.From<TNotifyEvent>(DoButtonClick);
Popup1.StylesData['background.HitTest']:=True;
Popup1.StylesData['background.Locked']:=False;
Popup1.IsOpen:=True;
End
else if (Button=TMouseButton.mbRight) and (ssShift in Shift) then
Begin
Popup1.Width:=100;
Popup1.Height:=100;
Popup1.StyleLookup:='buttonstyle';
ApplyStyleLookup;
(*
O:= FindRootStyleResource(popup1,'background');
TButtonStyleObject(O).OnClick:=DoButtonClick;
TButtonStyleObject(O).HitTest:=True;
TButtonStyleObject(O).Locked:=False;
*)
Popup1.StylesData['background.OnClick']:=TValue.From<TNotifyEvent>(DoButtonClick);
Popup1.StylesData['background.HitTest']:=True;
Popup1.StylesData['background.Locked']:=False;
Popup1.Popup(True);
End
else if (Button=TMouseButton.mbRight) and (ssAlt in Shift) then
Begin
Popup1.Width:=100;
Popup1.Height:=100;
Popup1.StyleLookup:='MemoPopupStyle';
ApplyStyleLookup;
Popup1.StylesData['content.OnClick']:=TValue.From<TNotifyEvent>(DoMemoClick);
Popup1.StylesData['content.HitTest']:=True;
Popup1.StylesData['content.Locked']:=False;
//Popup1.StylesData['background.TabStop']:=True;
//Popup1.StylesData['background.Enabled']:=True;
Popup1.IsOpen:=True;
End;
end;
end.
Project Source:
program Project1;
uses
System.StartUpCopy,
FMX.Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Again, any help is greatly appreciated, thanks!
Decided just to go with this answer here:
Allowing keyboard input to a FireMonkey TEdit nested inside a FireMonkey TPopup
For transparency, I added a child TPanel on the fmPopup form named Content. Afterwards I set the Transparency:=True, and applied my custom style to the Content panel. Not exactly what I wanted because I had to write my own positioning/hiding procs that a TPopup already had, but my existing "initialize style" procedure worked without any modifications. I certainly welcome any better solutions.
I would like to hide an application from the Windows 7 taskbar.
I want to make something like a toolbar on the edge of the screen which does certain things when the user clicks on it, but I don't want it to show in the taskbar, since its a thing that i want to stay in the background.
I tried the instructions in the following post, but it did not work on my application:
How to hide a taskbar entry but keep the window form
Then i tried it on a new empty VCL Forms Application and it still did not work. I searched for other solutions, but they all do very much the same like in the linked post.
Has something changed, that makes that impossible in windows 7? Or is there anything you
could think of, that could prevent it from working?
You can override the main form's CreateParam to remove the flag that forces the taskbar button (WS_EX_APPWINDOW) and additionally make the form owned by the application window. That's doing the opposite of the requirement for the shell to place a taskbar button for a window. From "Managing Taskbar Buttons":
[..] To ensure that the window button is placed on the taskbar, create an
unowned window with the WS_EX_APPWINDOW extended style. [..]
Sample:
type
TForm1 = class(TForm)
protected
procedure CreateParams(var Params: TCreateParams); override;
end;
procedure TForm1.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.ExStyle := Params.ExStyle and not WS_EX_APPWINDOW;
Params.WndParent := Application.Handle;
end;
Don't change the state of MainFormOnTaskbar property of the 'Application' from its default 'True' if you use this method.
You can also remove the second line (..WndParent := ..) and instead set PopupMode of the form to pmExplicit in the object inspector to same effect.
BTW, here's the documentation quote from the same topic for the solution TLama posted:
To prevent the window button from being placed on the taskbar, [...]
As an alternative, you can create a hidden window and make this hidden
window the owner of your visible window.
When you set MainFormOnTaskbar to false, the main form is owned by the application window by VCL design. And if you hide the application window, the requirement is fulfilled.
Try to use a tricky way described in this article:
Set the MainFormOnTaskBar to False in your project file. Then try to hide the application window from the main form's OnShow and OnActivate event handlers. So your project might look like follows:
Project1.dpr:
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := False;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Unit1.pas:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormShow(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormShow(Sender: TObject);
begin
ShowWindow(Application.Handle, SW_HIDE);
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
ShowWindow(Application.Handle, SW_HIDE);
end;
end.
your application main form is normally created in the dpr so open the dpr and look for the line that creates the main form.
// add this line first
// blank app title will prevent app from showing in the applications list in task manager
Application.Title := '';
// this line is already in the dpr and creates the main form, the class will differ
Application.CreateForm(TMainForm, Result);
// make the main form invisible to windows taskbar/task switcher
i := GetWindowLong(Application.Handle, GWL_EXSTYLE);
SetWindowLong(Application.Handle, GWL_EXSTYLE, i OR WS_EX_TOOLWINDOW AND NOT WS_EX_APPWINDOW);
i know this works on XP and 7. i'm guessing it's good for 8 as well. this adds the tool window flag and removes the appwindow flag so i guess if you're not interested in the toolwindow flag you can leave out the following part
i OR WS_EX_TOOLWINDOW
I built the code below using Delphi XE2. It creates Form1, and Form1 immediately creates an instance of Form2. When I press the button on Form2 a second Form2 is created.
Now if I hover the mouse over the button on this second, topmost, Form2 and wait for the tooltip to appear, the moment the tooltip appears, the first Form2 comes to the front, stealing focus.
The problem occurs only if Application.MainFormOnTaskbar is True. It also relies on the first Form2 being created from Form1's FormCreate method. If I use PostMessage() to delay the creation of the first Form2 until the application has finished initialising, the problem goes away.
I'd like to understand why this is happening. I have already learned that Delphi's Application object handles a lot of things including hint display, and I know that Delphi can recreate a window's handle during initialisation, but I haven't been able to follow this through to explain fully the behaviour described above (or indeed whether the above two facts are even relevant).
Project1.dpr
program Project1;
uses
Vcl.Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True; // False makes problem go away
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Unit1.pas
unit Unit1;
interface
uses
Vcl.Forms, Unit2;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
public
procedure CreateForm2;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
CreateForm2;
end;
procedure TForm1.CreateForm2;
var
frm : TForm2;
begin
frm := TForm2.Create(Application); // (Could pass Self - makes no difference)
frm.Show;
end;
end.
Unit2.pas
unit Unit2;
interface
uses
Vcl.Forms, System.Classes, Vcl.Controls, Vcl.StdCtrls, WinApi.Windows;
type
TForm2 = class(TForm)
Button1: TButton; // This button has a hint
procedure Button1Click(Sender: TObject);
end;
var
Form2: TForm2;
implementation
uses
System.SysUtils, Unit1;
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
begin
Form1.CreateForm2;
end;
end.
The key issue here is that the first instance of TForm2 is created as window that is owned by the application window, Application.Handle. And here I am referring to the Windows meaning of owner. In VCL language this is known as the popup parent.
Now, when you create that first TForm2 instance, the Application.MainForm property is still nil. And because you did not explicitly assign PopupParent, the code in TCustomForm.CreateParams sets the owner to be the application window.
You simply do not want your windows to be owned by the hidden application window. This is the reason why that first TForm2 instance sometimes appears behind all the other windows, in particular behind your main form. It has simply been created with the wrong owner.
The form that is owned by Application.Handle gets shown in THintWindow.ActivateHint. That happens due to the line that reads ParentWindow := Application.Handle. This is followed by a call to SetWindowPos(Handle, ...) which results in the incorrectly owned form coming to the front. Presumably that form comes to the front because it is also owned by Application.Handle. Right now I don't have a clear explanation for the precise mechanism, but I don't find that terribly interesting because the form is clearly setup wrongly.
In any case, the fundamental problem is that you have created a window that is incorrectly owned. The solution therefore is to make sure that the window is owned correctly. Do that by assigning the PopupParent. For example:
procedure TForm1.CreateForm2;
var
frm : TForm2;
begin
frm := TForm2.Create(Application); // (Could pass Self - makes no difference)
frm.PopupParent := Self;
frm.Show;
end;