Custom Control derived from CWnd won't paint inside CFormView Wind

Tech Tip: Click here to run a free scan for Windows Errors and optimize PC performance



Hi all.

I'm wanting to use a CFormView in a Doc/View project that contains several
comboboxes, textboxes, and a custom control. The custom control is not
painting when I run the program.

Using the dialog resource editor, I have created a resource called
IDD_AZURE_FORM, and placed my common controls on it. In addition, I have
dropped a custom control on it, and set the following properties:

Class = CDualTreeViewerCtrl
Disabled = False
ExtendedStyle = 0x0
Group = False
ID = IDC_DUALTREE
Style = 0x50010000
Tabstop = True
Visible = True

Prior to this, I had created a CWnd derived window called CDualTree that
will be used for my custom control. The following code it the CDualTree
header:

#pragma once

#define DUALTREEVIEWER_CLASSNAME _T("CDualTreeViewerCtrl")

class CDualTree : public CWnd
{
DECLARE_DYNAMIC(CDualTree)

public:
CDualTree();
virtual ~CDualTree();

public:
virtual void OnDraw(CDC* pDC);

protected:
BOOL RegisterWindowClass();

protected:
DECLARE_MESSAGE_MAP()
};

The following file is the implementation file. Please note I'm registering
the window in the Constructor.

IMPLEMENT_DYNAMIC(CDualTree, CWnd)

CDualTree::CDualTree()
{
RegisterWindowClass();
}

CDualTree::~CDualTree()
{
}

void CDualTree::OnDraw(CDC* pDC)
{
// paint code omitted...
}

BOOL CDualTree::RegisterWindowClass()
{
WNDCLASS wndcls;
HINSTANCE hInst = AfxGetInstanceHandle();

// Register Window Class on first time use.
if (!(::GetClassInfo(hInst, DUALTREEVIEWER_CLASSNAME, &wndcls)))
{
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = DUALTREEVIEWER_CLASSNAME;

if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}

return TRUE;
}

BEGIN_MESSAGE_MAP(CDualTree, CWnd)
END_MESSAGE_MAP()

Now, from what I have been able to find out online, the steps required to
sync these two up is the following:

From the resource editor, I generate a CFormView class using the class
wizard. I then add a member variable for my Custom Control using the Add
variable function.

The following class header for CAzureView is the result of those two actions:

#pragma once
#include "dualtree.h"

class CAzureView : public CFormView
{
protected: // create from serialization only
CAzureView();
DECLARE_DYNCREATE(CAzureView)

public:
enum{ IDD = IDD_AZURE_FORM };

// Attributes
public:
CAzureDoc* GetDocument() const;

// Operations
public:

// Overrides
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
virtual void OnInitialUpdate(); // called first time after construct

// Implementation
public:
virtual ~CAzureView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// Generated message map functions
protected:
afx_msg void OnFilePrintPreview();
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
DECLARE_MESSAGE_MAP()
public:
CDualTree m_dualTree;
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
};

#ifndef _DEBUG // debug version in AzureView.cpp
inline CAzureDoc* CAzureView::GetDocument() const
{ return reinterpret_cast<CAzureDoc*>(m_pDocument); }
#endif

Please note it's created the CDualTree m_dualTree member variable.

The following is the implementation file for the header:

#include "stdafx.h"
#include "Azure.h"

#include "AzureDoc.h"
#include "AzureView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


IMPLEMENT_DYNCREATE(CAzureView, CFormView)

BEGIN_MESSAGE_MAP(CAzureView, CFormView)
ON_WM_CREATE()
END_MESSAGE_MAP()

///////////////////////////////////////////////////////////////////////////////
// CAzureView construction/destruction

CAzureView::CAzureView()
: CFormView(CAzureView::IDD)
{
}

CAzureView::~CAzureView()
{
}

void CAzureView::DoDataExchange(CDataExchange* pDX)
{
CFormView::DoDataExchange(pDX);
DDX_Control(pDX, IDC_DUALTREE, m_dualTree);
}

BOOL CAzureView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs



return CFormView::PreCreateWindow(cs);
}

void CAzureView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
ResizeParentToFit();
}

void CAzureView::OnRButtonUp(UINT nFlags, CPoint point)
{
ClientToScreen(&point);
OnContextMenu(this, point);
}

void CAzureView::OnContextMenu(CWnd* pWnd, CPoint point)
{
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x,
point.y, this, TRUE);
}

///////////////////////////////////////////////////////////////////////////////
// CAzureView diagnostics

#ifdef _DEBUG
void CAzureView::AssertValid() const
{
CFormView::AssertValid();
}

void CAzureView::Dump(CDumpContext& dc) const
{
CFormView::Dump(dc);
}

CAzureDoc* CAzureView::GetDocument() const // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CAzureDoc)));
return (CAzureDoc*)m_pDocument;
}
#endif //_DEBUG

///////////////////////////////////////////////////////////////////////////////
// CAzureView message handlers

int CAzureView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFormView::OnCreate(lpCreateStruct) == -1)
return -1;

m_dualTree.Create(_T("CDualTreeViewerCtrl"), _T(""), WS_VISIBLE,
CRect(0,0,100,100), this, 1);

return 0;
}

The code added is the called to m_dualTree.Create() in the ::OnCreate
function.

Now, when I run the program, the view loads fine, but the CDualTree window
is not drawn in the middle of the CFormView. However, if I look at the window
with Spy++, it's actually there, it's just not being painted. A break point
on the OnDraw function is never hit.

The interesting thing is, if I remove the m_dualTree.Create call in
CAZureView::OnCreate, I still get the same behaviour, i.e. in Spy++ the
window is still there, just not being drawn.

I'm not sure if the ::OnCreate call is even needed, however I thought it was
required to set the correct styles, parent etc?

Any suggestions would be greatly appreciated!

Cheers

Jason
.


Quantcast