I have a modal dialog that is created with the following:
procedure TFormCompose.createParams(var Params: TCreateParams);
begin
inherited createParams(Params);
with Params do begin
exStyle:=exStyle or WS_EX_APPWINDOW;
wndParent:=getDesktopWindow;
end;
end;
In this form, I create an instance of TOpenDialog. When it opens, it sends my first modal dialog behind the main application window.
Is there a way to get the TOpenDialog to open without affecting the Z order of the modal dialog?
Thanks!
What version of Delphi are you using? Delphi 2007 and up add an overloaded TOpenDialog.Execute(ParentWnd: HWND); passing the handle of your modal dialog as the ParentWnd when calling Execute() may help.
For future reference, make sure you specify which version of Delphi. Answers appropriate to Delphi 2009, for example, wouldn't be of much use to you if you were using Delphi 5, and would be a waste of time for the person providing the answer.
Related
I'm using great TExceptionDialog from JEDI JCL package to show unhandled exceptions inside a C++ builder XE project, everything running ok so far. I've decided to enhance it a little bit by writing my own custom form to upload crash report to a server via FTP.
Problem is that I can't open my custom form from delphi PAS unit, tried to define as an external (no delphi programmer here, sorry :( ) but don't know how to properly code that. I've read lots of tutorials but couldn't find anything useful besides writing a DLL or an OLE container for my custom form, realy overkill for this project.
Question is, how can I properly execute this task? how to do ShowModal() of a form defined in a C++ unit, from a PAS delphi unit?
I've found an easy and practical way of doing it, kinda ugly but works!
Trick is to get form by iterating thru all forms with Screen.Forms object. I've set TAG property for my form to a predefined number just to get an easy id of it.
In short, inside C++ unit of my form, I'll do this:
MyForm->Tag=9999; // easy way of Iding my form
Then, inside my delphi unit of TExceptionDialog, in SEND button click method:
procedure TExceptionDialog.SendBtnClick(Sender: TObject);
var
i: integer;
form: TForm;
begin
for i := 0 to Screen.FormCount-1 do // all forms
begin
form := Screen.Forms[i]; // get a form
if(form.Tag = 9999) then // check if its my form
begin
form.ShowModal; // if its mine, call showmodal
break;
end;
end;
ModalResult := mrOk; // return to my app
end;
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Can you make a Borderless Application Main Window in Windows, without WS_POPUP style?
I have a form with BorderStyle:=bsNone;
How can I activate the minimized form by clicking on a it in task bar?
I'm guessing you're using an older version of Delphi (I've just done my testing on Delphi 2010, and I'm guessing you're using something older because in my version I don't need to do anything, restoring the window just works).
Problem 1: How do you MINIMIZE a border-less form? A border-less form doesn't have an "minimize" button! Are you sure it's minimized and it's not actually hidden? I've just attempted this, and I was only able to minimize the form by placing a button on it and running this code from the button:
ShowWindow(Handle, SW_MINIMIZE);
If I clicked on the application's button in my Windows 7 taskbar it came right up without problem. This brings us to the second problem.
Problem 2: What version of Delphi are you using? What version of Windows? Unfortunately it matters. There were changes in what Windows did with the taskbar button, and those changes prompted more changes in what Delphi does to support the taskbar button.
If you're on some old version of Delphi and on some new version of Windows you might try dropping a TApplicationEvents on your form, and from it's OnRestore event do this:
ShowWindow(Handle, SW_SHOW or SW_RESTORE);
The solution is to do
type
TForm1 = class(TForm)
private
protected
procedure CreateParams(var Params: TCreateParams); override;
{ Private declarations }
public
{ Public declarations }
end;
where
procedure TForm1.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.Style := Params.Style or WS_MINIMIZEBOX;
end;
exactly as David did in the old question about this topic.
HI
I'm using Delphi 2007 and have set the MainFormOnTaskBar property to true.
The issue that I'm having is this.
If you open a child window from the main form and then you show a message dialog from the child window you just opened. When you close the message dialog and then close the child window, the main form will be sent to the back of any other application you have on the screen.
This happens under windows Vista and Windows 7. Does anyone know why this is happens and how can I fix it?
I guess that would be QC66892-Closing forms deactivates the application, which appears to have been fixed with Delphi 2009 according to the report. At the bottom of the QC report you'll find a comment by Andreas Hausladen including a link to his fix of the bug. But you'd really want to utilize his VCL Fix Pack which includes many other fixes as well.
I've fixed this in two ways.
Firstly by adding stdcall to the end of DoFindWindow in Forms.pas as described by Andreas Hausladen. This handles when a child form is hidden (CloseAction = caHide) instead of released when closing the form.
Secondly - copied the code from TCustomForm.CMShowingChanged that calls FindTopMostWindow and then activates the window that was returned into TCustomForm.CMRelease.
(Edit: code block needs to be indented by 4 spaces)
procedure TCustomForm.CMRelease;
var
NewActiveWindow: LongInt;
begin
if Application.MainFormOnTaskbar then
begin
NewActiveWindow := 0;
if (GetActiveWindow = Handle) and not IsIconic(Handle) then
begin
NewActiveWindow := FindTopMostWindow(Handle);
end;
if NewActiveWindow <> 0 then
begin
SetActiveWindow(NewActiveWindow);
end;
end;
Free;
end;
This seems to have done it, I'll continue testing to make sure.
The PopupMode and PopupParent properties were added specifically to TForm to address this issue. Before showing the child form, set it's PopupParent to the main form, and it's PopupMode to pmAuto.
PopupParent specifically affects the Z-order of windows when other windows are shown.
The Delphi 2007 help has some documentation on these two properties, but you have to go through TForm to get to them. Use 'TForm,Pop' as your search topic (w/o the quotes, obviously ) to get there. The docs are a little confusing about PopupParent, because it discusses the effect that PopupMode has on the automatic assignment of PopupParent. A little experimentation after reading the docs should pay off, though.
My application is based on modal forms. Main form opens one form with ShowModal, this form opens another with ShowModal, so we have stacked modal forms. There is sometimes a problem that when we call ShowModal in new form, it hides behind previous forms, instead of showing on top. After pressing alt+tab, form comes back to the top, but this is not good solution. Did You meet this problem and how did you handle it?
EDIT:
I use Delphi 7.
You didn't mention which version of Delphi...
Newer Delphi versions have added two new properties to TCustomForm: PopupMode and PopupParent. Setting PopupParent of your modal dialog to the form that's creating that dialog makes sure that the child form stays on top of it's parent. It usually fixes the problem you're describing.
I think this pair of properties were added in Delphi 2006, but it may have been 2005. They're definitely there in Delphi 2007 and up.
EDIT: After seeing you're using Delphi 7, the only suggestion I have is that, in the code that displays your modal form, you disable the form creating it, and re-enable on return. That should prevent the creating window from receiving input, which may help keep the Z-order correct.
Something like this may work (untested, as I'm no longer using D7):
procedure TForm1.ShowForm2;
begin
Self.Enabled := False;
try
with TForm2.Create(nil) do
begin
try
if ShowModal = mrOk then
// Returned OK. Do something;
finally
Free;
end;
end;
finally
Self.Enabled := True;
end;
end;
If Form2 creates a modal window (as you've mentioned), just repeat the process - disable Form2, create Form3 and show it modally, and re-enable Form2 when it returns. Make sure to use try..finally as I've shown, so that if something goes wrong in the modal form the creating form is always re-enabled.
Sorry for adding a separate answer, but I have done a bit more research, and some of it indicates that my previous answer (DisableProcessWindowsGhosting) doesn't help. Since I can't always reproduce this issue, I cannot say for sure.
I found a solution that appears to appropriate. I referenced the code in Delphi 2007 for the CreateParams method and it matches pretty close (without having all of the other code that handles PopupMode).
I created the unit below which subclasses TForm.
unit uModalForms;
interface
uses Forms, Controls, Windows;
type
TModalForm = class(TForm)
protected
procedure CreateParams(var params: TCreateParams); override;
end;
implementation
procedure TModalForm.CreateParams(var params: TCreateParams);
begin
inherited;
params.WndParent := Screen.ActiveForm.Handle;
if (params.WndParent <> 0) and (IsIconic(params.WndParent)
or not IsWindowVisible(params.WndParent)
or not IsWindowEnabled(params.WndParent)) then
params.WndParent := 0;
if params.WndParent = 0 then
params.WndParent := Application.Handle;
end;
What I do then is include this unit in with a form unit, and then change the form's class (in the .pas code file) from class(TForm) to class(TModalForm)
It works for me, appears to be close to CodeGear's solution.
From this link it appears that the problem is with the "Ghosting window" that was introduced in 2000/XP. You can disable the ghosting feature by calling the following code at startup.
procedure DisableProcessWindowsGhosting;
var
DisableProcessWindowsGhostingProc: procedure;
begin
DisableProcessWindowsGhostingProc := GetProcAddress(
GetModuleHandle('user32.dll'),
'DisableProcessWindowsGhosting');
if Assigned(DisableProcessWindowsGhostingProc) then
DisableProcessWindowsGhostingProc;
end;
The only issue that I can see is that it will cause problems with the feature that allows for the user to minimize, move, or close the main window of an application that is not responding. But in this way you do not have to cover each call with the Self.Enabled := False code.
Just set the Visible property of the form, that you want to open modal, to False. Then you can open it with .ShowModal(); and it will work.
I have found that using the "Always On Top" flag on more than one form causes problems with the Z order. And you may also find the need for the BringWindowToTop function.
When launching a message box using the built-in WinAPI (MessageBox), I have found that passing the calling window's handle is necessary in order to make sure that the the prompt appears on top all the time.
try it
OnShowForm:
PostMessage(Self.Handle, WM_USER_SET_FOCUS_AT_START, 0, 0);
I'm writing a property editor for Delphi and I would like it to show up on the correct screen for multi-monitor support. In order to position it, I would like a reference to the "main" form for the Delphi IDE.
I've tried using the Application's MainForm property, and the Application object itself, but neither seems to work. I believe this is because the MainForm is actually the hidden TApplication instance referenced in this article by Nathanial Woolls (search for "application form"):
http://www.installationexcellence.com/articles/VistaWithDelphi/Original/Index.html
Does anyone know how to get a handle to the visible main form for the IDE. I'm trying to avoid something cheesy like iterating all forms and searching for "CodeGear RAD Studio" in the caption.
The IDE's main form is Application.MainForm. My quick test design package:
procedure DoStuff(Form: TCustomForm);
var
S: string;
begin
S := Form.Caption;
Form.Caption := S + ' - this one';
try
ShowMessage(Format('%s [%s] on monitor %d', [Form.Name, Form.ClassName, Form.Monitor.MonitorNum]));
finally
Form.Caption := S;
end;
end;
initialization
DoStuff(Application.MainForm);
This in my case displays "AppBuilder [TAppBuilder] on monitor 0" and I can see the " - this one" suffix in the main form's caption.
What doesn't seem to work in your case?
IIRC the main form is called TAppBuilder, so something like FindWindow('TAppBuilder',nil) might be a starting point for you.