QWinClass是本人開發的一套適用於CE5.0的觸摸屏UI類,其主要內容是對CWnd的繼承,對CDC的操作,以及窗體消息的過濾組合,從技術上而言這並不算複雜,只是對MFC的簡單操作,但的確是需要耗費時間的,主要是爲了備忘,在我的BLOG上寫點相關的技術難點(可能只是對我而言)。
此UI系統總的構建思路有多種,在我寫好並已應用的類裏,我是基於一個CDialog的DC來創建全部的窗體(大概十來個吧),我一開始的思路是以內存來換顯示速度,但使用到後面,內存開銷過大,因爲主類基本成型,想在內存吃緊的情況下動態delete一些DC資源相當有難度,於是我回想起我的QWinClass1.0時的辦法——在資源裏創建一個CDialog類,然後在類裏作其他操作,其方便的地方是,你可以很隨意地創建跟關閉一個Dialog,這在內存有限的情況下很有用,畢竟如果程序都沒辦法使用,談何刷圖速度呢?基於此想法,我再擴展一下我的UI類。
創建一個窗口,當然不想在資源面板裏手動添加,那實在不方便工程的協作,我是越來越喜歡純代碼的東西了,如果懂得繼承,搭建好父類,子類的代碼量可以足夠的少。好吧,接下來說實際操作。
可以使用VS的類嚮導創建一個基於CWnd的類CQBaseWnd,生成的CPP及H文件裏有一些原生代碼,主要是用於映射的,可以不管,照留着就好,然後重載OnCreate、PostNcDestroy、OnPaint函數,稍作添加,如下所示:
- //2013-1-12 重新修改代碼,添加關閉窗體函數
- ///////////////////////////////////////////////////
- //QBaseWnd.h
- ///////////////////////////////////////////////////
- #pragma once
- #include "afxwin.h"
- class CQBaseWnd : public CWnd
- {
- DECLARE_DYNAMIC(CQBaseWnd)
- private:
- //父窗體指針
- CWnd * _pParentWnd;
- //背景顏色
- COLORREF _crBackup;
- //窗體尺寸
- CRect _rcWnd;
- public:
- //默認構造函數
- CQBaseWnd(void);
- //析構函數
- virtual ~CQBaseWnd(void);
- //顯示窗體
- BOOL ShowWnd();
- //窗體創建函數
- BOOL Create(CWnd * pParentWnd, COLORREF crBackup, CRect rcWnd);
- //關閉窗體
- BOOL Close();
- private:
- //響應創建消息
- afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
- //響應重繪消息
- afx_msg void OnPaint();
- //創建窗體
- BOOL CreateWnd(CWnd * pParentWnd = NULL);
- protected:
- DECLARE_MESSAGE_MAP()
- //註銷窗體
- virtual void PostNcDestroy();
- };
- ////////////////////////////////////////////////////
- //QBaseWnd.cpp
- ////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "QBaseWnd.h"
- // CQBaseWnd
- //動態聲明類
- IMPLEMENT_DYNAMIC(CQBaseWnd, CWnd)
- //默認構造函數
- CQBaseWnd::CQBaseWnd()
- {
- }
- //析構函數
- CQBaseWnd::~CQBaseWnd()
- {
- }
- BEGIN_MESSAGE_MAP(CQBaseWnd, CWnd)
- ON_WM_CREATE()
- ON_WM_PAINT()
- END_MESSAGE_MAP()
- // CQBaseWnd 消息處理程序
- //響應創建消息
- int CQBaseWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
- {
- if (CWnd::OnCreate(lpCreateStruct) == -1)
- return -1;
- // TODO: 在此添加您專用的創建代碼
- CenterWindow();
- return 0;
- }
- //註銷窗體時必須調用Destroy()函數
- void CQBaseWnd::PostNcDestroy()
- {
- // TODO: 在此添加專用代碼和/或調用基類
- CWnd::PostNcDestroy();
- }
- //自建窗體的函數
- BOOL CQBaseWnd::CreateWnd(CWnd* pParentWnd)
- {
- LPCTSTR strSplashWndClass;
- strSplashWndClass = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, 0, 0, 0);
- return CreateEx(0,strSplashWndClass,NULL, WS_POPUP|WS_VISIBLE, 0, 0, this->_rcWnd.Width(), this->_rcWnd.Height(), pParentWnd->GetSafeHwnd(), NULL);
- }
- //自定義的窗體創建函數
- BOOL CQBaseWnd::Create(CWnd * pParentWnd, COLORREF crBackup, CRect rcWnd)
- {
- this->_pParentWnd = pParentWnd;
- this->_rcWnd = rcWnd;
- this->_crBackup = crBackup;
- if (!CreateWnd(pParentWnd))
- {
- delete this;
- return FALSE;
- }else{
- return TRUE;
- }
- }
- //關閉窗體,必須調用DestroyWindows()
- BOOL CQBaseWnd::Close()
- {
- this->DestroyWindow();
- return TRUE;
- }
- //顯示窗體
- BOOL CQBaseWnd::ShowWnd()
- {
- // 顯示啓動畫面
- if (!CreateWnd(AfxGetMainWnd())) {
- delete this;
- return FALSE; }
- UpdateWindow();
- return TRUE;
- }
- void CQBaseWnd::OnPaint()
- {
- CPaintDC dc(this); // device context for painting
- // TODO: 在此處添加消息處理程序代碼
- // 不爲繪圖消息調用 CWnd::OnPaint()
- CBrush br = CBrush(this->_crBackup);
- dc.FillRect(CRect(0, 0, this->_rcWnd.Width(), this->_rcWnd.Height()), &br);
- }
要顯示此窗體時,這樣用法:
- CTestDlg * pWnd = new CTestDlg();
- pWnd->ShowWnd();
顯示的窗體長怎麼樣,就看你在OnPaint()作了什麼操作了,我這裏只是刷了一片純色而已,大家可以詳細研究一下AfxRegisterWndClass與CWnd::CreateEx的用法。窗口生成後可以自行調用ShowWindows()來顯示或隱藏窗體。
需要提醒一下,我這沒寫關閉窗體的代碼,如果需要關閉,一定要使用DestroyWindow,否則會造成內存泄漏。