WIN MOBILE UI開發入門

來源:互聯網
上載者:User

首先感謝 『嵌入式平台安全』版塊版主加百力的邀請(貌似算不上邀請,表達不好,Whatever),才有了這篇文章的誕生,
在下才識有限,接觸WIN MOBILE開發時間不久,倉促整理了一些UI部分入門級的東東(內容並不系統,全面),希望能夠對剛涉足MOBILE開發的朋友有協助。         
註:由於自身局限,本文不涉及.net  
OK,廢話完畢,歡迎雞蛋和鮮花。

    
      本文假設您已經瞭解SMART PHONE與POCKET PC的區別。沒有特別說明,均指在POCKET PC上。
      現狀:IPHONE的風靡,引領了當前智能手機的系統及APP介面潮流。MS雖然發布了WINDOWS MOBILE 6.5,但在將來不短的 一段時間內,承載MOBILE 6.2及以下系統的PPC仍將是主流。手持功能的特殊性決定了其上APP介面表現的重要性,很多時候甚至項目70%的代碼 都與介面有關。
一。GDI繪圖基礎(必須掌握的基礎)
1.1   裝置環境DC
      “裝置環境”(device context),經常簡稱寫為DC, 是Windows 用來管理訪問顯示和列印裝置的工具。
1)   什麼是DC
        一個DC是一個結構,它定義了一系列繪圖物件的集合以及它們相關的屬性,以及影響輸出效果的一些圖形模式。
       這些繪圖物件包括一個畫線的筆,一個填充和painting的畫刷,一個用來向螢幕拷貝的位元影像,一個定義了一系列顏色集合的調色盤,一個用來剪裁等操作的地區。
       例如:使用TextOut,DC的屬性確定了文字的顏色、文字的背景色、顯示文字時字型等等。
如何理解DC:
DC用於繪圖輸出,輸出裝置包括螢幕,印表機等,在WM中一般總是螢幕輸出,總是與特定表單相關。實際上是GDI內部儲存的資料結構, DC中的有些值定義了GDI繪圖函數工作的細節。
2)   擷取裝置DC
一個應用程式從不直接地訪問(access)dc,常見的取得dc的方式:
HDC GetDC( HWND hWnd);
HDC GetWindowDC( HWND hWnd);
HDC GetDCEx( HWND hWnd, HRGN hrgnClip,DWORD flags);

Value    Description
DCX_WINDOW    返回與視窗矩形而不是與客戶矩形相對應的裝置上下文環境

      
DCX_CACHE    從快取而不是從OWNDC或CLASSDC視窗中返回裝置上下文環境。覆蓋CS_OWNDC和CS_CLASSDC。

DCX_PARENTCLIP(*)    使用父視窗的可見地區,父視窗的WS_CIPCHILDREN和CS_PARENTDC風格被忽略,並把裝置上下文環境的原點,設在由hWnd所標識的視窗的左上方。

DCX_CLIPSIBLINGS    排除hWnd參數所標識視窗上的所有子視窗的可見地區。

DCX_CLIPCHILDREN    排除hWnd參數所標識視窗上的所有子視窗的可見地區。

DCX_NORESETATTRS(*)    當裝置上下文環境被釋放時,並不重設該裝置上下文環境的特性為預設特性。

DCX_EXCLUDERGN    從返回裝置上下文環境的可見地區中排除由hrgnClip指定的剪下地區。

DCX_EXCLUDEUPDATE(*)    排除視窗更新地區.

DCX_INTERSECTRGN    The clipping region identified by hrgnClip is intersected with the visible region of the returned device context.

DCX_INTERSECTUPDATE    Returns a region that includes the window's update region

DCX_VALIDATE(*)    當與DCX_INTERSECTUPDATE一起指定時,致使裝置上下文環境完全有效,該函數與DCX_INTERSECTUPDATE和DCX_VALIDATE一起使用時與使用BeginPaint函數相同。.

1.2   有效區和無效區
Windows內部為每個視窗儲存一個「繪圖資訊結構」,這個結構包含了包圍無效地區的最小矩形的座標以及其它資訊,這個矩形就叫做「無效矩形」,或者「無效地區」。當重繪視窗時(收到WM_PAINT訊息),僅需重繪「無效地區」就可以 。
表單收到WM_PAINT訊息,
BeginPaint擷取無效地區的dc,計算無效地區,
重繪無效地區,
EndPaint函數,將無效地區標記為有效地區。
Windows不會將多個WM_PAINT訊息都放在訊息佇列中。WM_PAINT只會更新無效地區內資訊。在處理WM_PAINT訊息後,整個程式介面都變為有效地區,如果不對程式進行任何操作,它是不會產生無效地區的。引起WM_PAINT訊息的事件:
使用者移動視窗時,先前被覆蓋的視窗顯示時;
使用者調整視窗大小
使用ScrollDC等函數滾動視窗時
使用者模組發送WM_PAINT訊息(一般在InvaladataRECT 之後發送訊息)
WM_PAINT
case WM_PAINT:
             {
                 HDC hdc;
                 PAINTSTRUCT ps;
                 RECT rect;
                 hdc = BeginPaint(hwnd, &ps);
                 GetClientRect(hwnd, &rect);
                 DrawText(hdc, g_szMessage, -1,    &rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
              EndPaint (hwnd, &ps);
             }
             break;

將有效地區標記為無效地區
     BOOL InvalidateRect( HWND    hWnd,const RECT *lpRect, BOOL   bErase);
     InvalidateRect只是增加重繪地區,在下次WM_PAINT的時候才生效 。使無效地區立刻重繪:
InvalidateRect(…);
hWnd表單發出WM_PAINT的訊息,
         lpRect:是指定要重新整理的地區,此地區外的地區 不被重繪,這樣防止一個局部的改動,而導致整個用戶端區域重繪而導致閃爍。     
         BOOL   bErase的參數TRUE表示在無效地區重繪之前之前還向表單發送WM_ERASEBKGND訊息,這樣將導致,用背景色將所選地區覆蓋一次後再重繪,(背景色可通過設定BRUSH來改變)。
        
將無效地區標記為有效地區
可以通過呼叫ValidateRect函數使顯示地區內的任意矩形地區變為有效。如果這呼叫具有令整個無效地區變為有效效果,則目前隊列中的任何WM_PAINT訊息都將被刪除。
windows不會將多個WM_PAINT訊息都放在訊息佇列中。

1.3   位元影像
BMP(Bitmap-File)圖形檔案是Windows採用的 圖形檔案格式,在Windows環境下啟動並執行所有圖象處理軟體都支援BMP圖象檔案格 式。Windows系統內部各映像繪製操作都是以BMP為基礎的。 Windows 3.0以前的BMP圖檔案格式與顯示裝置有關,因此把這種BMP圖象 檔案格式稱為裝置相關位元影像DDB(device-dependent bitmap)檔案格式。Windows 3.0以後的BMP圖象檔案與顯示裝置無 關,因此把這種BMP圖象檔案格式稱為裝置無關位元影像DIB(device-independent bitmap)格式(註:Windows 3.0以 後,在系統中仍然存在DDB位元影像,象BitBlt()這種函數就是基於DDB位元影像的,只不過如果你想將映像以BMP格式儲存到磁碟檔案中時,微軟 極力推 薦你以DIB格式儲存),目的是為了讓Windows能夠在任何類型的顯示裝置上顯示所儲存的圖象。BMP位元影像檔案預設的副檔名是BMP或 者 bmp(有時它也會以.DIB或.RLE作副檔名)。

檔案結構:
位元影像檔案可看成由4個部分組成:位元影像檔案頭(bitmap-file header)、位元影像資訊頭(bitmap-information header)、彩色表(color table)和定義位元影像的位元組陣列,它具有如下所示的形式。
位元影像檔案的組成                      結構名稱                符號
位元影像檔案頭(bitmap-file header)    BITMAPFILEHEADER        bmfh
位元影像資訊頭(information header)    BITMAPINFOHEADER        bmih
彩色表(color table)               RGBQUAD                 aColors[]
圖象資料陣列位元組                  BYTE                    aBitmapBits[]

二:常用繪圖技巧
2.1 雙緩衝繪製技術:
限於手機的硬體效能,開發人員經常需要解決螢幕閃爍的問題,一般都可以通過雙緩衝繪製來解決。
所謂的雙緩衝就是把所有內容先繪製在一個記憶體DC上; 之後一次性拷到螢幕DC,作為最終顯示。 
記憶體DC,是一個虛擬記憶體裝置上下文,對它進行繪圖等操作,不會顯示在螢幕上,在記憶體DC繪製完成之後,再拷貝到螢幕上,這樣可以避免因為操作而給螢幕帶來的閃爍。
步驟:
HDC memdc = CreateCompatibleDC(hdc);//建立和目的DC一致的內DC
HBITMAP   hbmp;
hbmp= CreateCompatibleBitmap(hdc,rect.Width(),rect.Height());
SelectObject(memdc,bmp);     //建立一張螢幕DC的位元影像並選入記憶體DC
Drawmemdc (memdc) ;        //在記憶體DC繪圖
BitBlt(hdc,0,0,rect.right,rect.bottom,memdc,0,0,SRCCOPY);//繪製到螢幕DC
DeleteObject(memdc);        //銷毀資源,釋放記憶體DC

2。2映像半透明混合:
原理:操作像素點陣,假設一幅圖象是A,另一幅透明的圖象是B,那麼透過B去看A,看上去的圖象C就是B和A的混合圖象,設B圖象的透明度為alpha(取值為0-1,1為完全透明,0為完全不透明),Alpha混合公式如下:
R(C)=(1-alpha)*R(B)+alpha*R(A)
G(C)=(1-alpha)*G(B)+alpha*G(A)
B(C)=(1-alpha)*B(B)+alpha*B(A)

步驟:1:擷取原圖大小   2:擷取原始像素點陣   3:對各像素RGB分量進行混合  
for(int i=0;i<length;i++)
     {
     for(int t=0; t<width; t++ )
     {
         pix_array[i*width+t] = Getpixel(hdc,i,t);
     }
      }
     for(int i=0; i<length*width; i++)
      {
     newpix_array[i].byRed   = pix_array[i].byRed* alpha + 255*(1- alpha);

     newpix_array[i].byGreen   = pix_array[i].byGreen* alpha + 255*(1- alpha);

     newpix_array[i].byBlue = pix_array[i].byBlue* alpha + 255*(1- alpha);
       }
或者直接調用API:AlphaBlend

2.3背景色透明
調用API:TransparentBlt
BOOL TransparentBlt(
   HDC hdcDest,         //目的DC控制代碼
   int nXOriginDest,    //目的DC左上X軸座標
   int nYOriginDest,    //目的DC左上Y軸座標
   int nWidthDest,      //繪製時的矩形寬度
   int hHeightDest,     //繪製時的矩形高度
   HDC hdcSrc,          //源DC控制代碼
   int nXOriginSrc,     //源DC左上X軸座標
   int nYOriginSrc,     //源DC左上Y軸座標
   int nWidthSrc,       //源矩形寬度
   int nHeightSrc,      //源矩形高度
   UINT crTransparent   // 需要透明的顏色RGB值
);

三:PPC UI常見問題
3.1 手勢識別
原理:捕獲使用者觸筆點擊事件,收集觸筆運動軌跡,觸筆離開後綜合收集到的軌跡點,進行分析判斷。
基本實現:捕獲系統響應訊息,進行處理
單擊事件:WM_LBUTTONDOWN
移動事件:WM_MOUSEMOVE
彈起事件:WM_LBUTTONUP

常用技巧:
控制項聚焦 : 由於手持功能螢幕有限,控制項分布相對密集,對使用者操作的精準性有一定要求,當使用者進行捲軸的下拉或者其他行動控制項的動作時,很有可能在移動過程中觸筆或手指會離開控制項範圍,從而中斷移動操作,而這並非使用者所預期。
因此,有必要對控制項進行聚焦,即便出現上述狀況,控制項仍能收到WM_MOUSEMOVE事件。
解決該問題可調用API : SetFocus( HWND hWnd);

3.2介面自適應
由於POCKET PC支援橫豎屏兩種模式,在豎屏,橫屏間切換時,如果不對程式的控制項座標進行調整,會造成介面混亂的後果。
基本實現:捕獲系統的橫豎屏切換訊息,判斷將切換到何種模式,在OnSize()中進行相應處理。
常用方法:
另外由於PPC螢幕尺寸的繁雜,對不同螢幕尺寸的自適應也需要注意。此處不再贅述。

1):調整控制項座標
捕獲WM_SIZE訊息,在響應函數中擷取當前螢幕模式,根據螢幕大小對控制項座標進行調整,使整個介面自適應。

2):準備兩套不同UI資源
針對橫豎屏各準備一套UI資源,在WM_SIZE訊息的處理函數中擷取當前螢幕模式,根據不同模式調用相應UI資源,達到介面自適應的目的。

3.3 螢幕輸入面板(sip)
在POCKET PC上進行應用開發時,並非所有介面都需要SIP輸入面板,因此經常需要對SIP輸入面板的顯示和隱藏處理。
下面以直觀的圖給出兩者的對比:

在WINDOWS MOBILE中隱藏SIP的方法很多,以下簡要介紹其中幾種方法:
1)SHSipPreference(m_hWnd,SIP_Down);
2)SIPINFO si;
    memset(&si,sizeof(si));
    SHSipInfo(SPI_GETSIPINFO,0,&si,0);
    si.fdwFlags&=~SIPF_ON;
    SHSipInfo(SPI_SETSIPINFO,0,&si,0);
3) SHFullScreen(hDlg,SHFS_SHOWTASKBAR,SHFS_HIDESIPBUTTON);
4)SipShowIM(SIPF_DOWN);
5) 獲得視窗名為menu_worker的SIP視窗控制代碼,進行隱藏或顯示,實現:
CWnd* pWndSIP = FindWindow( _T("menu_worker"), 0 );
   if ( pWndSIP )
   {
     pWndSIP->ShowWindow(SW_HIDE);// SW_SHOW
   }

