<

Using a Property Sheet as your Main Window

Published on
10,944 Points
4,344 Views
1 Endorsement
Last Modified:
DanRollins
You've seen this in Control-Panel applets, small utility programs, and even the Windows Task Manager.  A simple dialog-based program won't provide the U/I experience you want, but the document/view architecture seems too complex.Property Sheet as the Main WindowsTo give that familiar U/I to your program, use a CPropertySheet-derived object as the main window.  Individual CPropertyPages can be used to handle various categories of settings and options, and you can provide multiple views -- real-time status, lists of objects, log of activities, etc. -- in other pages.  Each page is effectively a dialog box (a "form") so you have great flexibility in your U/I design.

In this article, I'll describe what you need to do to create this type of program, and I'll throw in a few tips and tricks that are handy to know in this scenario:  We'll get rid of the Apply and Help buttons and enable minimize/restore functionality.  Here we go.

1

In Visual Studio,
Create Project...
Project Type: VisualC++ / MFC
     Template: MFC Application
          Name: MyProg
Click [Next], then..
Application Type: Dialog-based
[Finish]

2

Create some PropertyPages
In the Resource View...
Right-click My Prog
Select Add > Resource
Click on Dialog to open it up.
Select IDD_PROPPAGE_LARGE
Click [New]
Creating the PagesIn the Dialog Editor, set
Caption: General
          ID: IDD_PgGeneral

Add some Controls:A Page with Some Controls

3

Create a CPropertyPage-derived object for that property page:
In the Dialog Editor, double-click on the title bar of the property page to bring up the Class Wizard. Set...
Class Name: CPgGeneral
 Base Class: CPropertyPage
Deriving from CPropertyPage

4

Repeat steps 2 and 3 for each property page
Three Pages in This Example

5

Open up the application main CPP file (MyProg.cpp)
Add these #include lines at the top:
#include "PgGeneral.h"
#include "PgSettings.h"
#include "PgActivityLog.h"

Open in new window

Now, locate the InitInstance() function, and near the bottom of it, replace the key start-up sequence as follows:
// replace these lines
//	CMyProgDlg dlg;             
//	m_pMainWnd = &dlg;
//	INT_PTR nResponse = dlg.DoModal();
// ... with these

	CPropertySheet cSheet( L"WonderProg" );
	CPgGeneral     cPgGeneral;
	CPgSettings    cPgSettings;
	CPgActivityLog cPgActivityLog;

	cSheet.AddPage( &cPgGeneral );
	cSheet.AddPage( &cPgSettings );
	cSheet.AddPage( &cPgActivityLog );

	int nResponse= cSheet.DoModal(); // run your entire program
	if (nResponse == IDOK)
      ... etc...

Open in new window

You now have a program that has a PropertySheet as its main window.  You can delete the two files MyProgDlg.cpp and MyProgDlg.h and you can remove the resource IDD_MYPROG_DIALOGThe Example Program Using the base CPropertySheet object
But Wait! There's More!

We used CPropertySheet's default functionality, but you will want make a few adjustments because this is your main window and you want want to exert some control over various aspects of the User Interface.

Get Rid of the Help and Apply Buttons
==============================
For instance, let's say that you want to get rid of the "Help" and "Apply" buttons.  We'll derive a class that does that:

1

In the Class View...
Right-click MyProg
Select Add > Class
Choose MFC Class
Click [Add]

2

In Class Wizard,
Class Name: CSheetMain
 Base class: CPropertySheet
[Finish]
Deriving from CPropertySheet

3

Right-click the SheetMain item in the Class View
Choose Properties
Click the diamond-shaped Overrides icon.
Click OnInitDialog and choose <Add OnInitDialog>
Put this code into your CSheetMain::OnInitDialog() function:
BOOL CSheetMain::OnInitDialog()
{
    BOOL bResult = CPropertySheet::OnInitDialog();

    //----------------- Some setup for the PropertySheet buttons

    GetDlgItem(IDHELP)->ShowWindow(SW_HIDE); // so wonderful, no help is needed!

    //----------------- move the two remaining buttons to the right
    CRect rcBtn, rcDlg;
    GetWindowRect( &rcDlg );    

    CButton* pBtn= (CButton*)GetDlgItem( IDCANCEL );
    pBtn->GetWindowRect( &rcBtn );
    ScreenToClient( &rcBtn );
    int nOffset= (rcDlg.Width()-12)- rcBtn.right;
    rcBtn.OffsetRect(nOffset,0);
    pBtn->MoveWindow( &rcBtn, TRUE /*fRepaint*/ ); 
	
    pBtn= (CButton*)GetDlgItem( IDOK );
    pBtn->GetWindowRect( &rcBtn );
    ScreenToClient( &rcBtn );
    rcBtn.OffsetRect(nOffset,0);
    pBtn->MoveWindow( &rcBtn, TRUE /*fRepaint*/ ); 

    return bResult;
}

Open in new window

And modify your constructor to be:
CSheetMain::CSheetMain(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)
	:CPropertySheet(pszCaption, pParentWnd, iSelectPage)
{
    m_psh.dwFlags |= PSH_NOAPPLYNOW ;
    m_psh.dwFlags &= ~PSH_HASHELP; 
}

Open in new window

4

Next, go back to MyProg.cpp and set it to use the derived object rather than the base object:
#include "SheetMain.h" // at the top and...
...
    // ...in InitInstance()
    CSheetMain  cSheet( L"WonderProg" );   
    //CPropertySheet cSheet( L"WonderProg" );

Open in new window

Moving the Buttons in OnInitDialog()
Enable Your App to Minimize to the Taskbar
===================================
Since this is your main window, you will want to let your user minimize it normally --  so that it will show an icon in the Taskbar, just like a real program!  It's not particularly obvious how to do that, so here's the trick.  First, change the CSheetMain() constructor like this:
CSheetMain::CSheetMain(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)
	:CPropertySheet(pszCaption, pParentWnd, iSelectPage)
{
    HICON hIcon= AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    m_psh.hIcon= hIcon;
    m_psh.dwFlags |= PSH_NOAPPLYNOW |PSH_USEHICON ;
    m_psh.dwFlags &= ~PSH_HASHELP; 
}

Open in new window

That gives your program an icon to display on the title bar and in the taskbar when it's minimized.  Now to enable the Minimize/Restore functionality, add this code to the bottom of your CSheetMain::OnInitDialog() function:
    CMenu* pSysMenu = GetSystemMenu( FALSE );
    pSysMenu->AppendMenu(MF_STRING, SC_MINIMIZE , L"Minimize");
    pSysMenu->AppendMenu(MF_STRING, SC_RESTORE  , L"Restore");

    ModifyStyle( 0, WS_MINIMIZEBOX  );

Open in new window

The finished product is illustrated by Fig 1.1 at the top of this article.

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
If you liked this article and want to see more from this author,  please click the Yes button near the:
      Was this article helpful?
label that is just below and to the right of this text.   Thanks!
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1
Comment
Author:DanRollins
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
0 Comments

Featured Post

Revamp Your Training Process

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action.

Join & Write a Comment

This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month