程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Windows 編程[23] - 快捷鍵資源

Windows 編程[23] - 快捷鍵資源

編輯:Delphi

 提示:

  1、因為加入快捷鍵, 本例的基礎代碼和以前不同了; 因為窗體初始化時要先載入快捷鍵資源, 還要攔截快捷鍵消息另作處理.

  2、關於快捷鍵的話題, 以前接觸過不少了, 但那些都不是本質:

  注冊系統級熱鍵

  所有可選的快捷鍵列表

  快捷鍵設置控件

  快捷鍵的記錄方式

  3、我曾經以為快捷鍵不過就是攔截鍵盤消息, 現在看來那是想得太簡單了; 很容易就可以說明: 鍵盤消息是需要焦點的, 而快捷鍵是只對主窗口.

  4、使用快捷鍵前應該先建立一個快捷鍵表或建立快捷鍵資源, 本例使用了後者.

  快捷鍵一般是執行菜單的功能, 那它是怎麼和菜單掛接的呢? 很簡單: 給每一項快捷鍵和每一個菜單項指定相同的標識即可!

  5、在本例中, 窗口建立後, 先用 LoadAccelerators 載入快捷鍵資源並返回快捷鍵資源句柄 hAcc;

  GetMessage 從消息隊列中取出消息後, 先用 TranslateAccelerator 檢查是否是快捷鍵消息. 如果是, TranslateAccelerator 會把此快捷鍵消息轉換成菜單消息(WM_COMMAND, 也可能是系統菜單消息: WM_SYSCOMMAND), 然後直接發送給窗口; 如果不是, 再繼續以前的消息傳遞.

  其實快捷鍵消息的本質也是鍵盤消息, 不過 TranslateAccelerator 會檢查鍵盤消息的組合是否是我們定義的快捷鍵. 但我們在執行快捷鍵時, 焦點未必就在主窗口, 它是怎麼吧其他窗口的鍵盤消息轉給主窗口的呢?

 如果 GetMessage 函數的第二個參數為 0 時, 它會檢索程序中所有窗口的消息, TranslateAccelerator 接過來後, 不管消息來自那個窗口, 都把消息包中的窗口句柄換成主窗口句柄再傳遞.

  關於快捷鍵資源文件還是解釋在資源文件下面吧...

  本例效果圖:

Windows 編程[23] - 快捷鍵資源

  本例使用的資源文件(TestRes.rc):

MyMenu1 MENUEX
BEGIN
 POPUP "菜單"
 BEGIN
  MENUITEM "菜單_1t Shift+1"      ,101
  MENUITEM "菜單_2t Ctrl+2"      ,102
  MENUITEM "菜單_3t Alt+3"       ,103
  MENUITEM "菜單_4t Shift+Ctrl+Alt+4" ,104
  MENUITEM "菜單_5t 5"         ,105
  MENUITEM "菜單_6t F5"        ,106
  MENUITEM "菜單_7t Ctrl+A"      ,107
  MENUITEM "菜單_8t Alt+A"       ,108 
 END
END

MyAccel ACCELERATORS
BEGIN
 "1",  101, VIRTKEY, SHIFT,        NOINVERT
 "2",  102, VIRTKEY, CONTROL,       NOINVERT
 "3",  103, VIRTKEY, ALT,         NOINVERT
 "4",  104, VIRTKEY, SHIFT, CONTROL, ALT, NOINVERT
 "5",  105, VIRTKEY, NOINVERT,      NOINVERT
 VK_F5, 106, VIRTKEY, NOINVERT,      NOINVERT
 "A",  107, VIRTKEY, CONTROL
 "a",  108, ASCII,  ALT 
END


注釋:

  1、快捷鍵資源文件關鍵字: ACCELERATORS, 需要取個名給程序中的 LoadAccelerators 使用, 這裡是: MyAccel.

  2、快捷鍵資源文件可以有五組參數, 從後面說: NOINVERT 是讓被激活的菜單的頂層菜單不閃爍(但我去掉也沒看出來).

  它前面是控制鍵: SHIFT、CONTROL、ALT.

  再前面有兩個選擇: VIRTKEY、ASCII, VIRTKEY 指示快捷鍵要用 虛擬鍵碼 說明; ASCII 指示用 ASCII 碼說明快捷鍵. 譬如例子中的 VK_F5 就是典型的虛擬鍵碼. 但常規數字鍵和字母鍵沒有對應的虛擬鍵碼, 對數字(非小鍵盤數字)來講, 這兩者沒有區別; 特別注意: VIRTKEY 時指示的字母須大寫、ASCII 指示的字母須小寫.

  3、這其中最重要的就是第二個參數了, 它必須和菜單的標識相對應.

  4、另外, 菜單資源也和以前有點區別: 在 t (Tab 的意思) 後面用文本說明了對應的快捷鍵, 不過這只是顯示效果而已, 有沒有都不影響功能.

  本例代碼文件:

program Project1;

{$R 'TestRes.res' 'TestRes.rc'}

uses
 Windows, Messages;

{收到 WM_COMMAND 消息時需要做的工作}
procedure OnCommand(h: HWND; wParam: Integer);
var
 W: Word;
 arr: array[Byte] of Char;
begin
 W := LoWord(wParam);
 case W of
  101..108: begin
   GetMenuString(GetMenu(h), W, arr, Length(arr), MF_BYCOMMAND);
   SetWindowText(h, arr);
  end;
 end;
end;

function WndProc(wnd: HWND; msg: UINT; wParam: Integer; lParam: Integer): Integer; stdcall;
begin
 Result := 0;
 case msg of
  WM_COMMAND : OnCommand(wnd, wParam); {收到 WM_COMMAND 消息後調用 OnCommand 過程}
  WM_DESTROY : PostQuitMessage(0);
 else
  Result := DefWindowProc(wnd, msg, wParam, lParam);
 end;
end;

function RegMyWndClass: Boolean;
var
 cls: TWndClass;
begin
 cls.style     := CS_HREDRAW or CS_VREDRAW;
 cls.lpfnWndProc  := @WndProc;
 cls.cbClsExtra  := 0;
 cls.cbWndExtra  := 0;
 cls.hInstance   := HInstance;
 cls.hIcon     := 0;
 cls.hCursor    := LoadCursor(0, IDC_ARROW);
 cls.hbrBackground := HBRUSH(COLOR_WINDOW + 1);
 cls.lpszMenuName := 'MyMenu1';
 cls.lpszClassName := 'MyWnd';
 Result := RegisterClass(cls) <> 0;
end;

{程序入口}
const
 tit = 'New Form';
 ws = WS_OVERLAPPEDWINDOW;
 x = 100; y = 100; w = 300; h = 180;
var
 hWnd: THandle;
 Msg : TMsg;
 hAcc: HACCEL; {定義快捷鍵資源句柄}
begin
 RegMyWndClass;
 hWnd := CreateWindow('MyWnd', tit, ws, x, y, w, h, 0, 0, HInstance, nil);
 ShowWindow(hWnd, SW_SHOWNORMAL);
 UpdateWindow(hWnd);

 hAcc := LoadAccelerators(HInstance, 'MyAccel'); {載入快捷鍵資源}

 while(GetMessage(Msg, 0, 0, 0)) do
 begin
  if (TranslateAccelerator(hwnd, hAcc, Msg) = 0) then {攔截並處理快捷鍵消息}
  begin
   TranslateMessage(Msg);
   DispatchMessage(Msg);
  end;
 end;
end.



  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved