Need Compromise: wxMenu - wxFrame - wxDialog & Modality Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply

If you had to choose, which would you prefer?

Allow the unconventional, wxMenu on wxDialog
1
14%
Allow a compromise: make wxFrame have all Modal functions and properties.
3
43%
Allow a compromise: create a new wxModalWindow class to clean it up.
2
29%
Do NOTHING. It is perfect and need not be addressed.
1
14%
 
Total votes: 7

jmason1182
Earned some good credits
Earned some good credits
Posts: 149
Joined: Fri Dec 14, 2007 3:40 pm
Location: Midland, TX
Contact:

Need Compromise: wxMenu - wxFrame - wxDialog & Modality

Post by jmason1182 »

This is the third project I've worked on that required extensive use of complex windows. By that I mean you have a very complex data structure. In order to show it, you must allow for a subset of data to be viewed in the first window. From there, you can select where to go and open a new window containing a different subset of different data. BUT all the windows you open require lots of tools to be available to use on the viewed data. AND because of the data's structure, you need to require the editing/opening of ONE set of windows at a time... you need a Modal Dialog.

THUS, you end up with a whole lot of wxFrames, each with a menu bar, but no conventional way to make it modal and be able to check if it is modal, etc. Thus, you decide to go with wxDialog since it has the functions IsModal, ShowModal, EndModal, etc. BUT now you can't have a menu!

So what are we to do? Completely rewrite something? No. We need a way to have a MODAL FRAME. Or better, just look at something LIKE a wxDialog but perhaps call it wxModalWindow. Maybe a simple restructure, transparent to user's code, of wxDialog could be a derivative of wxFrame and wxModalWindow.

We all know that the purpose of a dialog is simple... ask a question or something simple to fill out or display, and click a button and it sends it back. But, many times we have complex info to display and we don't want to lose the modal properties... so we have to fight with wxFrames....

I think a compromise would be good here.
wxFrame = wonderful. Complete. I don't think anything should be changed.
wxDialog = wonderful. Somewhat complete.

proposed wxModalWindow = could allow wxDialog to be derived and thus have better control with limiting the purpose of a dialog. PLUS then we could achieve a wxFrame that could be a modal window by simply inheriting wxFrame and wxModalWindow together. The wxDialog would still restrict menu use etc, but Viola... the programmer would then be in control of sticking to conventions or not.

Any thoughts/ suggestions are encouraged... flaming is not. :) Afterall, we can all agree that wxWidgets rocks! (ok... maybe of us can agree)
John A. Mason
Midland, TX
Frank
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Jan 01, 2005 6:19 pm

Post by Frank »

I don't even understand why there is wxFrame and wxDialog.

Just make a wxFrame::ShowModal and wxFrame::EndModal() and nobody needs wxDialog anymore.

That is what the OCL did, the Framework I used before wx. That was the only problem when porting our app to wx. We have one modal window in our application wich needs menus. We had to do a really nasty hack to get this window done.
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria »

While this discussion might be interesting, it would be much more suited to the mailing list, where you can reach the actual developers of wxWidgets.
jmason1182
Earned some good credits
Earned some good credits
Posts: 149
Joined: Fri Dec 14, 2007 3:40 pm
Location: Midland, TX
Contact:

Post by jmason1182 »

So you are saying that you want me to join the mailing list which I would only use for this one topic.....

I like the forum. Plus, I am intending on using this poll... if more people answer it.

And check my next post... you'll see why it is on the forum... sharing code.
Last edited by jmason1182 on Wed Aug 27, 2008 2:07 pm, edited 1 time in total.
John A. Mason
Midland, TX
jmason1182
Earned some good credits
Earned some good credits
Posts: 149
Joined: Fri Dec 14, 2007 3:40 pm
Location: Midland, TX
Contact:

Post by jmason1182 »

Frank wrote:We had to do a really nasty hack to get this window done.
So what hack did you do? I am needing something to get the job done and am needing a hack to put a menu on a wxDialog.

