Thread: Creating a modeless property sheet

  1. #1
    Registered User
    Join Date
    Dec 2004
    Posts
    205

    Creating a modeless property sheet

    Hi,
    I have been successful in making a modal property sheet (Very very basic) but when it comes to making a modeless one, I am baffled by how you use Create(). I am having trouble especially with passing a CWind pointer to the Create function. Can someone look at the code and let me know what I am doing wrong. The call to Create happens in the second piece of code at the end. I used MSVS .NET 2003 to make this using MFC dialog style. What should happen is first a dialogue box with 1 button pops up. If you click on the button a property sheet with two property pages should pop up. Thanks in advance.

    Code:
    // TEST.cpp : Defines the class behaviors for the application.
    //
    
    #include "stdafx.h"
    #include "TEST.h"
    #include "TESTDlg.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    
    // CTESTApp
    
    BEGIN_MESSAGE_MAP(CTESTApp, CWinApp)
    	ON_COMMAND(ID_HELP, CWinApp::OnHelp)
    END_MESSAGE_MAP()
    
    
    // CTESTApp construction
    
    CTESTApp::CTESTApp()
    {
    	// TODO: add construction code here,
    	// Place all significant initialization in InitInstance
    }
    
    
    // The one and only CTESTApp object
    
    CTESTApp theApp;
    
    
    // CTESTApp initialization
    
    BOOL CTESTApp::InitInstance()
    {
    	// InitCommonControls() is required on Windows XP if an application
    	// manifest specifies use of ComCtl32.dll version 6 or later to enable
    	// visual styles.  Otherwise, any window creation will fail.
    	InitCommonControls();
    
    	CWinApp::InitInstance();
    
    	AfxEnableControlContainer();
    
    	// Standard initialization
    	// If you are not using these features and wish to reduce the size
    	// of your final executable, you should remove from the following
    	// the specific initialization routines you do not need
    	// Change the registry key under which our settings are stored
    	// TODO: You should modify this string to be something appropriate
    	// such as the name of your company or organization
    	SetRegistryKey(_T("EVEREST VIT"));
    	
    	CTESTDlg dlg;
    
    	m_pMainWnd = &dlg;
    	INT_PTR nResponse = dlg.DoModal();
    	if (nResponse == IDOK)
    	{
    		// TODO: Place code here to handle when the dialog is
    		//  dismissed with OK
    	}
    	else if (nResponse == IDCANCEL)
    	{
    		// TODO: Place code here to handle when the dialog is
    		//  dismissed with Cancel
    		
    	}
    
    	// Since the dialog has been closed, return FALSE so that we exit the
    	//  application, rather than start the application's message pump.
    	return FALSE;
    Code:
    // TESTDlg.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "TEST.h"
    #include "TESTDlg.h"
    #include ".\testdlg.h"
    #include "prop1.h"
    #include "prop2.h"
    #include "modelesspropsheet.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    
    // CAboutDlg dialog used for App About
    
    class CAboutDlg : public CDialog
    {
    public:
    	CAboutDlg();
    
    // Dialog Data
    	enum { IDD = IDD_ABOUTBOX };
    
    	protected:
    	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    
    // Implementation
    protected:
    	DECLARE_MESSAGE_MAP()
    };
    
    CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
    {
    }
    
    void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    }
    
    BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    END_MESSAGE_MAP()
    
    
    // CTESTDlg dialog
    
    
    
    CTESTDlg::CTESTDlg(CWnd* pParent /*=NULL*/)
    	: CDialog(CTESTDlg::IDD, pParent)
    {
    	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }
    
    void CTESTDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	DDX_Control(pDX, ID_BUTTON1, button1);
    }
    
    BEGIN_MESSAGE_MAP(CTESTDlg, CDialog)
    	ON_WM_SYSCOMMAND()
    	ON_WM_PAINT()
    	ON_WM_QUERYDRAGICON()
    	//}}AFX_MSG_MAP
    	ON_BN_CLICKED(ID_BUTTON1, OnBnClickedButton1)
    END_MESSAGE_MAP()
    
    
    // CTESTDlg message handlers
    
    BOOL CTESTDlg::OnInitDialog()
    {
    	CDialog::OnInitDialog();
    
    	// Add "About..." menu item to system menu.
    
    	// IDM_ABOUTBOX must be in the system command range.
    	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    	ASSERT(IDM_ABOUTBOX < 0xF000);
    
    	CMenu* pSysMenu = GetSystemMenu(FALSE);
    	if (pSysMenu != NULL)
    	{
    		CString strAboutMenu;
    		strAboutMenu.LoadString(IDS_ABOUTBOX);
    		if (!strAboutMenu.IsEmpty())
    		{
    			pSysMenu->AppendMenu(MF_SEPARATOR);
    			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    		}
    	}
    
    	// Set the icon for this dialog.  The framework does this automatically
    	//  when the application's main window is not a dialog
    	SetIcon(m_hIcon, TRUE);			// Set big icon
    	SetIcon(m_hIcon, FALSE);		// Set small icon
    
    	// TODO: Add extra initialization here
    	
    	return TRUE;  // return TRUE  unless you set the focus to a control
    }
    
    void CTESTDlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    	{
    		CAboutDlg dlgAbout;
    		dlgAbout.DoModal();
    	}
    
    	else
    	{
    		CDialog::OnSysCommand(nID, lParam);
    	}
    }
    
    // If you add a minimize button to your dialog, you will need the code below
    //  to draw the icon.  For MFC applications using the document/view model,
    //  this is automatically done for you by the framework.
    
    void CTESTDlg::OnPaint() 
    {
    	if (IsIconic())
    	{
    		CPaintDC dc(this); // device context for painting
    
    		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
    
    		// Center icon in client rectangle
    		int cxIcon = GetSystemMetrics(SM_CXICON);
    		int cyIcon = GetSystemMetrics(SM_CYICON);
    		CRect rect;
    		GetClientRect(&rect);
    		int x = (rect.Width() - cxIcon + 1) / 2;
    		int y = (rect.Height() - cyIcon + 1) / 2;
    
    		// Draw the icon
    		dc.DrawIcon(x, y, m_hIcon);
    	}
    	else
    	{
    		CDialog::OnPaint();
    	}
    }
    
    // The system calls this function to obtain the cursor to display while the user drags
    //  the minimized window.
    HCURSOR CTESTDlg::OnQueryDragIcon()
    {
    	return static_cast<HCURSOR>(m_hIcon);
    }
    
    void CTESTDlg::OnBnClickedButton1()
    {
    	// TODO: Add your control notification handler code here
    	 CPropertySheet propsheet;
    	 prop1 propone;
    	 prop2 proptwo;
    	 propsheet.AddPage(&propone);
    	 propsheet.AddPage(&proptwo);
    	 propsheet.Create(this,WS_POPUP | WS_VISIBLE, 0);
    }
    Amish

  2. #2
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Add the Property sheets (dialogs) as member variables of the CTestDlg class (not locals of the Button click event) to avoid loosing scope when the handler ends.

    I do something like this to ensure the dialog has not been created
    (but I use a dlg 'drawn' in the resource editor)
    Code:
    	if(m_Dlg.GetSafeHwnd()!=NULL)
    		m_Dlg.ShowWindow(SW_SHOW);
    	else
    		m_Dlg.Create(MAKEINTRESOURCE(IDD_DIALOG),this);
    Last edited by novacain; 01-08-2005 at 12:10 AM.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  3. #3
    Registered User
    Join Date
    Dec 2004
    Posts
    205
    Thanks for the reply,
    I was wondering if you have used tabs before. Since I could not figure out how to create a property sheet properly and I also needed a minimize button, I decided to use tabs instead of property sheet. I have managed to initialize two tabs using the code below:
    Code:
    // XLRemoteDlg.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "XLRemote.h"
    #include "XLRemoteDlg.h"
    #include ".\xlremotedlg.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    
    
    // CAboutDlg dialog used for App About
    
    class CAboutDlg : public CDialog
    {
    public:
    	CAboutDlg();
    
    // Dialog Data
    	enum { IDD = IDD_ABOUTBOX };
    
    	protected:
    	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    
    // Implementation
    protected:
    	DECLARE_MESSAGE_MAP()
    };
    
    CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
    {
    }
    
    void CAboutDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    }
    
    BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    END_MESSAGE_MAP()
    
    
    // CXLRemoteDlg dialog
    
    
    
    CXLRemoteDlg::CXLRemoteDlg(CWnd* pParent /*=NULL*/)
    	: CDialog(CXLRemoteDlg::IDD, pParent)
    {
    	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }
    
    void CXLRemoteDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	DDX_Control(pDX, IDC_SWITCH, m_Color);
    }
    
    BEGIN_MESSAGE_MAP(CXLRemoteDlg, CDialog)
    	ON_WM_SYSCOMMAND()
    	ON_WM_PAINT()
    	ON_WM_QUERYDRAGICON()
    	ON_NOTIFY(TCN_SELCHANGE, IDC_SWITCH, OnTcnSelchangeSwitch)
    END_MESSAGE_MAP()
    
    
    // CXLRemoteDlg message handlers
    
    BOOL CXLRemoteDlg::OnInitDialog()
    {
    	CDialog::OnInitDialog();
    
    	// Add "About..." menu item to system menu.
    
    	// IDM_ABOUTBOX must be in the system command range.
    	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    	ASSERT(IDM_ABOUTBOX < 0xF000);
    
    	CMenu* pSysMenu = GetSystemMenu(FALSE);
    	if (pSysMenu != NULL)
    	{
    		CString strAboutMenu;
    		strAboutMenu.LoadString(IDS_ABOUTBOX);
    		if (!strAboutMenu.IsEmpty())
    		{
    			pSysMenu->AppendMenu(MF_SEPARATOR);
    			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    		}
    	}
    
    	// Set the icon for this dialog.  The framework does this automatically
    	//  when the application's main window is not a dialog
    	SetIcon(m_hIcon, TRUE);			// Set big icon
    	SetIcon(m_hIcon, FALSE);		// Set small icon
    
    	// TODO: Add extra initialization here
    	// Initialize tabs
    	TC_ITEM TabCtrlItem;
    	TabCtrlItem.mask = TCIF_TEXT;
    	TabCtrlItem.pszText = "Wood";
    	m_Color.InsertItem( 0, &TabCtrlItem );
    	TabCtrlItem.pszText = "Natural Gas";
    	m_Color.InsertItem( 1, &TabCtrlItem );
    	AfxMessageBox("Dialog closed successfully");
    	return TRUE;  // return TRUE  unless you set the focus to a control
    }
    
    void CXLRemoteDlg::OnSysCommand(UINT nID, LPARAM lParam)
    {
    	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    	{
    		CAboutDlg dlgAbout;
    		dlgAbout.DoModal();
    	}
    	else
    	{
    		CDialog::OnSysCommand(nID, lParam);
    	}
    }
    
    // If you add a minimize button to your dialog, you will need the code below
    //  to draw the icon.  For MFC applications using the document/view model,
    //  this is automatically done for you by the framework.
    
    void CXLRemoteDlg::OnPaint() 
    {
    	if (IsIconic())
    	{
    		CPaintDC dc(this); // device context for painting
    
    		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
    
    		// Center icon in client rectangle
    		int cxIcon = GetSystemMetrics(SM_CXICON);
    		int cyIcon = GetSystemMetrics(SM_CYICON);
    		CRect rect;
    		GetClientRect(&rect);
    		int x = (rect.Width() - cxIcon + 1) / 2;
    		int y = (rect.Height() - cyIcon + 1) / 2;
    
    		// Draw the icon
    		dc.DrawIcon(x, y, m_hIcon);
    	}
    	else
    	{
    		CDialog::OnPaint();
    	}
    }
    
    // The system calls this function to obtain the cursor to display while the user drags
    //  the minimized window.
    HCURSOR CXLRemoteDlg::OnQueryDragIcon()
    {
    	return static_cast<HCURSOR>(m_hIcon);
    }
    
    void CXLRemoteDlg::OnTcnSelchangeSwitch(NMHDR *pNMHDR, LRESULT *pResult)
    {
    	// TODO: Add your control notification handler code here
    	int nColor = m_Color.GetCurSel();
    
    	switch(nColor)
    	{
    	case 0:
    		
    		break;
    	case 1:
    		
    		break;
    	}
    	*pResult = 0;
    }
    I was wondering how do I add a simple dialogue box to each tab. I use MSVS .NET 2003 and I have already have the dialog box resources. Thanks
    Amish

  4. #4
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    I create both dlgs (hidden) both made the slighty smaller than the TAB controls client area.

    After you add the TAB labels, Set the TAB to the first label.

    Find the TAB controls position on the dialog, that is the offset from the top left. (GetWindowRect(), GetClientRect(), ScreenToClient() ect)

    Move the dialog to the correct position and ensure it in front of the other dialog (higher in the Z order eg HWND_TOPMOST use SetWindowPos() )

    Show the first dialog.

    Process move messages so the little dialog stays on the TAB (WM_MOVING ect)

    Process TAB selection changes. Hide current dlg, move and show new dlg.

    If in doubt post code...

    ie
    I would..

    TC_ITEM TabCtrlItem;
    ZeroMemory( &TabCtrlItem, sizeof(TC_ITEM) ); //make sure all fields we are NOT using are null, even though the IDE should
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  5. #5
    Registered User
    Join Date
    Dec 2004
    Posts
    205
    Hi,
    This is a part of a code that I found online describing how to set a dialog to display in a tabbed frame:
    Code:
    void MyTabCtrl::ActivateTabDialogs()
    {
    	int nSel = GetCurSel();
    	if(m_DialogFocus.m_hWnd)
    		m_DialogFocus.DestroyWindow();
    	m_DialogFocus.Create(m_DialogID[nSel],GetParent());
    
    	CRect l_rectClient;
    	CRect l_rectWnd;
    
    	GetClientRect(l_rectClient);
    	AdjustRect(FALSE,l_rectClient);
    	GetWindowRect(l_rectWnd);
    	GetParent()->ScreenToClient(l_rectWnd);
    	l_rectClient.OffsetRect(l_rectWnd.left,l_rectWnd.top);
    	m_DialogFocus.SetWindowPos(&wndTop,l_rectClient.left,l_rectClient.top,l_rectClient.Width(),l_rectClient.Height(),SWP_SHOWWINDOW);
    }
    I tried going through the code and I checked the MSDN library for the explanation about the different functions used but I can't quite grasp why one should go through all these steps. I understand that GetClientRect gets the size of the window while GetWindowRect get the position wrt to the top left of the screen but what is the purpose of "GetParent()->ScreenToClient(l_rectWnd)" & "l_rectClient.OffsetRect(l_rectWnd.left,l_rectWnd. top)".
    Thanks a lot for you time,
    Amish

  6. #6
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    sort of..

    Code:
    void MyTabCtrl::ActivateTabDialogs()
    {
    	//find TAB selected
    	int nSel = GetCurSel();
    	//see if dialog has already been created (on-screen currently)
    	if(m_DialogFocus.m_hWnd)
    		m_DialogFocus.DestroyWindow();//if so destroy old dlg
    	//create new dialog as a child of the TABs parent
    	//so positions ect are relative to the parent dialog
    	//and we can get messages from/ send message to the parent 
    	// look at WM_NOTIFY messages
    	m_DialogFocus.Create(m_DialogID[nSel],GetParent()); // note array used to select correct dlg
    
    	CRect l_rectClient;
    	CRect l_rectWnd;
    
    	// get the TABS size (usually with client rects left and top will be zero)
    	GetClientRect(l_rectClient);
    	// find the area we have to work with (TAB size minus the labels)
    	AdjustRect(FALSE,l_rectClient);
    	//get location relative to top left of screen
    	GetWindowRect(l_rectWnd);
    	//based on the TABS parent dialog (which is also m_DialogFocus's parent)
    	//convert from screen top left to parents dialog top left
    	//this gives the X,Y from the top left of the TABS parent dialog to the top left of the TAB
    	GetParent()->ScreenToClient(l_rectWnd);
    	// add this offset to the TABs client rect
    	l_rectClient.OffsetRect(l_rectWnd.left,l_rectWnd.t  op);
    	//now set the dialogs position and size
    	m_DialogFocus.SetWindowPos(&wndTop, //top of the Z order
    				l_rectClient.left,l_rectClient.top,// position relative to parent
    				l_rectClient.Width(),l_rectClient.Height(),//same dimensions as TAB ctrls use-able area
    				SWP_SHOWWINDOW)  ;//make dlg visible
    }
    but I would not destroy the window and create a new on each time....
    I would hide current then show new.
    This would retain previous values in edits ect (good or bad depending on app) and would have less overhead IMO.
    Last edited by novacain; 01-12-2005 at 01:32 AM.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  7. #7
    Registered User
    Join Date
    Dec 2004
    Posts
    205
    Thanks for your answer novacain. It was really helpful. Hopefully I won't have any more questions
    Amish

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Profiler Valgrind
    By afflictedd2 in forum C++ Programming
    Replies: 4
    Last Post: 07-18-2008, 09:38 AM
  2. Moving a Property Sheet
    By Eibro in forum Windows Programming
    Replies: 1
    Last Post: 07-05-2003, 09:20 AM
  3. Dialog Box & Property Sheet :: MFC
    By kuphryn in forum Windows Programming
    Replies: 2
    Last Post: 08-01-2002, 01:33 PM
  4. Passing a recordset pointer to a property sheet
    By Robert602 in forum Windows Programming
    Replies: 0
    Last Post: 05-14-2002, 07:45 AM
  5. Property Sheets :: MFC
    By kuphryn in forum Windows Programming
    Replies: 0
    Last Post: 05-09-2002, 03:04 PM