Click to See Complete Forum and Search --> : MFC TabControl Pages


npuleio
September 14th, 2009, 03:04 AM
Hello everyone!!

I've created a MFC Dialog Application, and I put a tabcontrol on it, then I've read somewhere to manage with pages I have to create modeless dialog template and class turning off titlebar and border, so I did.
BUT, to put that modeless dialog template into the page of tabcontrol I've read also to use MoveWindow to position all of the dialogs on the control...what would that mean?...Since MoveWindow would change simply position and dimensions, how it would be used to put templates in tabcontrol's page?...

Thanks
Ciao,
Luigi

Igor Vartanov
September 14th, 2009, 06:51 AM
Of course you have to have all your dialogs already created (by templates you mentioned), and have them all invisible except the one you currently show up.

npuleio
September 14th, 2009, 07:34 AM
Of course you have to have all your dialogs already created (by templates you mentioned), and have them all invisible except the one you currently show up.

Yes in fact I did that...I removed titlebar and border plus I settled visible = false... but how I can put that template in tabcontrol's page?...

Igor Vartanov
September 14th, 2009, 11:23 AM
See this sample (http://www.codeguru.com/forum/showthread.php?p=1691227#post1691227). And forget about template. Template is a resource. Since a dialog is created (by a template), it's already window but not template.

npuleio
September 14th, 2009, 01:35 PM
See this sample. And forget about template. Template is a resource. Since a dialog is created (by a template), it's already window but not template.

Ehm, the link doesn't work....returns a 404 page....

Igor Vartanov
September 14th, 2009, 01:59 PM
Yep, sorry. :( Try this (http://www.codeguru.com/forum/showthread.php?p=1691227#post1691227) one.

npuleio
September 15th, 2009, 09:26 AM
Hiya Igor,

I saw the template but that example refers to a non-resource modeless CDialog, when I need to have a template resource because I put controls on each like EditBox, RichEdit..etc etc...
Actually I started with a main CDialog interface where I put from component's toolbox a tabcontrol and creating 4 tabpages...
Then I created four CDialog class templates with resource where I removed border (Border = none), titlebar and settled Style as Child.
In one of them I put another tabcontrol with 2 tabpages.
The issue I have actually is I made a ShowTabDlg function as following your example:

ShowTabDlg(int TabSel)
{
for(int idx=0; idx < ARRAYSIZE(m_dlg); idx++)
m_dlg[idx]->ShowWindow(SW_HIDE);

CRect rc;
pTabDlg->GetClientRect(rc);
pTabDlg->AdjustRect(FALSE, rc);
pTabDlg->ClientToScreen(rc);
m_dlg[tabSel]->SetWindowPos(NULL, rc.left, rc.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE);
}

and a OnSize (related to WM_SIZE message and ON_WM_SIZE() on begin_message_map) always for each tabpage:

OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);

CWnd* pWnd = GetDlgItem(IDC_TABPAGE1);
if (pWnd)
{
CRect rect;
pWnd->GetWindowRect(rect);
ScreenToClient(rect);
rect.right = cx - rect.left;
rect.bottom = cy - 10;
pWnd->MoveWindow(rect);
}
}

BUT I couldn't get those CDialog templates fit in each TabPage....it goes like in the bottom-right of the main window if main CDialog isn't maximized and when maximized it goes indeed at almost the top-left of the tabcontrol... what could I have missed?...

Igor Vartanov
September 15th, 2009, 07:52 PM
that example refers to a non-resource modeless CDialogMy sample deals with resource dialogs, you can easily see that in .rc file. :)

what could I have missed?You've missed to upload a sample project (you could take mine) along with comprehensible description of your problems (maybe including screenshots).

npuleio
September 21st, 2009, 08:25 AM
Hello Igor and everyone...

I figured out using easier's CPropertyPage and CPropertySheet which are similar to tabcontrol....
BUT Just a little doubt: since I want to have a container component to put some controls like edit box, buttons, labels and stuff so I can reposition the container at the center when I resize the form and there is no Panel... I was thinking about creating something like a Frame...but how I could create a frame by resource then putting it in the PropertyPage since I don't see something like IDD_FRAME or whatever in the Dialog Resources.... (IDD_DIALOGBAR, IDD_FORMVIEW, IDD_OLE_PROPPAGE_LARGE...)

