Non-Modal File Dialog Class

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

Environment: Visual C++ 6

In response to a programming requirement, I went to CodeGuru for help with a non-modal FileDialog. I read the postings, generated some ideas, and developed a class I call CNonModalFileDialog.

In the simplest view, it is merely an instance of CFileDialog created in a CWinThread. Of course, nothing is ever as simple as you'd like.

The great benefit of a non-modal FileDialog is also it's greatest challenge. The program does not block waiting for the dialog to return, allowing users to continue to interact with the program even while the FileDialog is displayed; but, the program must handle the user's selections in the dialog. In the absence of a blocking call to CFileDialog::DoModal, how will you know whether the user pressed "OK" or "CANCEL", and how will you get the name of the file he selected?

My solution is to create a virtual class, CNonModalFileDialogParent. Any class wishing to make use of the CNonModalFileDialog must implement this Parent-class and pass itself to the CNonModalFileDialog instance. Then, when the user presses "OK" or "CANCEL" in the real CFileDialog, the CNonModalFileDialog informs the Parent of the action by invoking the parent's OnFileDialogOK or OnFileDialogCANCEL method and providing access to the CFileDialog instance in order to allow additional processing.

This text from the well-commented header file helps to fill in the blanks.

//################################################

#ifndef NON_MODAL_FILE_DIALOG_H
#define NON_MODAL_FILE_DIALOG_H

class CNonModalFileDialogParent
{
public:
 //---------------------------------------------------------
 // The class that creates a CNonModalFileDialog must
 // provide these functions in order to process
 // the CFileDialog's information.
 //
 // If a pointer to the CNonModalFileDialog is maintained
 // by the parent, it should be set to NULL in
 // these methods since the thread exits immediately
 // after invoking these methods.
 //
 // Maintaining a pointer to the CNonModalFileDialog is
 // not strictly necessary since the NonModalFileDialog
 // cleans up after itself. (Actually, the OS cleans
 // it up but that is not germaine, here.) However,
 // multiple instances will lead to multiple,
 // independent FileDialogs all sharing a single set of
 // Parent-implemented methods.
 //
 // The handler to display a NonModalFileDialog might
 // look like:
 //      if (_pFileDialog == NULL) {
 //         _pFileDialog = new CNonModalFileDialog (...);}
 //      else {
 //         _pFileDialog->Show ();
 //---------------------------------------------------------
 virtual void OnFileDialogOK (CFileDialog *dlg) = 0;
 virtual void OnFileDialogCANCEL (void) = 0;
};

class CNonModalFileDialog : public CWinThread
{
public:
//-----------------------------------------------
// Looks a lot like the CFileDialog constructor.
// Should probably be expanded to permit setting
// all of the OPENFILENAME structure's members.
//-----------------------------------------------
CNonModalFileDialog(
CNonModalFileDialogParent *myParent,
bool bMultiSelectable = false,
LPCSTR lpszPath = NULL,
bool bOpenFileDialog = true,
LPCSTR lpszDefExt = NULL,
LPCTSTR lpszFileName = NULL,
DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
LPCTSTR lpszFilter = NULL,
CWnd* pParentWnd = NULL);

//-------------------------------------------------------------------
// myParent:          The caller of this instance. Will process
//                    the eventual OK and CANCEL from the FileDialog.
// bMultiSelectable:  Will the FileDialog be able to select
//                    multiple files?
// lpszPath:          The directory to browse initially.
// bOpenFileDialog:   When true, the FileDialog is for opening files.
//                    When false, FileDialog operates as SaveAs.
// lpszDefExt:        In SaveAs mode, if user fails to append an
//                    extension, this one will be provided to him at
//                    no cost.
// lpszFileName:      The name to display in the File Name box.
//                    NULL leads to a blank field.
// dwFlags:           See the CFileDialog documentation for this.
// lpszFileter:       Again, this is best described in CFileDialog.
// pParentWnd:        The parent window for the FileDialog.
//-------------------------------------------------------------------
~CNonModalFileDialog ();

void Show (void);
virtual BOOL InitInstance();

private:
 bool        _multiSelectable;
 CString     _lpszPath;
 bool        _bOpenFileDialog;
 CString     _lpszDefExt;
 CString     _lpszFileName;
 DWORD       _dwFlags;
 CString     _lpszFilter;
 CWnd*       _pParentWnd;
 CFrameWnd   wind;
 static bool registeredDummy;
 CNonModalFileDialogParent *_myParent;
 CFileDialog               *_dlg;
};

