1
votes

Using Visual Studio 2013, I created a dialog resource using the resource editor. It is a child control with no border and is just a collection of radio buttons, push buttons, and static text. I want to turn this into a custom control in order to place this in several different locations. Let's call this a "Panel".

I then created a regular dialog and using the Toolbox "Custom Control", defined an area for the Panel. The Panel registers itself and has a valid window handle.

I used the following example: https://www.codeproject.com/Articles/521/Creating-Custom-Controls

The parent's DDX gets hit and the _panel is properly instantiated:

MyDialog::DoDataExchange(CDataExchange* pDX)
{
   CDialog::DoDataExchange(pDX)
   DDX_Control(pDX, IDC_CUSTOM_PANEL, _panel)
}

I read that I need to override the OnPaint() and OnEraseBkgnd(CDC* pDC) methods so the Panel class has these but they are empty. I do not have any custom painting to do as the Panel contains nothing but regular buttons.

What do I have to include in OnPaint()?

I also noticed that none of the member buttons are instantiated in the Panel like would normally happen in a dialog's DoDataExchange method. Instead, I've had to resort to dynamically creating each of the control's inside the Panel's PreSubclassWindow() method:

void MyPanel:PreSubclassWindow()
{
   _groupBox.Create(_T("Options"), WS_CHILD|WS_VISIBLE|BS_GROUPBOX, CRect(11, 11, 112, 231), this, IDC_STATIC_GROUPBOX);

   //... do this for every dialog element??? seems like overkill...

   CWnd::PreSubclassWindow()
}

Why do I need to do this when I've already defined/designed the Panel and each of its controls in the resource editor?

If I do not do this in the PreSubclassWindow method, nothing will appear on the dialog.

Any help is appreciated. Thanks.

1

1 Answers

1
votes

The article says override OnPaint and OnEraseBkgnd if you want to change the functionality. It doesn't say you have to override always.

Just remove ON_WM_PAINT and ON_WM_ERASEBKGND, remove OnPaint and OnEraseBkgnd if you don't need them. Or call the base class implementations if you are not making any changes:

void MyPanel::OnPaint() { CWnd::OnPaint(); }
BOOL MyPanel::OnEraseBkgnd(CDC* pDC) { return CWnd::OnEraseBkgnd(pDC); }

This will show a blank control with nothing in it, unless you add a child window to _panel as you have done in MyPanel:PreSubclassWindow

You are adding _groupBox to _panel. And you are adding _panel to the MyDialog.

MyDialog::DoDataExchange(...){DDX_Control(pDX, IDC_CUSTOM_PANEL, _panel)} is needed to invoke SubclassWindow for _panel. That in turn calls _groupBox.Create.

If MyPanel::OnPaint and MyPanel::PreSubclassWindow are not doing anything MyPanel appears as a blank control.

... do this for every dialog element??? seems like overkill...

You can directly add _groupBox to the main dialog. But if you want to add specific controls within MyPanel then you have to do it manually.

You can also create a child dialog within a main dialog. For example that's how a tab control works.