SHARE
Facebook X Pinterest WhatsApp

DevStudio-like Properties Dialog

Environment: VC6 SP3, NT4 SP5 These are the steps to follow to create a dialog resembling the DevStudio Properties dialog: clicking outside the dialog induces dialog closing, unless the Keep Visible button was previously pressed. Include the NewButton.h and NewButton.cpp files in your project Create a dialog with a button with Owner Draw style Define […]

Written By
thumbnail
CodeGuru Staff
CodeGuru Staff
Dec 29, 1999
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Environment: VC6 SP3, NT4 SP5

These are the steps to follow to create a dialog resembling the DevStudio Properties dialog: clicking outside the dialog induces dialog closing, unless the Keep Visible button was previously pressed.

  1. Include the NewButton.h and NewButton.cpp files in your project
  2. Create a dialog with a button with Owner Draw style
  3. Define the class that manage the dialog (must derive from CDialog or any other class that derive from CDialog), in the example CDlg
  4. Add a member variable for the button, must be of CNewButton class; if the Class Wizard doesn’t permit to choose that variable’s type, you could choose the CButton class and then modify it in the .h file of the CDlg class (in the example Dlg.h); remember to insert the line

    #include "NewButton.h"

    before the class definition:

    // Dialog Data
    //{{AFX_DATA(CDlg)

    enum { IDD = IDD_PROPERTIES };
    CNewButton m_KeepVisible;

    //}}AFX_DATA

  5. Modify CDlg constructor removing the default value of the pParent parameter; it is essential for the dialog to know its father:
    • in the .h file

      CDlg(CWnd* pParent);

    • in the .CPP file

      CDlg::CDlg(CWnd* pParent) : CDialog(CDlg::IDD, pParent), m_pParent( pParent )
      {

      //{{AFX_DATA_INIT(CDlg)
      //}}AFX_DATA_INIT

      }

  6. Define in Dlg.h public section the function:

    BOOL Create(); // Creation of mode-less dialog

  7. Define in Dlg.h protected section the following member variables:

    CWnd* m_pParent; // Parent of the dialog
    CToolTipCtrl m_toolTip; // Tooltip management
    static WNDPROC m_MFCWndProc; // Pointer to the default MFC window procedure
    static CDlg* m_pDialog; // Pointer to the active instance of the dialog (this variable is correct if we do the hypothesis that only one instance of CDlg could be active at once; otherwise is necessary to define a map which related a HWND with a CDlg*)

    and the function:

    static LRESULT CALLBACK NewWndProc( HWND, UINT, WPARAM, LPARAM );
    // New window procedure of the dialog

  8. With Class Wizard re-define WM_INITDIALOG, WM_CLOSE and PreTraslateMessage(), and define the button click message function; in the example:

    OnKeepVisible()

  9. Define the UserMessage to be used by the dialog to communicate with its father:

    #define WM_CLOSEDLG WM_USER+5

  10. In the .CPP file define the static variables:

    WNDPROC CDlg::m_MFCWndProc = 0;
    CDlg* CDlg::m_pDialog = NULL;

    and insert the following implementation of the previously declared functions and message handlers:

    BOOL CDlg::OnInitDialog()
    {
      CDialog::OnInitDialog();
     
      
    // Creation and init of tooltip for the Keep Visible button
      
    m_toolTip.Create( this, TTS_ALWAYSTIP );
      m_toolTip.Activate( TRUE );
      m_toolTip.AddTool( GetDlgItem( IDC_KEEP_VISIBLE ), "Keep Visible" );
     
      
    // Init of the Keep Visible button: set the parent of the button (dialog
      // that contains it) and the bitmaps which shows when the button is
      // pressed/released and the mouse is over/non-over
      
    UINT nBitmapIDs[] = { IDB_VISIBLEU, IDB_VISIBLED,
       IDB_VISIBLEU_OVER, IDB_VISIBLED_OVER };
      m_KeepVisible.SetParent( this, nBitmapIDs );
     
      
    // Change of the default window procedure
      
    WNDPROC temp = reinterpret_cast(::SetWindowLong(
       GetSafeHwnd(), GWL_WNDPROC, reinterpret_cast(NewWndProc) ));
      if ( !m_MFCWndProc ) m_MFCWndProc = temp;
      m_pDialog = this;
     
      return TRUE;
    // return TRUE unless you set the focus to a control
       // EXCEPTION: OCX Property Pages should return FALSE
    }
     
    BOOL CDlg::Create()
    {
      return CDialog::Create( CDlg::IDD );
    }
     
    void CDlg::OnKeepVisible()
    {
      CPoint point;
      ::GetCursorPos( &point );
      CRect rect;
      m_KeepVisible.GetWindowRect( &rect );
      
    // Check that the mouse is over the button
      
    if ( rect.PtInRect( point ) )
      {
        
    // Change the button state
        
    m_KeepVisible.SetMode();
        
    // The SetState function must be called two times
        
    m_KeepVisible.SetState( m_KeepVisible.GetMode() );
        m_KeepVisible.SetState( m_KeepVisible.GetMode() );
      }
    }
     
    LRESULT CALLBACK CDlg::NewWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
      
    // The new window procedure manages only the dialog inactivate;
      // the other msgs are managed by default window procedure
      
    if ( message == WM_ACTIVATE )
      {
        if ( wParam == 0 )
        {
          if ( !m_pDialog->m_KeepVisible.GetMode() )
            m_pDialog->m_pParent->PostMessage( WM_CLOSEDLG );
          return FALSE;
        }

      }
      return ::CallWindowProc( m_MFCWndProc, hWnd, message, wParam, lParam );
    }
     
    void CDlg::OnClose()
    {
      // Parent notify
      
    m_pDialog->m_pParent->PostMessage( WM_CLOSEDLG );
     
      CDialog::OnClose();
    }
     
    BOOL CDlg::PreTranslateMessage(MSG* pMsg)
    {
      
    // Different management of the WM_KEYDOWN msg when is pressed the ENTER button
      // (the default management closes the dialog) or the ESC (we want to close the
      // dialog)
      
    if ( pMsg->message == WM_KEYDOWN )
        switch ( (int)pMsg->wParam )
        {
          case VK_RETURN:
            if ( m_KeepVisible.GetMode() )
              return true;
            break;
          case VK_ESCAPE:
            m_pDialog->m_pParent->PostMessage( WM_CLOSEDLG );
            return true;
        }
     
      
    // Tooltip management
      
    m_toolTip.RelayEvent( pMsg );
     
      return CDialog::PreTranslateMessage(pMsg);
    }

  11. At this time we need to manage the dialog from its father (in the example the father is the MainFrame), in particular the closing message; so in the .h file we need to insert the definition of the message handler:

    // Generated message map functions
    protected:
    //{{AFX_MSG(CMainFrame)
    ...
    //}}AFX_MSG
    afx_msg LRESULT OnCloseDlg( WPARAM wParam, LPARAM lParam );
    DECLARE_MESSAGE_MAP()

    while in the .CPP file the message map:

    BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
    //{{AFX_MSG_MAP(CMainFrame)
    ...
    //}}AFX_MSG_MAP
    ON_MESSAGE( WM_CLOSEDLG, OnCloseDlg )
    END_MESSAGE_MAP()

    and the function implementation:

    LRESULT CMainFrame::OnCloseDlg( WPARAM wParam, LPARAM lParam )
    {
      if ( m_pDlg )
      {
         m_pDlg->DestroyWindow();
         delete m_pDlg;
         m_pDlg = NULL;
      }
     
      return 0L;
    }

    where m_pDlg is a pointer to the dialog active instance.

To correctly use this source it’s necessary define, in the MainFrame or where you want manage the dialog, a member variable which points to the dialog active instance:

CDlg* m_pDlg;

furthermore, in the code, where you want create the dialog, insert the next lines:

// If the dialog already exists set the focus to it, otherwise create the dialog and show it
if ( m_pDlg )
  m_pDlg->SetFocus();
else
{
  m_pDlg = new CDlg( this );
  m_pDlg->Create();
  m_pDlg->ShowWindow( TRUE );
}

Don’t forget to initialize the pointer in the constructor:

m_pDlg = NULL;

and verify, in the destructor, that there isn’t active instance:

if ( m_pDlg )
{
  m_pDlg->DestroyWindow();
  delete m_pDlg;
}

Thanks to Matteo Benzoni and Diego Perrotta

Downloads

Download demo project – 35 Kb
Download source – 5 Kb

Recommended for you...

How To Make Windows 11 Faster
Enrique Stone
Nov 30, 2022
Working with the Windows Registry in C#
Joydip Kanjilal
Jun 17, 2022
Using Multiple Programming Languages to Create an ASP.NET Website
Tariq Siddiqui
Jun 11, 2022
Finding a Microsoft Office version with .NET
Hannes DuPreez
May 20, 2022
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.