How do the initialization is done in propertysheet? - mfc

I am having propertysheet where I had overriden OnInitDialog in CPropertySheet derived class
as follows,
BOOL CMySheet::OnInitDialog()
{
CPropertySheet::OnInitDialog();
//Once the call reached this point and after this my first page OnInitDialog is being called.
//Only first page onInitDialog is being called and it is not calling the remaining pages //OnInitDialog.why?
//I am not sure how this calling or mapping is being done.
}
//CMySheet is derived from CPropertySheet
can anyone please explain me how all this mapping is being done.

how to correctly add the pages:
you can immagine a CPropertySheet as a dialog container, so its main job is to contain other dialogs CPropertyPage.
So firstly i would say that you have to create your CPropertyPages: so create the resources, classes etc...
Then you add the pages using CPropertySheet::AddPage method, but you don't have to do it in the CPropertySheet::OnInitDialog you can do it in the constructor or even outside the class but the important thing is that you do it before you call the CPropertySheet::DoModal because that is the moment where the CPropertySheet::OnInitDialog will be called.
something like this:
CMySheet *pSheet = new CMySheet();
CMyPage *pPage = new CMyPage();
pSheet->AddPage(pPage);
INT_PTR iReturn = pSheet.DoModal();
How stuff works:
after you use the CPropertySheet::DoModal method the CPropertySheet::OnInitDialog will be called, the CPropertySheet will then load the first page, because as i said it is a dialog container, and therefore it will show one dialog at a time, that's why you see only the first page loading, because the CPropertySheet is made to show only one CPropertyPage at a time! So each page will load separatedly, lets say when you click on a tree that stores the pages or when you click on the next button if you created a wizard, and not all at the same time

Related

How to manually show CMFCToolBarComboBoxButton sub-menu?

Standard behaviour for CMFCToolBarComboBoxButton is to have a clickable button plus a drop-down arrow for displaying a submenu. I want to show the submenu independently of where the click was made. How can I do it?
My code to create the button is, more or less, the following (it has been extracted from a larger project, so I apologize for any missing not-too-important piece of code):
// In class declaration:
CMenu m_menu;
CMFCToolBar m_toolbar;
// Where toolbar initialization takes place:
m_menu.CreateMenu();
// ... populate menu
// ID_BUTTON is the ID in the resource file for the toolbar button, 0 is the index for the button icon
CMFCToolBarMenuButton button(ID_BUTTON, m_menu.GetSafeHmenu(), 0);
m_toolbar.ReplaceButton(ID_BUTTON, button);
I've been looking around for awhile and cannot find a related answer.
The solution happened to be very straightforward, just call the OnClick function of the CMFCToolBarComboBoxButton button from its associated ON_COMMAND.
// ... message map
ON_COMMAND(ID_BUTTON, OnToolbarMenuButtonClicked)
// ...
void MyWnd::OnToolbarMenuButtonClicked()
{
const int index = m_toolbar.CommandToIndex(ID_BUTTON);
auto button = (CMFCToolBarComboBoxButton*)m_toolbar.GetButton(index);
button->OnClick(NULL, TRUE);
}
This behaviour is not documented and, contrary to what common sense told me, it doesn't create an infinite recursive call. It seems that the "main" button is still controlled by CMFCToolBarButton, while just the "arrow-button" is controlled by the CMFCToolBarComboBoxButton.
PS: obviously, and out of the scope of the question, the OnToolbarMenuButtonClicked can be used for a very different purpose, such as the default action while the sub-menu contains other less-frequent options.

Embedded dialog in Tab Control cannot work in second dialog, MFC

I have following code which works in the main dialog, but cannot work in the second (or third) dialog. The thing is that I want each page of the tab control can show a embedded dialog, it's similar to property page.
First I create two dialog, IDD_DIALOG1 and IDD_DIALOG2.Then I change the style of them to child and border to None. After that I add CDialog class to each of them.
In my MainDialog.h, I have the following code:
#include "Dialog1.h"
#include "Dialog2.h"
...
public:
CDialog1 m_para1;
CDialog2 m_para2;
CTabCtrl m_TabCtrl;
In my MainDialog.cpp, I use the following code to embed the dialo in the OnInitDialog:
m_TabCtrl.InsertItem(0, _T("TAB1"));
m_TabCtrl.InsertItem(1, _T("TAB2"));
m_para1.Create(IDD_DIALOG1,GetDlgItem(IDD_MAINDIALOG));
m_para2.Create(IDD_DIALOG2,GetDlgItem(IDD_MAINDIALOG));
CRect rs;
m_TabCtrl.GetClientRect(&rs);
rs.top+=37;
rs.bottom+=8;
rs.left+=13;
rs.right+=7;
m_para1.MoveWindow(&rs);
m_para2.MoveWindow(&rs);
m_para1.ShowWindow(TRUE);
m_para2.ShowWindow(FALSE);
m_TabCtrl.SetCurSel(1);
By using this way, It can work in this case. But if I want to use this method in my SecondDialog, the non-main dialog, it cannot work. Can someone help me out? Thanks in advance.
When you create a modeless dialog box, try this:
m_para1.Create(IDD_DIALOG1,&m_TabCtrl);
m_para2.Create(IDD_DIALOG2,&m_TabCtrl);
The second parameter of the Create function is a point to the parent window object (of type CWnd) to which the dialog object belongs. The return type of the GetDlgItem function is HWND.
See following:
http://msdn.microsoft.com/en-us/library/tc46f3be.aspx
http://msdn.microsoft.com/en-us/library/kc6x1ya0.aspx