6)另外通過IMM也可以對SIP進行控制。

3.4   MenuBar定製
MOBILE底部的MenuBar在應用程式中扮演著和使用者互動的關鍵作用,根據不同的需求,經常需要定製MenuBar,本節將介紹如何對MenuBar資源變更。
基本操作:
1. SHMENUBARINFO結構體
typedef struct tagSHMENUBARINFO {
    DWORD          cbSize;       // SHMENUBARINFO結構體大小
    HWND           hwndParent;   //CommondBar父視窗控制代碼
    DWORD          dwFlags;     //MenuBar類型標識
    UINT             nToolBarId;   //工具列標識
    HINSTANCE       hInstRes;     //控制資源的執行個體控制代碼
    int                nBmpId;      // 按鈕背景bmp圖片資源ID
    int                cBmpImages; //bmp圖片資源數量
    HWND            hwndMB;     //【輸出參數】控制MenuBar的視窗控制代碼
COLORREF   clrBk;             //MenuBar背景顏色參數,包括SIP()
} SHMENUBARINFO,*PSHMENUBARINFO;

2.MenuBar類型
可以通過對dwFlags的設定,建立不同類型的MenuBar
SHCMBF_COLORBK           設定menu bar背景顏色
SHCMBF_EMPTYBAR       建立一個空的menu bar
SHCMBF_HIDDEN           建立一個隱藏的menu bar
SHCMBF_HIDESIPBUTTON    建立一個沒有sip的menu bar
SHCMBF_HMENU               通過資源定製menu bar而不通過工具列

3.MenuBar的建立

SHMENUBARINFO mbi;
memset(&mbi, 0, sizeof(SHMENUBARINFO));
mbi.cbSize      = sizeof(SHMENUBARINFO);
mbi.hwndParent = hWnd;//視窗控制代碼
mbi.nToolBarId = IDR_MENU;//菜單資源號
mbi.hInstRes    = g_hInst;//執行個體控制代碼
SHCreateMenuBar(&mbi)
g_hWndMenuBar = mbi.hwndMB;

建立完MenuBar執行個體之後,再對資源檔進行修改,指定
IDR_MENU SHMENUBAR DISCARDABLE
BEGIN
     IDR_MENU, //ID
     2,//個數
     I_IMAGENONE, IDM_OK/*COMMAND ID*/,
     TBSTATE_ENABLED,
     TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE/*按鈕或快顯功能表*/,
    IDS_OK/*字元*/,
     0, NOMENU,
      I_IMAGENONE,IDM_HELP,TBSTATE_ENABLED, TBSTYLE_DROPDOWN|TBSTYLE_AUTOSIZE,
     IDS_HELP, 0, 0,
END
IDR_MENU SHMENUBAR DISCARDABLE
BEGIN
     IDR_MENU,
     1,
     I_IMAGENONE, IDM_OK, TBSTATE_ENABLED,
      TBSTYLE_BUTTON |TBSTYLE_AUTOSIZE,
    IDS_OK, 0, NOMENU,
END
通過以上操作,開發人員可以給自己的程式定製個人化的MenuBar。

四:定製控制項
這是當前MOBILE開發很重要,也很讓開發人員頭疼的一個問題,有很多可以說但一下子說完貌似又不現實。大體來說,主要分為控制項自繪,以及“偽控制項”。

所幸,大部分控制項和案頭系統一致,碰到有關控制項的自繪和偽控制項的實現問題,相關資料網路上都能找到不少,故在此不再展開。(combobox和案頭系統不同,MOBILE上不支援自繪)
如果覺得描述的不夠具體可以看看下面的連結,是一些筆者曾製作的UI:http://hi.baidu.com/%C0%B6%C9%AB%D3%...5a044df04.html
其中 “按鈕GO”就是BUTTON控制項自繪
另外的COMBOBOX及顯示資料的表格控制項,都是用STATIC控制項實現的偽控制項。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.