Custom Control derived from CWnd won't paint inside CFormView Wind
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