#endif
//################################################
I have a driver dialog program. The main GUI class inherits from 'public CNonModalFileDialogParent'.

It declares a 'CNonModalFileDialog *_pFileDialog;' and initializes it to NULL. In a button's event handler, I have:

if (_pFileDialog == NULL)
{
 _pFileDialog = new CNonModalFileDialog (this, 
  false, 
  _path, 
  true,
  NULL, 
  _file, 
  OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
  szFilters);
}
else
{
 _pFileDialog->Show ();
 }
The implementations of the CNonModalFileDialogParent virtual functions are equally simple:
void CFileDialog_NonModalDlg::OnFileDialogOK (CFileDialog *dlg)
{
//---------------------------------
// Process the info from
// the CFileDialog
//---------------------------------

 //...

 _pFileDialog = NULL;
}

void CFileDialog_NonModalDlg::OnFileDialogCANCEL (void)
{
 _pFileDialog = NULL;
}

Downloads

Download demo project - 39 Kb
Download source - 3 Kb


Comments

  • Very good, but just work for CFileDialog. I modify for all CDialog.

    Posted by Legacy on 12/19/2002 12:00am

    Originally posted by: Manier Stephane

    I rewrite the class, now you can pass the adress of a modal CDialog, and it became out application modeless box. 
    
    CBox must be on Topmost windowspos.

    exemple
    // MainFrame.h
    //-------------------------------------------------

    // Class CBox: public CDialog

    class CMainFrame : public CMDIFrameWnd
    {
    ...
    protected:
    CNonModalCDialog *m_pModeless;
    CBox m_MyBox;
    ...
    };

    // MainFrame.cpp
    //-------------------------------------------------
    CMainFrame::CMainFrame()
    { m_pFileDialog = NULL;
    }

    CMainFrame::~CMainFrame()
    { if(m_pFileDialog)
    delete m_pFileDialog;
    }
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    ...
    m_pFileDialog = new CNonModalCDialog(&m_MyBox);
    m_pFileDialog->Hide();
    return 0;
    }
    void CMainFrame::OnEcranSwitch()
    {
    if (m_pFileDialog->IsVisible())
    m_pFileDialog->Hide();
    else
    m_pFileDialog->Show();
    }


    // NonModalCDialog.h
    //-------------------------------------------------
    #ifndef NON_MODAL_C_DIALOG_INCLUDE_H
    #define NON_MODAL_C_DIALOG_INCLUDE_H

    class CNonModalCDialog : public CWinThread
    {
    public:
    CNonModalCDialog(CDialog *pDlg); // The CDialog you want to Modeless

    ~CNonModalCDialog();

    void Show();
    void Hide();
    BOOL IsVisible();


    protected:
    virtual BOOL InitInstance();

    CDialog *m_pDlg; // ptr CDialog

    };//CNonModalCDialog
    #endif//NON_MODAL_C_DIALOG_INCLUDE_H

    // NonModalCDialog.cpp
    //-------------------------------------------------
    #include "StdAfx.h"
    #include "NonModalCDialog.h"

    CNonModalCDialog::CNonModalCDialog(CDialog *pDlg)
    {
    m_pDlg = pDlg;
    CreateThread ();
    }
    CNonModalCDialog::~CNonModalCDialog ()
    {
    m_pDlg->ShowWindow(SW_HIDE);
    m_pDlg->DestroyWindow();
    m_pMainWnd = NULL;
    }
    BOOL CNonModalCDialog::InitInstance()
    {
    m_pMainWnd = m_pDlg;
    m_pDlg->DoModal();
    return TRUE;
    }
    void CNonModalCDialog::Show()
    { if (!m_pDlg->IsWindowVisible())
    m_pDlg->ShowWindow(SW_SHOW);
    }
    void CNonModalCDialog::Hide()
    { if (m_pDlg->IsWindowVisible())
    m_pDlg->ShowWindow(SW_HIDE);
    }
    BOOL CNonModalCDialog::IsVisible()
    { return m_pDlg->IsWindowVisible();
    }

    Reply
  • Dialog_base

    Posted by Legacy on 07/17/2002 12:00am

    Originally posted by: Liu

    Hi,everyone

    I find it works well for Dialog_base apllication. However,
    I find that the thread cannot be terminated when I close the child dialog by pressing the CANCEL button. Could anyone tell me why?

    Thanks in advance.

    Liu

    Reply
  • I like it

    Posted by Legacy on 06/14/2001 12:00am

    Originally posted by: Jim Rong

    I like it

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date