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;
}
開發識别螢幕方向的應用程式
我們先來看下微軟的“今日”設定界面。
上面這兩個圖分别是肖像模式和風景畫模式的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一個如下對話框。
。
用OptimizeListRight來對其到右邊。nIDPrimaryCtl為清單控件,cControlCount為其他控件個數。在WM_SIZE中添加
CScreenLib::OptimizeListRight(hDlg, IDC_LIST, 2, IDC_SEND, IDC_DELETE);
這樣實作了控件的又靠其。但是發現下面兩個按鈕沒顯示出來。我們使用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);
運作結果如下:
這樣圖示已經下對其了。但是”向右”按鈕沒有和删除按鈕右對其。接口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);
運作效果如下:
CScreenlib在
http://download.csdn.net/source/1630242