天天看點

Windows Mobile 開發識别螢幕方向的應用程式

Windows Mobile 開發識别螢幕方向的應用程式

編寫目的:

    現在Windows Mobile的螢幕分辨率支援非常多。最新的Windows Mobile6.5支援

240*240,240*320,240*400,320*320,480*480,480*640,480*800,480*854。當我們開發的窗體程式想适應如此多的分辨率時,往往要為一個對話框建立多個對話框模闆。最常用的方法就是用RelayoutDialog。來重新layout對話框。這樣使我們陷入了不斷的擺放控件,然後編譯檢視效果。往往為了支援,方屏、肖像模式、風景畫模式要建立三個模闆。此文的目的就是用代碼的方式來Layout窗體,使支援不同的分辨率。

更改螢幕方向:引MSDN

通常,螢幕方向僅在使用者使用“螢幕方向”控制台,或按下某硬體按鈕來旋轉螢幕時才改變。

此外,應用程式也可通過 ChangeDisplaySettingsEx 函數以程式設計方式更改螢幕方向。該函數使用方法見 MSDN 中“Rotating the Content of the Screen”(旋轉螢幕内容的方向)一文。例如,如果使用的應用程式隻能在豎向模式下操作,則可通過程式設計改變螢幕方向。但是,如果螢幕方向的改變很突然,通過程式設計改變螢幕方向會讓使用者搞不清楚。應用程式應始終要求使用者在旋轉螢幕前确認顯示模式。

為了在豎向模式下顯示,将 dmDisplayOrientation 字段中的 DEVMODE 結構設定為 DMDO_0。對于右手橫向模式,使用 DMDO_270。對于左手橫向模式,使用 DMDO_90

應用程式視窗如何識别螢幕方向:引MSDN

螢幕方向如果改變,或當“輸入面闆”出現時,應用程式的所有全屏頂層視窗都要适應新的取向。

注意: 如果視窗的上、左、右坐标在工作區域邊界之上或之外,該視窗被認為是全屏視窗。工作區域是标題欄下的整個螢幕區域。頂層視窗是無父視窗的視窗,即有一個 NULL 父視窗。

如果視窗大小改變,視窗将收到 WM_SIZE 通知。WM_SIZE 消息的 lParam 參數的低位字指定了用戶端區域的新寬度,高位字指定了用戶端區域的新高度。應用程式應識别視窗大小的改變,并相應地更新視窗布局。此外,也應重新确定所包含任何子視窗的布局。

如果應用程式沒有全屏視窗,它收不到 WM_SIZE 通知。相反,它應在 wParam 參數設定為 SETTINGCHANGE_RESET 時監聽 WM_SETTINGCHANGE消息。

注意: 如果應用程式有頂層視窗,或使用 SHHandleWMSettingChange、SHInitDialog 和 SHFullScreen 方法建立了視窗,它會同時收到 WM_SIZE 和 WM_SETTINGCHANGE 消息。但是,如果應用程式建立了子視窗,子視窗收不到 WM_SIZE 消息,即使子視窗是全屏視窗。

以下 WindowProc 模闆的代碼示例利用了 WM_SIZE 和 WM_SETTINGCHANGE 消息。

    switch (uMessage)

    {

        case WM_SIZE:

            // 重新計算所有子視窗的布局;重新設定

            // 列出視圖和編輯框的大小,重新确定按鈕、

            // 靜态文字和其他控件的位置。

            break;

        case WM_SETTINGCHANGE:

            if (SETTINGCHANGE_RESET == wParam) {

                // 螢幕方向改變。此時

                // 執行 WM_SIZE 不能執行的處理,

                // 如重新調整全屏子視窗的大小,對

                // 頂層視窗調用 MoveWindow 等等。

                // 如果不需要處理 WM_SETTINGCHANGE 消息,可以

                // 忽略它。

            }

            break;

      }

開發識别螢幕方向的應用程式

    我們先來看下微軟的“今日”設定界面。

Windows Mobile 開發識别螢幕方向的應用程式
Windows Mobile 開發識别螢幕方向的應用程式

上面這兩個圖分别是肖像模式和風景畫模式的UI布局。如果用DRA中的RelayoutDialog來實作,我們起碼需要兩個對話框模闆。代碼如下

WM_SIZE:

DRA::RelayoutDialog(

            g_hInst,

            hDlg,

            DRA::GetDisplayMode() != DRA::Portrait ? MAKEINTRESOURCE(IDD_TODAY_WIDE) : MAKEINTRESOURCE(IDD_TODAY));

如果要你放到方屏的機器上,你又要添加一個對話框模闆。并要修改相應的代碼。

WM_SIZE:

