I have a dialog (CDialog derived class) that can be used in two different ways (edition mode and programming mode).
When the dialog is open to be used in programming mode it is a modeless dialog that it is used for modifying the main view (kind of a toolbar). When it is open in edition mode the user can change the configuration of the dialog itself and in this case it is a modal dialog.
Right now they are two different dialogs with few differences and I would like to have just want dialog and let the user change between programming mode and edition mode just by pressing a button in the dialog.
So I need to convert the modeless dialog in a modal dialog and vice versa at runtime. Is there a way to achive that?
Thanks.
As maybe someone could be interested in doing something similar in the future, this is the way I eventually did it:
I use this two functions of main frame: CMainFrame::BeginModalState() and CMainFrame::EndModalState().
The problem with these functions is the same that with disabling the parent window. The window you want to make modal also gets disabled. But the solution is easy, just re-enable the window after calling BeginModalState.
void CMyDialog::MakeModal()
{
//disable all main window descendants
AfxGetMainWnd()->BeginModalState();
//re-enable this window
EnableWindow(TRUE);
}
void CMyDialog::MakeModeless()
{
//enable all main window descendants
AfxGetMainWnd()->EndModalState();
}
Thanks for your help.
That can't be done easily without closing and reopening the dialog. Then you can call ShowWindow or DoModal as appropriate.
That is not correct. This can be done, if you look at MFC's source you will realize that it's modal dialogs are not technically even modal. You will have to do a lot of mucking about to make this work properly, but basically you just have to disable the parent of the 'modal' window, and re-enable it when the 'modal' window closes.
I have done this personally so this may work for you, though I am not exactly sure what you are trying to do.
Related
I have the main window, and then the user can "pop up" one of the frames in the application so that it floats rather than being contained in the main window. There are multiple frames that can be popped up so that in a given time there might be three WS_POPUP windows.
The problem is when I want to show the modal dialog, I can only disable one of them using the parameter in the DoModal function. How can I disable all top-level windows using DoModal? I can't simply disable the windows before showing modal and then enable it back because There could multiple chained modal dialog (one modal dialog opens up another modal dialog).
Does the API provide a way to do something like this? I've googled this for two hours and can't find a good enough solution. I'm using a combination of MFC, WTL, and ATL.
Thanks in advance!
As I understand the problem, it is the same like the MFC frame windows work.
In fact only the CFrameWnd of an MFC application gets disabled. On arrival off the WM_ENABLE message (with FALSE) BeginModalState is called and this function just disables it floating "child windows" of the CFrameWnd.
Same again, when EnableWindow (WM_ENABLE arrives with TRUE) is called for CFrameWnd. EndModalState is called and all disabled "child and floating" windows are enabled again.
See the MFC implementation of CFrameWnd::OnEnable, BeginModalState, EndModalSTate in the source code.
So you main window knows it's own popups. Upon launching the true modal dialog, and disabling this parent, it will disable it's floating popups.
The trick is that CDialog::DoModal needs the real parent... if not given in the constructor it guesses the correct one in most cases. For your case it should be necessary that you provide your "main window" as the parent window... same for message boxes...
I have a modeless QDialog box that popup on errors/warning in my Qt application, I want to force the user to only focus on that dialog box and not click anything in the application until they clicked Ok on the dialog box.
I need the dialog box to remain modeless. A solution like hiding the main window or covering it up is not acceptable.
At the moment I'm using setModal(true); to solve my problem. But I think this method might be stopping the main application from executing.
From the documentation:
If you use show() and setModal(true) together to perform a long
operation, you must call QApplication::processEvents() periodically
during processing to enable the user to interact with the dialog.
Instead of using a QDialog box, try using qDebug statements in your code or a log file using qInstallMsgHandler.
You could also show a QTextEdit and post your log/error messages there in real time, too.
http://qt-project.org/doc/qt-4.8/debug.html
http://qt-project.org/doc/qt-4.8/qdebug.html#details
http://qt-project.org/doc/qt-4.8/qtglobal.html#qInstallMsgHandler
http://qt-project.org/doc/qt-4.8/qtextedit.html#details
If you still really want to debug using a QDialog box for errors, in a pseudo modal dialog but not modal dialog, you could try using eventFilters to prevent mouse and keyboard events from arriving at any other window, but it would be tricky to allow the exception to end up only at QDialog, but it is do-able.
You could also go to the one or two widgets that accept mouse and keyboard input, and ignore the input if the a QDialogBox is visible. But both of these ways of showing an error, but limiting input without making it Modal is really hacky, and would probably be error prone.
I have a strange error and spend hours in the debugger without finding a solution.
(But it helped me to fixed another error that you should never call EndDialog from a WM_KICKIDLE task).
My problem is that i have a main window and a modeless dialog window wich raises a modal subdialog window. When the subdialog window is closed. The modeless dialog window turns itself into a modal window. My code really does leave the modal loop. And if i close the now modal window it behaves like an invisble modal window is active, meaning no interaction is possible anymore.
When i only run a modal dialog on top of the main window it is closed fine.
BTW: The main window is not the one available view CWinApp::m_pMainWnd but a new create FrameWindow. I hide the p_MainWnd and use it as an invisible message only window. From some comments and my debugging session i found that the pMainWnd has some special meaning but i could figure what exactly it has to do with modal windows (there is an undocumented "CWinApp::DoEnableModeless" for example).
EDIT: I'm posting a WM_CLOSE to the dialog and then use EndDialog(0) from the OnClose() handler to exit the modal state. I also tried to use EndDialog(0) directly. There is no difference between this two methods.
When MFC creates a modal dialog, it makes it modal by disabling the windows above it. The code that reenables those windows occurs when the dialog ends normally with a call to EndDialog. If anything prevents that code from running, the other windows will be locked out.
Modeless dialogs are a different beast, and there's a note specifically in the EndDialog documentation warning you to use DestroyWindow instead.
Maybe this is justifiable but I have a question:
why are you using hidden window? Was it created as message only window (passing HWND_MESSAGE as a parent handle and Message as a class) or you just call it message only?
OK, a little more info about MFC and dialogs.
MFC does not use Windows modal dialog. It always creates modeless dialog; either Create or DoModal call in turn ::CreateDlgIndirect windows API.
Modeless dialof rely on the main window message dispatch, while modal calls RunModalLoop that is similar to MFC window message pupmp (not a message loop).
It runs in the main thread of execussion without freezing because it allows for idle processing (calls OnIdle).
How do you dismiss the modeless dialog? As Mark pointed you should use DestroyWindow.
As for m_pMainWnd, MFC framework uses it extensively to determine may things that control main window behavior. By changing it you may have created the behavior you experience.
Did you set the value to a newly created frame you treat as a main window?
What kind of MFC application is it? SDI or MDI?
Would it be possible to create test app to duplicate this behavior and post it somewhere for download?
By the way, you do not have to be concern about DoEnableModeless, since it does not do anything but calls hook (COleFrameHook type) that is spasly used, unless you are trying to implement some functionality using OLE or ActiveX or you are trying to marry MFC and .NET Windows Forms.
In conclusion if your (or third party code uses this hook, I would suggest checking the code in the COleFrameHook class.
I'm trying to set something up so my main dialog has one or more child dialogs, and these are glued/docked to the outside of the main dialog - when the main dialog is minimised, the children are too, when main dialog moves, children move with it.
I'd tried setting child dialogs as having main dialog CWnd as parent, with CHILD style. But then they get clipped by the parent's boundary. If I set them as POPUP, they can be outside but then don't move with the parent.
I'm looking at putting an OnMove handler on the parent dialog, but is there something built-in? And, should child dialogs still be children of the main dialog... I assume they should?
This is VS2005 (I think VS2008 has some related functionality so I mention this).
You need to implement the movement manually when they are popups, and yes they should be popups otherwise they will be clipped out.
I'm new to SO. Not sure if I can refer to an external article.
I guess this is what you are looking for.
I started to write this class because
I'm often in need to popup additional
dialogs around the main one. Often
these dialogs can give some trouble to
the user; for example, he must
move/close them one by one... A
solution that could give the
application a more solid aspect and
that could make the management of the
various windows easier could be, to
dock all dialogs side by side (like
Winamp does, for example).
As Roel says, your extra dialogs will need to be popups. I'm interested: what kind of UI is this? Is it WinAmp-style, where the windows snap to eachother?
Or are you doing some kind of expanding dialog? If it's an expanding dialog (with a More>> button on it, e.g.), then you can put all of the controls on the same dialog and play with the window rect when showing/hiding the extras.
How do I disable all the controls in a dialog window ? I know I could use
EnableWindow(FALSE);
but this doesnt seem like a good idea because now there is no way for the user to click "Ok" or "Cancel" button or press the "X" icon to exit. The dialog is like frozen.
What I am looking for is a way to disable all the controls in a dialog while providing some way for a user to exit.
Another solution is to do it manually by going through all the dialog controls and disabling them but this gets tedious. Any easy way ?
Thanks.
Sorry, but going through all of the controls and disabling each of them is the easy way.
You can write a general function to do this using EnumChildWindows or using a loop calling GetWindow(... GW_HWNDNEXT) until it returns NULL for the next window.
Just remember to skip disabling the window that has the IDCANCEL as the id.