去年用VC做了一個仿Win8 Metro風格的界面,感覺挺有意思,最近打算把實作過程和一些技術原理記錄下來。
主要是風格上類似Win8,其實功能上很多借鑒了Android的操作方式。界面隻支援兩種大小的Metro磁鐵。
原創博文,轉載請标明出處:http://www.cnblogs.com/mythou/p/3157205.html
1、主要實作了以下功能:
- 手指滑動切換頁面。
- 圖示位置交換。
- 從全部清單拖動添加到首頁面。
- 首頁面按鈕拖動添加删除操作。
- 首頁面按鈕拖動添加到導航欄上。
- 背景更換
下面是一張最終桌面效果圖:
程式是運作在Wince上,不過是使用MFC開發,是以對PC開發也是同用。
2、類圖關系
要實作滑動操作和按鈕拖動操作最基本的就是需要有一個支援滑動拖動的按鈕。VC上微軟的Button拖動效率太
低而且不好操作,是以很多重載Button類的控件都用不了。做嵌入式開發,需要一個絢麗點的界面,基本隻有一條
路徑,就是重繪。是以我們這裡使用的按鈕和其他控件都是基于重繪的。
做這個界面主要時為了兼顧程式健壯性,是以使用了MVC模式,所有界面元素都是獨立于對話框,我把它們
都放在一個DUIInterface的目錄下。還有一點這個界面邏輯是基于DirectUI的思想來做,基于一個窗體上繪
畫不同的視窗和控件。不過這個并沒有完整的使用DirectUI,消息分發方面還沒有獨立處理,仍然依賴視窗
的消息隊列。
先把我界面結構類圖畫出來:
3、基類CDUIBase
CDUIBase是所有類的基類,是一個虛基類,提供了基本的點選接口、滑動接口、繪畫控件接口
/*************************************************
2012. Co., Ltd.
Edited by OWL
Class name: CDUIBase
Description:
繪圖控件基類,定義了繪畫操作的動作
*************************************************/
#pragma once
class CDUIBase
{
public:
CDUIBase(void);
~CDUIBase(void);
public:
//畫圖
virtual void Draw(CDC * pDC);
//響應視窗OnLButtonDown
virtual BOOL OnLButtonDown(POINT point);
//響應視窗OnLButtonUp
virtual void OnLButtonUp(POINT point);
//響應視窗OnMouseMove
virtual int OnMouseMove(POINT point, CDC * pDC, CDC * pBackDC);
};
VC裡面界面響應回調主要就是依靠OnLButtonDown、OnLButtonUp、OmMouseMove。這三個回調函數
基本構成了是以界面操作的基礎。不僅僅是VC,其他的軟體界面響應,其實底層都是基于這三個接口,然後根據
這三個接口資料就可以延伸出很多界面操作,例如手勢操作。最近也在研究Android手勢支援部分子產品,Android
的手勢支援很好,很多手勢動作都可以識别出來。例如基本的滑動,按下拖動等等。不過這些操作都可以利用
OnLButtonDown、OnLButtonUp、OmMouseMove來混合實作。(多點觸摸手勢除外,這個需要底層螢幕驅動支援)。
例如判斷手指向右拖動,可以根據OnLButtonUp的X坐标減去OnLButtonDown裡面X坐标,得到結果如果是正數,
證明向右滑動,至于滑動距離也可以算出來。如果加上up和down之間的響應時間,就可以計算出這次滑動的速度是多少。
4、按鈕類CDUIButton
這個Button類代碼比較多,我就不貼出來了。主要就是繼承實作CDUIBase裡面的四個接口,另外因為Button點選
一般要處理事情,是以增加一個回調函數,在OnLbuttonUp的時候調用。
//定義點選按鈕的響應回調函數
typedef void (CALLBACK* DUIBtnCallBack)(CWnd *pWnd, CString cmd, CString name, CString Animate);
pWnd是回調的視窗,cmd是按鈕按下的識别指令,name是按鈕名稱,Animate是按鈕按下需要執行的動畫。
這幾個可以根據需要調整,加入動畫是為了操作看上去比較流暢。自從iPhone出來以後,做界面不加動畫就是反人類 -_-!
class CDUIButton: public CDUIBase
{
public:
CDUIButton(void);
~CDUIButton(void);
private:
//按鈕區域
CRect m_btnRc;
//标題的區域
CRect m_FontRc;
//按鈕未選中狀态圖檔路徑
CString m_btnPic;
//按鈕選中狀态圖檔路徑
CString m_btnPicSel;
//按鈕動畫效果圖檔路徑
CString m_AnimatePic;
//按鈕打開動畫
CString m_AnimateType;
//點選按鈕識别指令行
CString m_BtnClickCMD;
//按鈕按下狀态,TRUE為按下
BOOL m_ClickState;
//是否處于滑動
BOOL m_mouseMove;
//PNG圖檔正常狀态透明度
BYTE m_Alpha;
//PNG圖檔按下透明度
BYTE m_AlphaSel;
//字型大小
int m_fontSize;
//..........
public:
//初始化按鈕
void CreateBtn(CWnd * OwerWnd, HWND mainWnd, CString btnPic, CString btnPicSel, CRect rc);
//畫圖
void Draw(CDC * pDC);
//響應視窗OnLButtonDown
BOOL OnLButtonDown(POINT point);
//響應視窗OnLButtonUp
void OnLButtonUp(POINT point);
//響應視窗OnMouseMove
int OnMouseMove(POINT point, CDC * pDC, CDC * backDC);
//畫按鈕的名稱
void DrawBtnText(CDC * pDC);
//..........
};
上面是定義的CDUIButton的一部分屬性和方法,按鈕一般都有按下、焦點、不可用、普通和點選5種狀态。
不過我這裡隻需要用到普通和按下兩種狀态,是以隻有兩種屬性,如果有需要可以把其他狀态都加入進去。
這種隻是一種虛拟的按鈕,簡單來說就是定義螢幕某個區域,然後在這個區域貼一張圖檔,如果你點選了這張圖檔,
把圖檔重新整理成點選的狀态,然後執行某個操作。就完成了一個按鈕需要做的事情。至于按鈕的資料是使XML配置,
然後讀取XML配置的時候解析XML自動生成這個按鈕對象,再放到管理容器裡面。這方面的内容,後面會分開說明。
使用這種自繪的Button的好處就是,你要拖動這個按鈕,其實隻是拖動一張圖檔,整個系統消耗是很小的。
如果你要拖動重載的微軟控件,還涉及閃爍、拖動慢、重新整理慢等問題。例如下面的截圖,我把電子詞典這個按鈕
拖動出來,其實隻要繪畫一張圖檔就可以。
按鈕都是用PNG圖檔來顯示,是以操作的時候都加入了半透明效果,至于PNG圖檔顯示和使用,我已經寫了兩篇文章,
有興趣的可以看看:
1、Wince PNG貼圖類:
http://www.cnblogs.com/mythou/archive/2013/06/13/3133606.html
2、Wince/VC高效PNG貼圖,自定義Alpha算法:
http://www.cnblogs.com/mythou/p/3150396.html
今天就先說到這裡,其他邏輯實作,我會後面接着寫。
PS:代碼問題,這個項目因為是公司的項目,是以代碼無法上傳,我後面會自己寫一個demo,然後上傳上來。
發現那裡寫錯的朋友,歡迎留言指出!