{

UINT uIDDialog= IDD_TODAY_WIDE;

Switch(DRA::GetDisplayMode())

{

DRA::RelayoutDialog(

          g_hInst,

          hDlg,

          DRA::GetDisplayMode() == DRA::Portrait ? MAKEINTRESOURCE(IDD_TODAY) : (DRA::GetDisplayMode() == DRA::Square? MAKEINTRESOURCE(IDD_ TODAY_SQUARE):MAKEINTRESOURCE(IDD_TODAY_WIDE));

}

用RelayoutDialog來開發支援螢幕方向應用十分的麻煩。那麼有沒有通過代碼實作,用一個對話框模闆就可以實作的呢。

我們可以來分析下上面的兩個Layout好的對話框。可以發現右邊的三個按鈕”上移”、“下移”、“選項”都是靠右的。而最下面的Checkbox和Combox。是下靠其的。然後中間留出的位置給list view來擺放。上面的對話框從肖像模式到風景畫模式可以這樣改變。

向右對于控件實作如下:

1.     記錄要移動控件的位置

2.     找出除list view,最left和最right的控件。标記為MinLeft,MaxRight

3.     計算最right的控件移動右邊的位移。并儲存為MoveX. MoveX =(rcClient.right - nMargin) - MaxRight.right. nMargin為邊緣空白的距離,預設設定為8個像素。

4.     儲存最left控件到list控件的距離,并儲存,這樣保證list控件到其他控件的相對位置不變。cListMargin = MinLeft.left - rcPrimary.right;

5.     根據計算出的MoveX,把所有控件向右移動MoveX(除list).

6.     計算list控件的寬度。MinLeft.left - cListMargin + MoveX - rcPrimary.left

7.     高度不變,左上頂點左邊不變。用MoveWindow改變寬度。

同樣的,向下對其也是同樣的道理。

之前在網上看到過一個CScreenlib的類,是用來Layout窗體的。我在其基礎上擴充了三個比較實用的接口

static void DockControl(HWND hwndDlg, UINT nIDAffectedCtl, DockType nType = dtFill);

static void OptimizeWidth(HWND hwndDlg, int cAffectedCtls, UINT nIDAffectedCtl, ...);

static void OptimizeHeight(HWND hwndDlg, UINT nIDAffectedCtl);

 static void AlignControls(HWND hwndDlg, AlignType nType, int cAffectedCtls, UINT nIDFixedCtl, UINT nIDAffectedCtl, ...);

static void MakeSameSize(HWND hwndDlg, SizeType nType, int cAffectedCtls, UINT nIDFixedCtl, UINT nIDAffectedCtl, ...);

static void OptimizeListRight(HWND hwndDlg, UINT nIDPrimaryCtl, int cControlCount, ...);

static void OptimizeListBottom(HWND hwndDlg, UINT nIDPrimaryCtl, int cControlCount, ...);

static void AlignFixControls(HWND hwndDlg, AlignType nType, UINT nIDPrimaryCtl, int cControlCount, ...);

下面來介紹下各個函數的使用方法。

DockControl: 自動拉伸

OptimizeWidth: 自動把控件拉伸到右邊

OptimizeHeight:把控件拉伸到底部

AlignControls:其他控件根據nIDFixedCtl的位置向左、向右、向下、向上對其。

MakeSameSize:使其他跟nIDFixedCtl一樣大小

關于上面這幾個函數的使用,見MSDN視訊

下面介紹下

OptimizeListRight、OptimizeListBottom和AlignFixControls

OptimizeListRight把一組控件和list控件向右靠其

我們在VS2005中layout一個如下對話框。

Windows Mobile 開發識别螢幕方向的應用程式

用OptimizeListRight來對其到右邊。nIDPrimaryCtl為清單控件,cControlCount為其他控件個數。在WM_SIZE中添加

CScreenLib::OptimizeListRight(hDlg, IDC_LIST, 2, IDC_SEND, IDC_DELETE);

Windows Mobile 開發識别螢幕方向的應用程式
Windows Mobile 開發識别螢幕方向的應用程式

這樣實作了控件的又靠其。但是發現下面兩個按鈕沒顯示出來。我們使用OptimizeListBottom來進行按鈕的下對其。

在WM_SIZE中添加

CScreenLib::OptimizeListRight(hDlg, IDC_LIST, 2, IDC_SEND, IDC_DELETE);

CScreenLib::OptimizeListBottom(hDlg, IDC_LIST, 3, IDC_CHECK,  IDC_LEFT, IDC_RIGHT);

運作結果如下:

Windows Mobile 開發識别螢幕方向的應用程式
Windows Mobile 開發識别螢幕方向的應用程式

這樣圖示已經下對其了。但是”向右”按鈕沒有和删除按鈕右對其。接口AlignFixControls

把一組控件對其到某個控件,nIDPrimaryCtl為目标控件。這組控件間的相對位置不變,如果是向右對其,則把這組控件最右的控件對其到目标控件,然後移動其他控件,并保持這組控件相對位置不變。

在WM_SIZE中添加

CScreenLib::OptimizeListRight(hDlg, IDC_LIST, 2, IDC_SEND, IDC_DELETE);

CScreenLib::OptimizeListBottom(hDlg, IDC_LIST, 3, IDC_CHECK,  IDC_LEFT, IDC_RIGHT);

CScreenLib::AlignFixControls(hDlg, CScreenLib::atRight,IDC_DELETE, 2,IDC_LEFT, IDC_RIGHT);

運作效果如下:

Windows Mobile 開發識别螢幕方向的應用程式
Windows Mobile 開發識别螢幕方向的應用程式

CScreenlib在

http://download.csdn.net/source/1630242