Thanks
Ciao,
Luigi

Arjay
September 21st, 2009, 12:45 PM
In MFC, for each property page, you create a dialog resource with the frame style set to 'child'.

Then you create a class for the dialog derived from CPropertyPage.

In the later versions of visual studio, to create a class, just right click on the dialog when opened in the resource studio, and choose "Add Class...".

From there, choose CPropertyPage as the derived class.

This will create the necessary CPropertyPage class that can be used with a CPropertySheet.

In VC6, create the CPropertyPage derived class using the Class Wizard.

npuleio
September 21st, 2009, 06:35 PM
Hello Arjay,

I did that! Just I'd like to have a container to keep some controls inside so I can "center" the container when I resize the dialog application window which resizes also the propertysheets....
But I don't need to resize also the controls, indeed I need to center the controls in the propertysheet and I thought I'd do with a "container" like an IDD_FORMVIEW or so like it's a Frame container.... any idea?...

Thanks
Luigi

Arjay
September 21st, 2009, 08:03 PM
Not sure of your approach. What I would do is replace the main application dialog with the propertysheet dialog in CMyWinApp::InitInstance( ).

npuleio
September 22nd, 2009, 12:21 AM
I'm finding a way to have a container where to put some controls inside like edit box, labels, checkboxs because I tried to use a Group Box, then putting those controls inside and in OnSize of the CPropertyPage I put this:

CWnd* pWnd = GetDlgItem(IDC_GRP_BOX);
if (pWnd)
{
CRect rctDlg;

pWnd->GetWindowRect(&rectDlg);
ScreenToClient(&rectDlg);
pWnd->MoveWindow(rectDlg.left, rectDlg.top, cx - 2 * rectDlg.left, cy - rectDlg.top - rectDlg.left, TRUE);
}

but the GroupBox doesn't keep inside the controls and move them where the GroupBox goes... so that's why I'm looking for a way to have a controls container which I can center in the CPropertyPage. In this way I was thinking about something like a Frame with a fixed dimensions where to fill with those controls; then load the Frame inside the CPropertyPage so in the OnSize I can MoveWindow the frame in the center of the CPropertyPage.
So the question is how I can create a Frame-like with resources?...

Arjay
September 22nd, 2009, 10:03 AM
Groupbox isn't a control container like it is in a different environment like VB or .Net. In Win32 (i.e. MFC), GroupBox is just another control so you need to resize it like any other control.

When you need to resize several controls within the OnSize handler, use DeferWindowPos to help reduce flickering.

void CMyDialog::OnSize(UINT state, int cx, int cy)
{
HDWP hdwp = BeginDeferWindowPos(3);

if (hdwp) hdwp = DeferWindowPos(hdwp,
m_GroupBoxCtrl.GetSafeHwnd( ),
NULL, 0, 0, cx, cy,
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);

if (hdwp) hdwp = DeferWindowPos(hdwp,
m_NameFirstCtrl.GetSafeHwnd( ),
NULL, 10, 10, cx-20, 30,
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
if (hdwp) hdwp = DeferWindowPos(hdwp, m_NameLastCtrl.GetSafeHwnd( ),
NULL, 10, 50, cx-20, 30,
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
if (hdwp) EndDeferWindowPos(hdwp);}Note: the actual size params aren't correct - I just threw in some values for the example.

Igor Vartanov
September 23rd, 2009, 02:00 AM
I'm finding a way to have a container where to put some controls inside like edit box, labels, checkboxs because I tried to use a Group Box...The container name is... a dialog. ;) I have no idea why did you do that (finding a way to have a container other than the main dialog), but you always can have a child dialog window belonging to your main dialog. The evident demerit is: you need to have separate dialog procedure for a child dialog, and therefore, some way of communiction between the dialogs.

npuleio
September 23rd, 2009, 02:25 AM
Oh well... I abandoned the idea of child container for controls and I implemented MoveWindow for each control from a reference control calculating moving space difference then I used before and after LockWindowUpdate() and UnlockWindowUpdate() and it works.... :-) Thanks :-)

npuleio
September 24th, 2009, 04:35 AM
Hello again....

I'm trying to communicate between two CPropertyPage's pages...I tried to include the .h of the other page then doing this:

(CButton*) checkbasic = (CButton*)GetDlgItem(IDD_CONFIG_BASIC::IDC_CHECK_BASIC); <--- it's a checkbox
if (checkbasic->GetCheck() == BST_CHECKED)
CConfig_Basic::ActivateBasicControls(FALSE);

but seems it doesn't work since returns an illegal token on right side of '::' when calling GetDlgItem...and plus, looks like I can't call ActivateBasicControls method because if I declare methods as static I can't call the controls inside the function like GetDlgItem(IDC_CHK_PSE)...

Any suggest?...

Arjay
September 24th, 2009, 11:53 AM
There's really a quite simple approach in dealing passing data between property pages.

Most folks take the wrong approach and try to read data in the controls of one page, from another page. This is usually problematic, introduces complexity, and tight coupling between the pages. It's often a mess.

The simple approach is to copy the MFC doc/view architecture and treat the property sheet as the document and read/write the data to the propertysheet (i.e document).

By creating control variables (rather than using the old fashioned GetDlgItem method), you can leverage the DDX data xfer mechanism of MFC to read and write data to the 'document' variables contained in the property sheet as such:

void CPropPage1::DoDataExchange( CDataExchange* pDX )
{
ASSERT( NULL != m_pPropSheet );
CPropertyPage::DoDataExchange( pDX );

DDX_Text(pDX, IDC_NAME_FIRST, m_pPropSheet->GetNameFirst( ) );
DDX_Text(pDX, IDC_NAME_LAST, m_pPropSheet->GetNameLast( ) );
}

In the code above, the m_pPropSheet pointer is passed into each sheet, variable accessor methods are created around the data and the DDX entries read and write the data to the accessor method.

If another page needs some data from a different page, it simple calls the appropriate accessor method in the propertysheet.

Here's the code. See the PropPageDocument.zip (http://www.codeguru.com/forum/showthread.php?t=441832) attachment in my reply about 2/3 of the way down the page.

npuleio
October 1st, 2009, 10:43 AM
Hello again...

I've read about drawing stuffs on the device context so when I have to draw something on a control inside a CPropertyPage then I have to use OnCtlColor. BUT when I want to draw something, or to change background color of the canvas of CPropertyPage itself, how I can do?... If I call:


CDC* pDC = new CDC();
pDC->SetTextColor(RGB(255,0,0));

it doesn't change the background at all....ah I put this code inside BN_CLICKED event of a checkbox I put in this canvas...
Any suggest?...

Thanks!!
Luigi

Igor Vartanov
October 1st, 2009, 12:34 PM
CDC* pDC = new CDC();
pDC->SetTextColor(RGB(255,0,0));

it doesn't change the background at allDoesn't this sound any bells?

npuleio
October 2nd, 2009, 01:29 AM
Yea in fact I wanted to say SetBkColor... just it doesn't color anything when I click on a checkbox I have on the canvas...
I tried with CClientDC too but same result... putting also Invalidate(); before and UpdateWindow(); after....

Any suggest?...

hoxsiew
October 2nd, 2009, 11:04 AM
Hello again...

I've read about drawing stuffs on the device context so when I have to draw something on a control inside a CPropertyPage then I have to use OnCtlColor. BUT when I want to draw something, or to change background color of the canvas of CPropertyPage itself, how I can do?... If I call:


CDC* pDC = new CDC();
pDC->SetTextColor(RGB(255,0,0));

it doesn't change the background at all....ah I put this code inside BN_CLICKED event of a checkbox I put in this canvas...
Any suggest?...

Thanks!!
Luigi

You need to do any custom painting in a paint handler (WM_PAINT). Set a flag in your BN_CLICKED event and call Invalidate() or InvalidateRect(), then in your paint routine, check for the flag, and if set, paint your color, else paint it normally.

npuleio
October 5th, 2009, 10:46 AM
In fact you both of you, hoxsiew and Vartanov,are right: first I had to write SetBkColor...plus now I am trying do it in a MFC ActiveX Control so I can use that in different applications or windows...
but when I compile the component, even if I put a static Text Control and a Slider Control, when I put the component compiled in a MFC application test, it shows only a white rectangle when it should show those two controls and plus the MFC ActiveX Control has Style's property set as Child.... I thought it was maybe the absence of AfxEnableControlContainer(); but looks like it isn't that... maybe a certain project setting that I have missed?....

Thanks
Luigi