EDIT: I went ahead and created a wxModalWindow class. It inherits from wxFrame... so menus and other behaviors mimic a wxFrame. BUT, it behaves like a wxDialog when it comes to modal status. I even added the eventloop and windowDisabler just like wxDialog does. So technically it is a simplified wxDialog (without restrictions.) As far as I know it handles native controls/windows the same as wxFrame... but I haven't tested it beyond my needs. Feel free to add/change/delete to fix any bugs that I didn't test.

wx\modalwindow.h

Code: Select all


/**********************************************************************************************
 *
 * Filename  : modalwindow.h
 * Purpose   : Allow a modalwindow like wxDialog but allowing menus and such.
 * Author    : John A. Mason
 * Created   : 8/27/2008 07:54:12 AM
 * Copyright : Released under wxWidgets original license.
 *
 **********************************************************************************************/

#ifndef __wx_ModalWindow_h__
#define __wx_ModalWindow_h__

#include <wx/wxprec.h>

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#include <wx/frame.h>

#ifndef WX_PRECOMP
    #include <wx/utils.h>
    #include <wx/app.h>
#endif

#include <wx/evtloop.h>

class wxModalWindow : public wxFrame {
	private:
			// while we are showing a modal window we disable the other windows using
			// this object
			wxWindowDisabler *m_windowDisabler;

			// modal window runs its own event loop
			wxEventLoop *m_eventLoop;

			// is modal right now?
			bool m_isShowingModal;

			//The return code of a modal window
			int m_returnCode;
	public:
			wxModalWindow();
			wxModalWindow(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE, const wxString& name = "modalwindow");
			virtual ~wxModalWindow();


			void Init();
			bool Show(bool show);
			bool IsModal() const;
			int ShowModal();

			void EndModal(int retCode);
			void SetReturnCode(int retCode);
			int GetReturnCode() const;
};

#endif





wx\modalwindow.cpp

Code: Select all


/**********************************************************************************************
 *
 * Filename  : modalwindow.cpp
 * Purpose   : Allow a modalwindow like wxDialog but allowing menus and such.
 * Author    : John A. Mason
 * Created   : 8/27/2008 07:54:12 AM
 * Copyright : Released under wxWidgets original license.
 *
 **********************************************************************************************/

#include "modalwindow.h"

wxModalWindow::wxModalWindow()
: wxFrame() {
	Init();
}

