While adding a secondary window (TForm) to a project written with Embarcadero C++Builder 10.4, I have the problem where that secondary window is always in front of the main one. That is, when clicking on the primary window, the secondary window loses focus but remains on top of the primary window.
I have tried changing the BorderStyle property, the PopupMode property, and I even tried to call the secondary window's SendToBack() method when the primary window activates. Nothing changes.
The secondary window is created with a NULL owner, and it is shown through it's Show() method.
The question is simple: How can I make the active window (TForm) on top of the other windows (TForm)?
(Primary TForm should not be behind secondary TForm when primary is active.)
This is expected behavior.
With Application->MainFormOnTaskBar set to true, when the secondary TForm is creating its window, and that Form's FormStyle is fsNormal, and the Form is not being shown modal, then its PopupMode is ignored and its owner window (in Win32 API terms, not VCL terms) gets set to the Application->MainForm window.
When a window has an owner window assigned, it can't ever go behind its owner.
To do what you are asking for (without switching to an MDI design), you need to instead have the hidden TApplication window be the owner of your secondary window, then you will be able to freely switch between your two windows. To accomplish that, you can either:
set Application->MainFormOnTaskBar to false (not advisable on Vista+ systems, as it will also disable a lot of other VCL behaviors that are needed for proper Vista+ interactions)
use the TApplication::OnGetMainFormHandle event to provide the desired owner window, in this case Application->Handle
have the secondary TForm class override the virtual CreateParams() method and set Params.WndParent to Application->Handle.
Related
I'm working with common dialog recently and I've found that a hWndOwner is required in the structure that passed to functions like ChooseColor.
It seems of no difference when I used different hWndOwner. What does different hWndOwner choosing affects? Are there anything to take care when choosing the owner window?
Thanks for all who commented! Below are the key ideas I've got from the document.
There are a few things that relates to ownership, as taken from the document:
An owned window is always above its owner in the z-order.
The system automatically destroys an owned window when its owner is destroyed.
An owned window is hidden when its owner is minimized.
Setting owner to a child window (a window that is not a overlapped window or popup window) is equivalent to setting it to the top-level parent window.
The ownership could not be transferred after the window is created.
That's what I've learnt by reading the document. It would be much better if someone can give some extra information that is not included in the document.
Using the MFC, I have multiple derived classes
class CImageView : public CFormView
{
};
and open 3 windows all with the same dialog ID.
Is that valid and they wont interfere with each other?
I know it is not valid to have the same dialog ID for child windows within the dialog.
Thanks
Yes, this is perfectly fine. It's just the resource id identifying the dialog resource to use to create the window. The resulting view windows are actually created with different/unique window handle (HWND) values. The reason child controls should not have duplicate ID's is because it would confuse API's like GetDlgItem, which are used to retrieve a specific control's HWND based on the ID specified.
Sincerely,
Only child windows have control ID's. Pop-up windows do not have a control ID; the API has no way of setting one. If you look at the documentation for CreateWindowEx, you'll see that the hMenu argument is overloaded. It's used to set a control ID only when creating a child window.
The dialog ID you are referring to really is the identifier used to look up a DIALOGEX resource in the executable image's resource section. Once the dialog is created, that ID is gone. Using multiple dialogs created from the same dialog template is safe, and multiple instances will not interfere with each other.
I have a modeless popup dialog in my app. I want to make it topmost only within the app it belongs to, not always topmost on the desktop.
I have tried to set the first parameter to wndTopMost, but this way the dialog will remain on top on the desktop, which is very bad user experience.
I have also tried wndNoTopMost with SWP_NOZORDER parameter, but this only put the dialog in front when its displayed. If I move another dialog/window to the dialog location, the dialog will be buried under the new dialog/window.
I am currently using the SetWindowPos in the OnInitDialog();
SetWindowPos(&wndNoTopMost
, myRect.left
, myRect.top
, myRect.Width()
, myRect.Height()
, SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOZORDER
);
Yes HWND_TOPMOST is a very bad user experience, so I will commend you for not taking the easy way out and trying to flip this switch.
The key to getting a dialog to appear on top of other windows is setting its owner. (Note that in Win32, an owner is distinct from a parent window, although the terms are often confusing.) All dialogs have an owner, and dialogs always stay on top of their owner.
So when you create the modeless dialog (e.g. using the CreateDialog function), make sure to specify the handle to your application's main window as its owner. Confusingly, the parameter is named hwndParent, but it actually specifies the owner window.
i can't understand what's the benefit of setting parent for a QMessageBox, for instance in the following code:
void mainWindow::showMessage(QString msg) {
QMesageBox::information(this, "title", msg); //'this' is parent
}
can somebody help me ?
Probably a few things. First of all QMessageBox inherits from QDialog. Since QDialog has a concept of a parent, QMessageBox should too for consistency.
Specifically, the documentation says:
parent is passed to the QDialog constructor.
At the very least, a new dialog is often displayed centered in top of its parent.
However, there is more!
According to the documentation it can effect actually functionality. For example:
On Mac OS X, if you want your message box to appear as a Qt::Sheet of
its parent, set the message box's window modality to Qt::WindowModal
or use open(). Otherwise, the message box will be a standard dialog.
Also, there is a concept of both "Window Modality" and "Application Modality", where the former only prevents input in the parent window, the latter prevents input for the whole application. This obviously requires the concept of a parent to be known.
Finally, for certain static functions such as ::about(...), the first place it looks for an icon to use is parent->icon().
So, if you want to get nice platform specific behavior and have your code be cross platform, you are better off passing a sane parent to it.
The parent-child hierarchy of dialogs defines the window stacking behavior in the various platforms. If you pass dialog P as parent of dialog C, C will appear above P on all (desktop) platforms. If you pass 0, the window stacking will differ and usually not behave as wanted. The worst such issues I've seen on OS X, where some message boxes showed up behind the main window, which was disabled as the message boxes being modal, without any way to get to the message box (neither shortcuts nor moving windows via mouse helped).
In short, my suggestion: always pass a sensible parent.
The other answers are probably better, but my own little reason is that it puts the message box at the centre of the parent instead of the centre of the screen...
Don't forget to mention that QMessageBox will inherit of the palette and the style-sheets of its parent. Believe me when you use custom complex style-sheets you don't want you message to pop like they doesn't belong to your application ...
It is also useful for memory management if you don't use static functions, but actually create an instance of QMessageBox. When the parent is deleted your instance will be deleted too.
HWND button = CreateWindowEx(0, "BUTTON", ...);
SetFocus(button); // Button no get focus! :(
Also, I have other controls on my form that I am able to SetFocus() to.
Thanks, Martin
It has been FOREVER since I've had to do this, but...
Were this a dialog, I would tell you to send a WM_NEXTDLGCTL via PostMessage(). The default dialog item message handler would take care of the rest for you setting keyboard focus and selection activation. However, this is a different case if I read this correctly. You're creating both parent and child windows raw on the fly. If this is the case, SetFocus() to the parent window, and handle WM_SETFOCUS on the parent window by bringing it to top, then setting focus on the child window. WM_SETFOCUS, and WM_KILLFOCUS were designed to allow you to switch the 'activated' state of your controls, and most handle it for you (unless your window is an owner draw control or some such). But in a raw window, when your base parent window is sent the focus, you need to appropriately ensure the proper child has it if you're hosting any (think of it as managing your own 'dialog'). Again, normally this is done by the default dialog procedure for you if this were a dialog, but being raw windows you're kind of stuck managing it all yourself.
Though I can't imagine how, I hope that helped somewhat.
SetFocus is a function, not a procedure. Call it as a function and check its returned value. Either the retuned value is null because you made an error in the CreateWindowEx() call and "button" isn't a valid handle or it's a window not associated with your thread's message queue, or the return value is not null (it's now the prior focused window's handle) and you do have the focus (but are somehow failing to detect it).
Try setting the WS_TABSTOP style on the button.
If you create that button in respond of the WM_INITDIALOG message you should return FALSE to prevent dialog box procedure to change the focus.