Click here to Skip to main content
15,881,089 members
Articles / Containers / Docker
Article

Creating the General ProfUIS Dialog and ProfUIS MessageBox

Rate me:
Please Sign up or sign in to vote.
4.90/5 (16 votes)
19 Jun 20073 min read 77.2K   771   32   20
Creating the General ProfUIS Dialog and ProfUIS MessageBox

Introduction

This article concerns those MFC programmers who use the ProfUIS library in their projects; also, it contains some general tips on how to use custom UI libraries. I think most programmers who use custom UI control classes in their dialogs don't like the simple way to do it - create new member of the desired control class and do something like DDX_Control(). The more dialogs you have in your program - the more you become bothered by this "simple way". So, I solved this problem, and now I can give a simple and "right" way to make it work. In addition, I will give two interesting tips on how to replace the standard MessageBox and standard Print Preview bar with skinned ones.

Background

If you want to check this sample in real work, I recommend you install the free version of the professional user interface solutions by FOSS software by simply downloading it from the company site: http://www.prof-uis.com/download.aspx.

So let's start.

General concept

The article will give an example of three classes and some hints on the external code. The main classes are: CGeneralSubclassersContainer, CProfUISDialog, and CProuisDialogBar.

The general concept is to dynamically create and subclass all usual skinned controls. Since I used not only the dialogs to deal with, but also the dialog bars, I created the standalone class to manipulate all dynamic controls - the CGeneralSubclassersContainer class. The CProfUISDialog replaces the standard CDialog class, and the CProuisDialogBar class replaces the standard CDialogBar class, so to use them - simply replace all entries of CDialog (CDialogBar) in your derived classes with CProfUISDialog (CProuisDialogBar), and have fun.

Class code

Header file

C++
#pragma once
#include < vector >
BOOL CALLBACK EnumContainerChildProc( HWND hwnd, LPARAM lParam );


struct CGeneralSubclasserContainer {
    CGeneralSubclasserContainer()
    {
        m_ActLikeMessageBox = false;
    }
    virtual  ~CGeneralSubclasserContainer()
    {
        for( long i = 0; i < m_GeneralSubclassers.size(); ++i ) 
    {
            delete m_GeneralSubclassers[i];
        }
    }
    bool m_ActLikeMessageBox;
    std::vector< CWnd* > m_GeneralSubclassers;
    long addWindow(CWnd* newWnd)
    {
        m_GeneralSubclassers.push_back( newWnd );
        return m_GeneralSubclassers.size() - 1;
    }
};

class CProuisDialogBar : public CExtWA < CExtWS < CDialogBar > >, 
                    public CGeneralSubclasserContainer
{
public:
    CProuisDialogBar() {}
    virtual ~CProuisDialogBar() {};
    void StandardPrepare();
};
class CExtProgressCtrl : public CProgressCtrl {
public:
    CExtProgressCtrl(){}
    virtual ~CExtProgressCtrl(){}

public:
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnPaint();
};


// CQSOFilterDialog dialog

class CProfUISDlg : public CExtResizableDialog, 
    public CGeneralSubclasserContainer //CExtWA < CExtWS < CDialog > >
{
    DECLARE_DYNAMIC(CProfUISDlg)

public:
    CProfUISDlg() {}
    CProfUISDlg(UINT nID, CWnd* pParent = NULL);   // standard constructor
    CProfUISDlg( __EXT_MFC_SAFE_LPCTSTR lpszTemplateName, 
                    CWnd * pParentWnd = NULL );
    virtual ~CProfUISDlg();

    void StandardPrepare();

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
    afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
};

The ProfUIS library needs the next class to be declared, so you will get a skinned look for the non-client area as well.

C++
template < >
class CExtNCW < CProfUISDlg >
    : public CProfUISDlg
    , public CExtNcFrameImpl
{
public:
    CExtNCW()
    {
    }
    CExtNCW(
        UINT nIDTemplate,
        CWnd * pParentWnd = NULL
        )
        : CProfUISDlg( nIDTemplate, pParentWnd )
    {
    }
    CExtNCW(
        __EXT_MFC_SAFE_LPCTSTR lpszTemplateName,
        CWnd * pParentWnd = NULL
        )
        : CProfUISDlg( lpszTemplateName, pParentWnd )
    {
    }
    virtual ~CExtNCW()
    {
    }
    virtual HWND NcFrameImpl_OnQueryHWND()
    {
        return GetSafeHwnd();
    }
protected:
    virtual void PreSubclassWindow()
    {
        CProfUISDlg::PreSubclassWindow();
        CExtNcFrameImpl::PreSubclassWindow();
    }
    virtual void PostNcDestroy()
    {
        CExtNcFrameImpl::PostNcDestroy();
        CProfUISDlg::PostNcDestroy();
    }
    virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
    {
        if( ! NcFrameImpl_IsSupported() )
            return CProfUISDlg::WindowProc( message, wParam, lParam );
        HWND hWndOwn = m_hWnd;
        LRESULT lResult = 0;
        if( NcFrameImpl_PreWindowProc( lResult, message, wParam, lParam ) )
            return lResult;
        lResult = CProfUISDlg::WindowProc( message, wParam, lParam );
        if( ! ::IsWindow( hWndOwn ) )
            return lResult;
        if( CWnd::FromHandlePermanent(hWndOwn) == NULL )
            return lResult;
        NcFrameImpl_PostWindowProc( lResult, message, wParam, lParam );
        return lResult;
    }
}; // class CExtNCW