wxModalWindow::wxModalWindow(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
: wxFrame(parent, id, title, pos, size, style, name) {
	Init();
}


wxModalWindow::~wxModalWindow() {
	delete m_eventLoop;
}


void wxModalWindow::Init()
{
    m_returnCode = 0;
    m_windowDisabler = NULL;
    m_eventLoop = NULL;
    m_isShowingModal = false;
}

bool wxModalWindow::Show(bool show)
{
    if ( !show )
    {
        // if we had disabled other app windows, reenable them back now because
        // if they stay disabled Windows will activate another window (one
        // which is enabled, anyhow) and we will lose activation
        if ( m_windowDisabler )
        {
            delete m_windowDisabler;
            m_windowDisabler = NULL;
        }

        if ( IsModal() )
            EndModal(wxID_CANCEL);
    }

    bool ret = wxFrame::Show(show);

	//I don't think we need this. Since it is a wxFrame that we are extending,
	// we don't need wxEVT_INIT_DIALOG firing off - that's what InitDialog does...
	// and this would only make sense if we have a wxDialog and validators
//    if ( show )
        //InitDialog();

    return ret;
}

bool wxModalWindow::IsModal() const {
	return m_isShowingModal;
}

int wxModalWindow::ShowModal() {
  if ( IsModal() )
    {
       wxFAIL_MSG( wxT("wxModalWindow:ShowModal called twice") );
       return GetReturnCode();
    }

    // use the apps top level window as parent if none given unless explicitly
    // forbidden
    if ( !GetParent() )
    {
        wxWindow *parent = wxTheApp->GetTopWindow();
        if ( parent && parent != this )
        {
            m_parent = parent;
        }
    }

    Show(true);

    m_isShowingModal = true;

    wxASSERT_MSG( !m_windowDisabler, _T("disabling windows twice?") );

#if defined(__WXGTK__) || defined(__WXMGL__)
    wxBusyCursorSuspender suspender;
    // FIXME (FIXME_MGL) - make sure busy cursor disappears under MSW too
#endif

    m_windowDisabler = new wxWindowDisabler(this);
    if ( !m_eventLoop )
        m_eventLoop = new wxEventLoop;

    m_eventLoop->Run();

    return GetReturnCode();
}



void wxModalWindow::EndModal(int retCode) {
    wxASSERT_MSG( m_eventLoop, _T("wxModalWindow is not modal") );

    SetReturnCode(retCode);

    if ( !IsModal() )
    {
        wxFAIL_MSG( wxT("wxModalWindow:EndModal called twice") );
        return;
    }

    m_isShowingModal = false;

    m_eventLoop->Exit();

    Show(false);
}


void wxModalWindow::SetReturnCode(int retCode) {
	m_returnCode=retCode;
}


int wxModalWindow::GetReturnCode() const {
	return m_returnCode;
}







Usage: Use it like a wxFrame... ie:

Code: Select all


class UnitDisplay : public wxModalWindow {
...

and 

...
UnitDisplay::UnitDisplay(wxWindow* parent)
: wxModalWindow(parent,wxID_ANY,wxT("Title"),wxDefaultPosition,wxDefaultSize,wxFRAME_NO_TASKBAR | wxFRAME_OTHER_OPTIONS...) {
...

Hope this helps somebody.
John A. Mason
Midland, TX
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria »

jmason1182 wrote:So you are saying that you want me to join the mailing list which I would only use for this one topic.....

I like the forum. Plus, I am intending on using this poll... if more people answer it.

And check my next post... you'll see why it is on the forum... sharing code.
well, it's not me you need to convince, it's the wx devs ;) Most of them prefer using the mailing list, therefore while you are free to discuss whatever you wish here, you should not be surprised if this thread does not have much concrete results (except of course the nice contributed class ;) )
Frank
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Jan 01, 2005 6:19 pm

Post by Frank »

Thanks John, that looks really good. I'll try it tommorrow at work with our window.

I don't remember what our hack was, it's been some time. The only thing I remember was all the swearing... But it dit not had an own message loop. If I remember right, it had an endless loop wich called wxYield() every 25 millisecons or something.
jmason1182
Earned some good credits
Earned some good credits
Posts: 149
Joined: Fri Dec 14, 2007 3:40 pm
Location: Midland, TX
Contact:

Post by jmason1182 »

Well... it's official... for my purposes at least, the class I wrote works like a dream.

Somebody let me know if there are any issues you encounter with it.

Oh, and thanks to Frank and Auria for responding. Luckily I really enjoy doing this sort of thing (as most programmers should) so it was actually a "frustrated fun"! 8)
John A. Mason
Midland, TX
User avatar
tierra
Site Admin
Site Admin
Posts: 1355
Joined: Sun Aug 29, 2004 7:14 pm
Location: Salt Lake City, Utah, USA
Contact:

Post by tierra »

Is there something wrong with using wxWindow::MakeModal()?

Regardless, from my perspective of user interface design, it's just generally bad design to have an application with multiple menus (on multiple frames), especially if one of those menus isn't accessible because another frame with a different menu is modal. Multiple toolbars (on different frames) makes more sense, but I generally avoid doing that too.

If you have a modal window anywhere in your application, it shouldn't be one that accounts for a majority of the work and time a user spends in the application - locked in a modal window.

P.S. Consider yourself lucky if this hack works on Mac. Apple discourages developers from ever using modal windows anywhere in your application. They do allow it of course, but they would prefer that none of your application ever uses a modal window.
Frank
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Jan 01, 2005 6:19 pm

Post by Frank »

MakeModal() has no message loop. It returns imediateley.