CMFCButton::SetToolTip(str) not work in OnInitDialog() and

I want my CMFCButton to show tooltip when mouse over.
It doesn't work if I use SetToolTip() method in OnInitDialog
CMFCButton* bt = ((CMFCButton*)GetDlgItem(IDC_MFCBUTTON1));
bt->SetTooltip(_T("tooltip"));
BUT it does work if I put this code in message handle function like another button's click handle.
What I want is that the CMFCButton could show tooltip when the dialog is created, where should I put these code?
========================
By the way, The tooltip text I set in the Property view does not work for most time.
I just derived a class
class CMyButton : public CMFCButton
{
public:
void SetDelayFullTextTooltipSet(bool DelayFullTextTooltipSet)
{
m_bDelayFullTextTooltipSet = DelayFullTextTooltipSet;
}
};
Instead of a CMFCButton variable on the Dialog class I use the button, I now have a CMyButton.
And in the OnInitDialog, after the SetTooltip call, I do
button.SetDelayFullTextTooltipSet(FALSE);
Have you called the base class' OnInitDialog()? The main point is that the control needs to be created before you call SetToolTip() on it. Step into OnInitDialog() with the debugger and see if m_hWnd of the control has a value at the moment you call SetToolTip().

Sharing variable among class instances

class MyApp : public CWinApp {
afx_msg OnPrefrences();
};
OnPrefrences() get called when user selects tools->Preference from the menubar.
Now in one dialog(Say DlgX) there is one button, on clicking this I need to open the Preference dialog which has in fact many panes, but here I need to open the Preference dialog by selecting one the these pane as active. Also in that particular pane I need to hide some of the controls only when It gets open through this the dialog not through menu.
So I have created one variable(Say m_varX) in MainFrm class.
void DlgX::OnButtonXClick()
{
CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
if(pFrame)
{
pFrame->m_varX = TRUE;
((CMyApp*)(AfxGetApp()))->OnPrefrences();
pFrame->m_varX = FALSE;
}
}
And in button handler of DlgX I have made this m_varX TRUE and call the OnPreference() and after closing of this preference dialog I have made m_varX FALSE.
All this is working fine... But the problem is that things gets clutter in mainFrm. Also the project I am working on is legacy one so I cant make much changes.
Is there any patter available for handling such case?
Thanks
You could solve this with a custom dialog (if you don't have it already)
When you show the dialog from the main menu i.e. onPreferences() you fill and show all 'panes'. you would have to do a custom dialog where the ctor takes some arguments.
E.g.
enum { all, part };
void MainFrame::OnPreferences()
{
CMyPreferences dlg( GetDocument(), all );
dlg.DoModal();
}
but when you call it from within a dialog you only fill in the parts you need.
void YourDialog::OnPreferences()
{
CMyPreferences dlg( GetDocument(), part );
dlg.doModal();
}
The argument could be something more sophisticated for more fine tuned configuration of what to show/allow to edit.
I think for that special case, even if sometimes is no more considered a pattern, the singleton pattern would work for you.

Configuring new document in MFC

When the user creates a new document in my SDI-application, I need to present a dialog specifying details on the document to be created (think: resolution, bit-depth, etc.) I initially put the code for displaying this dialog in OnNewDocument() (I don't need it when opening an existing document), but putting user-interface code in the document-class just doesn't feel right (also, I don't have any CWnd* to use as a parent for the dialog).
Is there a better place to do this in MFC?
You're right, the document class is no good place for UI.
CDocTemplate::[OpenDocumentFile][1](pszPath) looks like a better candidate:
pszPath==NULL means 'create a new document'.
The method is virtual -> Just derive CMySingleDocTemplate from CSingleDocTemplate and use an instance of this class in CMyWinApp::InitInstance().
This class is responsible for creating docs, frames and views, hence I think it's a good place to put a UI operation.
BOOL CMyWinApp::InitInstance()
{
...
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CMySingleDocTemplate( // <--Derives from CSingleDocTemplate
IDR_MAINFRAME,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CMyView));
AddDocTemplate(pDocTemplate);
...
}
CDocument* CMySingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
BOOL bMakeVisible)
{
CDocument *pDoc =
CSingleDocTemplate::OpenDocumentFile(lpszPathName, bMakeVisible);
if (lpszPathName==NULL)
{
// GUI to get user info
// update doc
m_pOnlyDoc->Blah(input);
// update view
m_pOnlyDoc->UpdateAllViews(NULL,...,...);
}
}
This might not be ideal though: In SDI, there is one and only doc object. It's re-used accross File/Load and File/New operation.
This function will then be called a first time before the initial mainframe is created. You may not want to have a dialog presented to user before the frame is created. Ouch! It's a little more complicated:
Instead of popping up a GUI in in OpenDocumentFile(NULL) as above, just post a custom message/command to the main frame. Then add a handler that will react by the sequence pop up GUI/update doc/update views. That way, the main frame will be displayed before the GUI is popped up and your user will be happier.
This also solves your problem where you don't have a CWnd parent: the main frame is already created and your dialog will use it byt default.
BTW, another solution consists in adding a command handler for ID_FILE_NEW in your CMyWinApp's message map and add your own override of OnFileNew(). But when you write OnFileNew(), I believe you'll quickly find out that it's an ugly solution :-(