Implementation file

C++
#include < stdafx.h >
#pragma hdrstop
#include "ProfUISDlgApp.h"
#include "ProfuisDlg.h"

// CQSOFilterDialog dialog

IMPLEMENT_DYNAMIC(CProfUISDlg, CExtResizableDialog)
                // CExtWA < CExtWS < CDialog > >)

CProfUISDlg::CProfUISDlg(UINT nID, CWnd* pParent /*=NULL*/)
    : CExtResizableDialog( nID, pParent)
{
}
CProfUISDlg::CProfUISDlg( __EXT_MFC_SAFE_LPCTSTR lpszTemplateName, 
                        CWnd * pParentWnd )
    : CExtResizableDialog( lpszTemplateName, pParentWnd)
{
}

CProfUISDlg::~CProfUISDlg()
{
}

void CProfUISDlg::DoDataExchange(CDataExchange* pDX)
{
    CExtResizableDialog::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CProfUISDlg, CExtResizableDialog )
    ON_WM_SHOWWINDOW()
END_MESSAGE_MAP()

// CQSOFilterDialog message handlers
BOOL CALLBACK EnumContainerChildProc( HWND hwnd, LPARAM lParam )
{
     CGeneralSubclasserContainer* dialogPtr = 
                (CGeneralSubclasserContainer*)lParam;
    if( CWnd::FromHandlePermanent( hwnd ) == 0 ) {
        CWnd* tmp = CWnd::FromHandle( hwnd );
        CString className;
        GetClassName( hwnd, className.GetBufferSetLength( 200 ), 200 );
        className.ReleaseBuffer();
        if( className.CompareNoCase( _T("edit") ) == 0 ) 
    {
            dialogPtr->m_GeneralSubclassers[dialogPtr->addWindow
                        ( new CExtEdit )]->
                SubclassWindow( hwnd );;
        } 
    else if( className.CompareNoCase( _T("Static") ) == 0 ) 
    {
            dialogPtr->m_GeneralSubclassers[dialogPtr->addWindow(
                new CExtLabel )]->SubclassWindow( hwnd );
        }  
    else if( className.CompareNoCase( _T("BUTTON") ) == 0 ) 
    {
            CButton* tmpButton = (CButton*)CWnd::FromHandle( hwnd );
            if( tmpButton->GetButtonStyle() == BS_CHECKBOX ||
                tmpButton->GetButtonStyle() == BS_AUTOCHECKBOX )
            {
                dialogPtr->m_GeneralSubclassers[dialogPtr->addWindow
            ( new CExtCheckBox )]->
                    SubclassWindow( hwnd );
            } 
        else if( tmpButton->GetButtonStyle() == BS_GROUPBOX ) 
        {
                dialogPtr->m_GeneralSubclassers[dialogPtr->addWindow
            ( new CExtGroupBox )]->
                    SubclassWindow( hwnd );
                ((CExtGroupBox*)dialogPtr->m_GeneralSubclassers[dialogPtr->
                    m_GeneralSubclassers.size() - 1])->SetStyle
                ( CExtGroupBox::STYLE_ROUNDED );
                ((CExtGroupBox*)dialogPtr->m_GeneralSubclassers[dialogPtr->
                    m_GeneralSubclassers.size() - 1])->SetWindowPos
            ( &CWnd::wndBottom, 0,0,0,0, SWP_NOSIZE| SWP_NOMOVE );

            } 
        else if( tmpButton->GetButtonStyle() == BS_AUTORADIOBUTTON ||
                tmpButton->GetButtonStyle() == BS_RADIOBUTTON )
            {
                dialogPtr->m_GeneralSubclassers[dialogPtr->addWindow
            ( new CExtRadioButton )]->
                    SubclassWindow( hwnd );
            } 
        else 
        {
                dialogPtr->m_GeneralSubclassers[dialogPtr->addWindow
            ( new CExtButton )]->
                    SubclassWindow( hwnd );
            }
        }  
    else if( className.CompareNoCase( _T("msctls_progress32") ) == 0 ) 
    {
            dialogPtr->m_GeneralSubclassers[dialogPtr->
                addWindow( new CExtProgressCtrl )]->SubclassWindow( hwnd );
        } 
    else if( className.CompareNoCase( _T("ComboBox") ) == 0 ) 
    {
            dialogPtr->m_GeneralSubclassers[dialogPtr->
                addWindow( new CExtComboBox )]->SubclassWindow( hwnd );
        }
    }
    return TRUE;
}
CProuisDialogBar::StandardPrepare()
{
    EnumChildWindows( GetSafeHwnd(), EnumContainerChildProc, LPARAM(
        static_cast< CGeneralSubclasserContainer* >( this ) ) );
}
void CProfUISDlg::StandardPrepare()
{
    EnumChildWindows( GetSafeHwnd(), EnumContainerChildProc, LPARAM(
        static_cast< CGeneralSubclasserContainer*>( this ) ) );
    ShowSizeGrip( FALSE );
}
BOOL CProfUISDlg::OnInitDialog()
{
    CExtResizableDialog::OnInitDialog();
    StandardPrepare();
    return TRUE;
}