And sorry, but I'm not interested in your's or appels point of view on GUI design. All I'm interested in is what my users want.
jmason1182
Earned some good credits
Earned some good credits
Posts: 149
Joined: Fri Dec 14, 2007 3:40 pm
Location: Midland, TX
Contact:

Post by jmason1182 »

That's the reason why developers should always be in control of the code that they are developing.

See the applications that I am dealing with lately are invoicing and inventory applications. While it would be completely possible to just make frames over and over again to show the various different parts to the application and data model, most of the data model relies on other parts of the data model.

That is why I need a modal window.... Until a user completes changes/additions/etc. to one part of the data model, no control can be released to the remainder of the application. That is the point of a modal dialog... ask a question or display a simple form and due to the nature of the data - don't release the control to another window since that window will rely on the data given.

Where it gets complicated to me is the required data model for the project. We can always argue that a true software engineering technique could be applied to clean up the model so it doesn't have restrictions.... but then the customer can't get what they want. This particular data model is complex enough to require multiple parts of data from different data sets to be accessible in a particular window. Not to mention the user's expectation that you should have an edit menu (Ctrl-C and CTRL-v are not as widely known as we wish... many users still click Edit-Copy, etc.). Couple that with a help menu for each window so that contextual is available... then you have a real reason to add a menu to even your modal windows.

As a quick example to why I need this sort of functionality:

An invoice is made up of line-items (products), a customer, a shipping address, as well as some other details. The customer itself is made up of a name, an address, some contact information, some account information, etc.
So if a user wants to write an invoice, they have to start by adding products, etc. Then, let's say that have to add a new customer for this invoice. They go to Cards->New Customer which opens up a window. If this window wasn't modal, then the invoice could be modified, a customer be assigned to the invoice, even print the invoice without the new customer being completed. That is not the design we wish to implement. So we make it modal.
Then you look at the type of data needed to specify a customer. Much of it is looked up from the database... ie account information, contact info, even address listings. So instead of having tons of buttons to load and lookup a detail, we have a menu for that. Not to mention the "Help" menu for user friendly assistance, but also the edit menu, as well as a file menu so the customer details can be printed, saved to a file, etc. all from the customer detail window.

I agree with Frank. I don't care if you like the use of a modal window with a menu. There ARE times when it is necessary. Many people would never create a straight wxWindow... they would use either wxFrame or wxDialog, but that doesn't mean there isn't a case where a straight wxWindow is needed.

Leave the developers in control of their application. They are responsible for the application.... In my opinion, the framework is supposed to be an enabler.
John A. Mason
Midland, TX
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria »

You're talking to wx users here. This rant will have absolutely no impact on anyone.
jmason1182
Earned some good credits
Earned some good credits
Posts: 149
Joined: Fri Dec 14, 2007 3:40 pm
Location: Midland, TX
Contact:

Post by jmason1182 »

Okay then I'll summarize as to how it is relevant:

Forcing developers to conform to some ideal because the wxWidgets doesn't allow something simple, like the modal window with menus here, means that the developer isn't in full control of the wxWidgets application he/she is developing. There ARE reasons for a developer to need this sort of control. That is the purpose of this thread.

If nobody agrees with me, then fine. I'll just use my class and anyone else who finds it useful for their purposes can do the same. My goal was not to rant. My goal was simply to illustrate an example for this particular situation where a Modal window with a menu was needed.

P.S. And this is the wxWidgets forum... and I have posted wxWidgets code as well as discussing a "feature" (for lack of better word) that is missing in the wxWidgets API. Seems appropriate to me.
John A. Mason
Midland, TX
whachmann
In need of some credit
In need of some credit
Posts: 1
Joined: Thu May 09, 2013 2:28 pm

Re: Need Compromise: wxMenu - wxFrame - wxDialog & Modality

Post by whachmann »

John Mason,
You gave a very good contribution to wx users. Now I'm having exactly the same problem trying to do a modal wxFrame. I'll use your new class. I was using Borland C++ builder 2006 before, with modal forms, and now I'm porting all to wxWidgets.
Congratulations!
Post Reply