CView继承类,和其他窗口类的区别,很重要的就是对CDocument类和CFrameWnd类的操作,而其中,涉及CDocument类的操作,都进行了有效性判断(m_pDocument != NULL),CView类初始化的时候,m_pDocument = NULL,因此并不影响CView类作为控件的使用。涉及CFrame类的操作,有这么几个地方:
第一个地方:CView::OnDestroy()。
- void CView::OnDestroy()
- {
- CFrameWnd* pFrame = GetParentFrame();
- if (pFrame != NULL && pFrame->GetActiveView() == this)
- pFrame->SetActiveView(NULL); // deactivate during death
- CWnd::OnDestroy();
- }
第二个地方:CView::OnActivateFrame()。
- void CView::OnActivateFrame(UINT /*nState*/, CFrameWnd* /*pFrameWnd*/) { }
这里,其实是空的,在CView继承类中,只有CFormView类继承了这个虚函数
- void CFormView::OnActivateFrame(UINT nState, CFrameWnd* /*pFrameWnd*/)
- {
- if (nState == WA_INACTIVE) SaveFocusControl(); // save focus when frame loses activation
- }
实际上都不需要真的CFrame指针,对CView类作为控件使用没有障碍。
第三个地方:CView::OnMouseActivate()。
- int CView::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
- { int nResult = CWnd::OnMouseActivate(pDesktopWnd, nHitTest, message); if (nResult == MA_NOACTIVATE || nResult == MA_NOACTIVATEANDEAT) return nResult; // frame does not want to activate CFrameWnd* pParentFrame = GetParentFrame(); if (pParentFrame != NULL) { // eat it if this will cause activation ASSERT(pParentFrame == pDesktopWnd || pDesktopWnd->IsChild(pParentFrame)); // either re-activate the current view, or set this view to be active CView* pView = pParentFrame->GetActiveView(); HWND hWndFocus = ::GetFocus(); if (pView == this && m_hWnd != hWndFocus && !::IsChild(m_hWnd, hWndFocus)) { // re-activate this view OnActivateView(TRUE, this, this); } else { // activate this view pParentFrame->SetActiveView(this); } } return nResult; }
另外,在CView::PostNcDestroy(),实现了CView类的自我销毁,这是因为CView类是可以动态生成的(DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE)。
// self destruction
void CView::PostNcDestroy()
{ // default for views is to allocate them on the heap
// the default post-cleanup is to 'delete this'.
// never explicitly call 'delete' on a view delete this;
}
基本上,修改了CView继承类的这几个地方,直接返回不要调用基类相应的成员函数,就可以在对话框上使用。
下面举例,用向导生成对话框应用程序,对话框类为CMyDigalog。
从CHTMLView类继承一个CHTMLCtrl类,建立相应的消息处理函数并修改以下几个地方:
- // CHTMLCtrl 消息处理程序
- int CHTMLCtrl::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
- {
- return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, message);
- //return CHtmlView::OnMouseActivate(pDesktopWnd, nHitTest, message);
- }
- void CHTMLCtrl::OnDestroy()
- { //CHtmlView::OnDestroy();
- CWnd::OnDestroy();
- }
- void CHTMLCtrl::PostNcDestroy()
- { // TODO: 在此添加专用代码和/或调用基类
- //CHtmlView::PostNcDestroy();
- }
- void CHTMLCtrl::OnActivateFrame(UINT nState, CFrameWnd* pDeactivateFrame)
- { // TODO: 在此添加专用代码和/或调用基类
- //CHtmlView::OnActivateFrame(nState, pDeactivateFrame);
- }
增加一个成员函数CreateFromCtrl:
public: BOOL CreateFromCtrl(UINT nID, CWnd* pParent);
这个函数通过对话框上的控件创建一个CHTMLCtrl控件,目的是在对话框设计的时候便于布局:
- BOOL CHTMLCtrl::CreateFromCtrl(UINT nID, CWnd* pParent)
- {
- if (!pParent || !pParent->GetSafeHwnd())
- return FALSE;
- CWnd *pCtrl = pParent->GetDlgItem(nID);
- if (!pCtrl)
- return FALSE;
- CRect rcCtrl;
- pCtrl->GetWindowRect(rcCtrl);
- pParent->ScreenToClient(rcCtrl);
- UINT style = ::GetWindowLong(pCtrl->GetSafeHwnd(), GWL_STYLE);
- pCtrl->DestroyWindow();
- return Create(NULL, NULL, style | WS_CHILD | WS_VISIBLE, rcCtrl, pParent, nID, NULL);
- }
还应注意,默认的从CView继承的类,其构造函数和析构函数是protected的,需要修改成public。
public: CHTMLCtrl(); // 动态创建所使用的受保护的构造函数
virtual ~CHTMLCtrl();
然后,在对话框模板中(使用资源编辑器),插入一个Static Text控件,ID为IDC_HTML。
在对话框头文件中,插入包含文件: #include "htmlctrl.h"
增加CHTMLCtrl类型的成员变量: CHTMLCtrl m_ctlHTML;
在对话框初始化的时候,创建这个CHTMLCtrl控件:
- BOOL CMyDialog::OnInitDialog()
- {
- CDialog::OnInitDialog();
- ...
- m_ctlHTML.CreateFromCtrl(IDC_HTML, this);
- return TRUE;
- }
下面,再添加一个按钮,在按钮的消息响应函数中打开HTML文件:
- void CMyDialog::OnSysCommand(UINT nID, LPARAM lParam)
- {
- if ((nID & 0xFFF0) == IDM_ABOUTBOX)
- {
- CAboutDlg dlgAbout;
- dlgAbout.DoModal();
- } else {
- CDialog::OnSysCommand(nID, lParam);
- }
- }