BEGIN_MESSAGE_MAP(CExtProgressCtrl, CProgressCtrl)
    ON_WM_PAINT()
END_MESSAGE_MAP()

void CExtProgressCtrl::OnPaint()
{
    CRect rcClient;
    GetClientRect( &rcClient );
    CPaintDC dcPaint( this );
    CExtMemoryDC dc( &dcPaint, &rcClient );
    if( g_PaintManager->GetCb2DbTransparentMode(this) )
    {
        CExtPaintManager::stat_ExcludeChildAreas(
            dc,
            GetSafeHwnd(),
            CExtPaintManager::stat_DefExcludeChildAreaCallback
            );
        g_PaintManager->PaintDockerBkgnd( true, dc, this );
    } // if( g_PaintManager->GetCb2DbTransparentMode(this) )
    else
        dc.FillSolidRect( &rcClient, g_PaintManager->
    GetColor( CExtPaintManager::CLR_3DFACE_OUT, this ) );
    DefWindowProc( WM_PAINT, WPARAM(dc.GetSafeHdc()), 0L );
    g_PaintManager->OnPaintSessionComplete( this );
}

void CProfUISDlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
    CExtResizableDialog::OnShowWindow(bShow, nStatus);
    if( m_ActLikeMessageBox && bShow ) {
        EnumChildWindows( GetSafeHwnd(), EnumContainerChildProc,
            LPARAM( static_cast< CGeneralSubclasserContainer*>( this ) ) );
        ShowSizeGrip( FALSE );
    }
}

Using the code

To use these classes in your applications, first you must copy the declarations to your header file and the implementation to the implementation file. After including this code to your project, use the desired class CProfUISDlg or CProuisDialogBar as usual CDialog or CDialogBar!

Example

C++
// CExtNCW - used in profuis for customising non-client area
class CImportDialog : public CExtNCW< CProfUISDlg >
{
    ....
    public:
        virtual BOOL OnInitDialog();
}

Important tip: if you want to subclass some control in an unusual way, subclass it before calling the parent CProfUISDlg::OnInitDialog!!

C++
BOOL CImportDialog::OnInitDialog()
{
    // some real custom subclass code
    BOOL result = CProfUISDlg::OnInitDialog();
    // post subclass code
    return result;
}

Following the given instructions, you can obtain something that looks like this:

Image 1

The red/green indicator is a simple static-derived control I coded for a nice look in large input forms. It can switch on/off the next control after it by mouse click, and also indicates the control state. Maybe in my next short article, I will put it on the top of the discussion.

Useful hints

Now, some useful code hints.

First hint: How to replace the standard MessageBox with a brand-new one.

You must replace the standard CWinApp::DoMessageBox with your own CMyApp::DoMessageBox. The new version will look like this:

C++
int CMyApp::DoMessageBox(LPCTSTR lpszPrompt, UINT nType, UINT nIDPrompt)
{
    CExtNCW<CProfuisDlg> dlg;
    dlg.m_ActLikeMessageBox = true;
    AfxHookWindowCreate( &dlg );
    return CWinApp::DoMessageBox(lpszPrompt, nType, nIDPrompt);
}
//.............Somewhere in your code.........
AfxMessageBox( _T("Hi! Now you'll see the result!");
 //.............Somewhere in your code.........

And here is the Mr. NiceLooking MessageBox:

Image 2

Second hint: How to replace the standard print preview bar with a new one.

If you already know how to work with custom print preview, then add to your custom DoPrintPreview the given code:

C++
BOOL CWrapperView::DoPrintPreview(UINT nIDResource, CView* pPrintView,
    CRuntimeClass* pPreviewViewClass, CPrintPreviewState* pState)
{
// Some standard preparing job

// Create the preview view object
    CMyPreviewView* pView = (CMyPreviewView*)pPreviewViewClass->CreateObject();
    if (pView == NULL)
    {
        TRACE0("Error: Failed to create preview view.\n");
        return FALSE;
    }
    pView->m_pPreviewState = pState;        // save pointer

    // It's fun, but the real change is in the only one line!!!:
    pView->m_pToolBar = new CProuisDialogBar;

    if (!pView->m_pToolBar->Create(pParent, MAKEINTRESOURCE(nIDResource),
        CBRS_TOP, AFX_IDW_PREVIEW_BAR))
    {
        // some clearing and failure code
        return FALSE;
    }
    ((CProuisDialogBar*) pView->m_pToolBar)->StandardPrepare();
    pView->m_pToolBar->m_bAutoDelete = TRUE;    // automatic cleanup

// you can already manipulate with your new nice-looking printpreview bar,
// for example place custom button on it...
    addOptionsButtonToPreviewBar( pView->m_pToolBar );

// your standard code continues
}

After all, we get what we wanted to:

Image 3

Conclusion

You can test the code in a working sample project. You can download the project at the top of this article.

I hope you find this article really useful, see ya.

Special thanks

Special thanks to my friend SloNN for the message box hint.

History

  • 20.06.2007 - sample project added and code samples changed to be stable and tested.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Russian Federation Russian Federation
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralGreat Article and Code Pin
Darren Sessions1-Mar-10 8:45
Darren Sessions1-Mar-10 8:45 
QuestionCannot get this to function.... Pin
vachaun18-Mar-08 8:41
vachaun18-Mar-08 8:41 
AnswerRe: Cannot get this to function.... Pin
Evgueni Kolossov20-Mar-08 1:07
Evgueni Kolossov20-Mar-08 1:07 
QuestionCFileDialog? Pin
Evgueni Kolossov11-Mar-08 4:59
Evgueni Kolossov11-Mar-08 4:59 
QuestionVista problem? Pin
ahamade29-Feb-08 7:33
ahamade29-Feb-08 7:33 
Generalbug at windows server 2008 rc0 Pin
XiaoQing Li23-Dec-07 21:15
XiaoQing Li23-Dec-07 21:15 
QuestionHow to use another font in Messageboxes? Pin
Carsten Panch7-Nov-07 0:06
Carsten Panch7-Nov-07 0:06 
AnswerRe: How to use another font in Messageboxes? Pin
Leshchuk Aleksey13-Nov-07 3:00
Leshchuk Aleksey13-Nov-07 3:00 
Generaltmp variable needed [modified] Pin
ppaappuuss27-Jul-07 12:52
ppaappuuss27-Jul-07 12:52 
GeneralRe: tmp variable needed Pin
Leshchuk Aleksey27-Jul-07 18:40
Leshchuk Aleksey27-Jul-07 18:40 
Generalmany mugs... Pin
__ant__29-Jun-07 4:29
__ant__29-Jun-07 4:29 
GeneralRe: many mugs... Pin
Leshchuk Aleksey29-Jun-07 8:45
Leshchuk Aleksey29-Jun-07 8:45 
GeneralVery useful with some bugs Pin
Wocki15-Jun-07 0:20
Wocki15-Jun-07 0:20 
GeneralRe: Very useful with some bugs Pin
Leshchuk Aleksey15-Jun-07 5:32
Leshchuk Aleksey15-Jun-07 5:32 
if you mean:
} else { return FALSE; }


than it's not a bug, if you have any non-common control on your dialog, than you will possibly replace not all of your real common controls, so you better always return TRUE.

P.S. EnumChildProc specification: To continue enumeration, the callback function must return TRUE; to stop enumeration, it must return FALSE.
AnswerRe: Very useful with some bugs Pin
Wocki17-Jun-07 21:45
Wocki17-Jun-07 21:45 
GeneralRe: Very useful with some bugs Pin
Leshchuk Aleksey18-Jun-07 1:30
Leshchuk Aleksey18-Jun-07 1:30 
GeneralRe: Very useful with some bugs Pin
Leshchuk Aleksey19-Jun-07 11:21
Leshchuk Aleksey19-Jun-07 11:21 
GeneralRe: Very useful with some bugs Pin
Wocki20-Jun-07 19:42
Wocki20-Jun-07 19:42 
Generalthnx Pin
Leshchuk Aleksey14-Jun-07 9:53
Leshchuk Aleksey14-Jun-07 9:53 
GeneralCool Pin
Wes Aday14-Jun-07 9:44
professionalWes Aday14-Jun-07 9:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.