| 導購 | 订阅 | 在线投稿
分享
 
 
 

實現一個熱鍵注冊編輯的類

來源:互聯網網民  2006-01-31 23:49:32  評論

實現一個熱鍵注冊編輯的類

CST(http://blog.csdn.net/mrtechno) 2005-8-19


1 文檔目的... 1
2 熱鍵編程基礎... 1
2.1 API函數... 1
2.2 編程方法... 2
3 實現概述... 4
4 實現細節... 4
4.1 XML配置文檔結構... 4
4.2 熱鍵編輯控件 ThotKeyEdit 5
4.3 熱鍵自定義窗體類TformHotKeyconfig. 6
4.4 主類ThotKeyConfig. 6
4.4.1 解析XML文檔... 7
4.4.2 注冊注銷系統熱鍵... 8
4.4.3 熱鍵編輯窗體... 8
4.4.4 對象唯一性... 8
5 程序源代碼... 9
6 小結... 25
6.1 沒有解決的一些問題... 25
6.2 程序心得... 26

1 文檔目的本文檔介紹了在Delphi 7中注冊、注銷、使用熱鍵(Hot Key)的基本函數和方法,並在此基礎上介紹了一個熱鍵控制的類THotKeyConfig。該類可以從指定的xml配置文檔中讀入熱鍵配置信息,並在程序指定的位置注冊、注銷、修改熱鍵。

本文將不涉及XML文檔的讀寫方法,也不會詳述控件開發的方法。如果您對這些內容不了解,推薦您先略讀一下相關的文章。關于xml文檔的解析,可以到我的blog找到文章。

2 熱鍵編程基礎2.1 API函數在Delphi7中使用熱鍵要用到如下幾個函數:

//注冊熱鍵

BOOL RegisterHotKey(

HWND hWnd, // 接受熱鍵消息的窗口句柄

int id, // 熱鍵ID

UINT fsModifiers, // 按鍵組合整數

UINT vk // 案件虛擬鍵碼VK

);

其中fsModifiers 值如下:

1: M_strDisplay:='Alt + ';

2: M_strDisplay:='Ctrl + ';

3: M_strDisplay:='Ctrl + Alt + ';

4: M_strDisplay:='Shift + ';

5: M_strDisplay:='Shift + Alt + ';

6: M_strDisplay:='Ctrl + Shift + ';

7: M_strDisplay:='Ctrl + Shift + Alt + ';

//注銷熱鍵

BOOL UnregisterHotKey(

HWND hWnd, //接受熱鍵消息的窗口句柄

int id //熱鍵ID

);

注銷時,根據注冊時賦予的熱鍵ID進行注銷,因此在注冊時必須保證ID唯一。

關于這兩個WIN32 API函數的具體說明可以參考WIN32 SDK文檔。

2.2 編程方法基本的熱鍵編程方法是定義2個窗體過程,和一個消息響應函數:

Procedure HotKeyOn;

Procedure HotKeyOff;

procedure HotKeyDown(var Msg: Tmessage); message WM_HOTKEY;

在HotKeyOn過程中調用API函數注冊熱鍵,代碼可以是這樣的:

procedure TfrmMain.HotKeyOn;

begin

HKStep := 1;

HKScreen := 2;

HKComponent := 3;

HKShowMain := 4;

HKShowOI := 5;

if not RegisterHotKey(Handle, HKStep, MOD_CONTROL, Ord('C')) then

showmessage('can not register the hotkey "Ctrl-C"');

if not RegisterHotKey(Handle, HKScreen, MOD_CONTROL, Ord('V')) then

showmessage('can not register the hotkey "Ctrl-V"');

if not RegisterHotKey(Handle, HKComponent, MOD_CONTROL, Ord('B')) then

showmessage('can not register the hotkey "Ctrl-B"');

if not RegisterHotKey(Handle, HKShowMain, MOD_CONTROL, VK_F11) then

showmessage('can not register the hotkey "Ctrl-F11"');

if not RegisterHotKey(Handle, HKShowOI, MOD_CONTROL, VK_F12) then

showmessage('can not register the hotkey "Ctrl-F12"');

end;

在HotKeyOff過程中調用API函數注銷熱鍵,代碼可以是這樣的:

procedure TfrmMain.HotKeyOff;

begin

UnRegisterHotKey(handle, HKStep);

UnRegisterHotKey(handle, HKScreen);

UnRegisterHotKey(handle, HKComponent);

UnRegisterHotKey(handle, HKShowMain);

UnRegisterHotKey(handle, HKShowOI);

end;

在HotKeyDown消息處理函數中判斷系統消息,根據不同的熱鍵組合執行響應的語句,代碼可以是這樣的:

procedure TfrmMain.HotKeyDown(var Msg: Tmessage);

begin

if (Msg.LParamHi = Ord('C')) and (Msg.LParamLo = MOD_CONTROL) then

ShowMessage('"Ctrl-C"')

else if (Msg.LParamHi = Ord('V')) and (Msg.LParamLo = MOD_CONTROL) then

ShowMessage('"Ctrl-V"')

else if (Msg.LParamHi = Ord('B')) and (Msg.LParamLo = MOD_CONTROL) then

ShowMessage('"Ctrl-B"')

else if (Msg.LParamHi = VK_F11) and (Msg.LParamLo = MOD_CONTROL) then

ShowMessage('"Ctrl-11"')

else if (Msg.LParamHi = VK_F12) and (Msg.LParamLo = MOD_CONTROL) then

ShowMessage('"Ctrl-12"')

end;

如果系統熱鍵數量少、穩定不變,則適合使用這種方法。如果系統熱鍵較多,而軟件需求又要求熱鍵可以由用戶設置修改,則需要有一個自動化管理的模塊來實現。因此我在學習了如上的方法後實現了一個熱鍵自動管理的類。

3 實現概述實現這個熱鍵管理類我定義了1個記錄體和3個類。可以將熱鍵配置信息保存在一個獨立的xml文檔中,也作爲子樹加入到應用程序的配置文檔中。

記錄體ThotKeyStatus保存從XML配置樹中讀入的熱鍵記錄,該記錄體的數組變量將被整個單元文件內的對象所共享。

類ThotKeyEdit是一個自定義的控件,用于接受用戶輸入的熱鍵組合,一方面轉化爲系統可以接受的形式,另一方面也給用戶一個即時反饋。

類TformHotkeyConfig是一個窗體類,該窗體類將根據從XML中讀入的熱鍵配置動態創建ThotKeyEdit控件,提供用戶查看和修改熱鍵。

類ThotKeyConfig是我們要使用和直接訪問的類,它提供一個後台操作的功能,用戶在引入該類後可以選擇在程序指定位置讀入XML配置文件、生效熱鍵配置、打開TformHotKeyConfig提供的編輯窗體、保存配置到XML文件。另外該類在編程上爲了控制對象的唯一性,采用了類方法MgetInstance來獲得唯一對象,關于用類方法控制對象唯一性的方法可以參考我blog中的文章。

4 實現細節4.1 XML配置文檔結構XML配置文檔的結構可以如下:

<?xml version="1.0" encoding="UTF-8"?>

<configure>

<hotkeys>

<hotkey>

<caption>添加SCREEN</caption>

<hkid>101</hkid>

<mod>2</mod>

<vk>49</vk>

</hotkey>

<hotkey>

<caption>新建STEP</caption>

<hkid>102</hkid>

<mod>2</mod>

<vk>50</vk>

</hotkey>

</hotkeys>

</configure>

其中,<hotkeys>爲保存熱鍵配置的節點的子樹樹根。每個<hotkey>子樹記錄一個熱鍵配置。

caption爲熱鍵名稱,將顯示在TformHotKeyConfig實例中的ThotKeyEdit對象的標題位置。

Hkid爲熱鍵唯一標識,對應上文API函數中的ID值,該值必須局部唯一。

Mod爲熱鍵模式,對應上文API函數中的fsModifier值。

Vk爲熱鍵虛擬鍵碼,對應上文API函數中的VK值。

4.2 熱鍵編輯控件 ThotKeyEdit該控件的聲明如下:

//---------------------------------------

// 熱鍵編輯控件

//---------------------------------------

THotKeyEdit = class(TLabeledEdit)

private

//當前控件接收到的熱鍵組合是否合法

FKeySetValid:Boolean;

//組合鍵

FModValue:Integer;

//虛擬鍵碼

FVirtualKeyValue:Integer;

//修改合法後顯示的顔色

FValidateColor:TColor;

//用來覆蓋OnExit事件的函數

procedure LostFocusEvent(Sender:TObject);

//用來覆蓋OnKeyDown事件的函數

procedure GetHotKeyDownEvent(Sender: TObject; var Key: Word; Shift: TShiftState);

//將熱鍵數據轉換爲直觀文字

function GetDisplayText:string;

//熱鍵組合合法執行的代碼

procedure ActionOnHotKeyValid;

//熱鍵組合非法執行的代碼

procedure ActionOnHotKeyInvalid;

public

//覆蓋構造函數

constructor Create(AOwner: TComponent); override;

//外部請求將內部數據表現爲直觀文字

procedure DisplayHotKey;

published

property HasValidKeySet:boolean read FKeySetValid;

property VirtualKeyValue:integer read FVirtualKeyValue write FVirtualKeyValue;

property KeyModValue:integer read FModValue write FModValue;

end;

ThotKeyEdit控件繼承自TlabeledEdit控件,包含一個顯示熱鍵名稱的LABEL和一個只讀的EDIT區,在該區將顯示用戶輸入的熱鍵組合。控件的OnKeyDown事件被GetHotKeyDownEvent過程重寫,在該過程中捕捉用戶按下的按鍵組合,先將捕捉到的鍵位信息保存到私有字段中,然後調用GetDisplayText函數判斷私有字段中的鍵位是否合法,並且返回由這些信息轉換得到的熱鍵字串。合法性將保存在一個私有布爾字段FKeySetValid中。

對于用戶提供的熱鍵布局,如果可以接受則控件edit區會變色,如果不能接受則會在失去焦點時清除內容,並恢複默認顔色。

4.3 熱鍵自定義窗體類TformHotKeyconfig該窗體類繼承自Tform類,並需要UnitHotkeyConfigClass.dfm資源文件的支持。

類的聲明代碼如下:

//---------------------------------------

// 熱鍵設定窗體

//---------------------------------------

TFormHotkeyConfig = class(TForm)

GroupBoxLeft: TGroupBox;

PanelRight: TPanel;

ButtonYes: TButton;

ButtonNo: TButton;

procedure ButtonYesClick(Sender: TObject);

procedure ButtonNoClick(Sender: TObject);

private

//用來保存動態創建的THotKeyEdit控件的對象列表

FEditList:TObjectList;

public

constructor Create(AOwner: TComponent); override;

end;

該類重寫了構造方法,並在構造方法中根據從xml中讀入的熱鍵個數動態創建和初始化響應數量的ThotKeyEdit控件,因此需要一個私有成員FeditList來維護控件數組。

4.4 主類ThotKeyConfigThotKeyConfig的聲明如下:

//---------------------------------------

// 主類:提供熱鍵注冊和編輯功能

//---------------------------------------

THotkeyConfig = class (TComponent)

private

//如果用戶自定義配置文件路徑則記錄它

FAssociatedXML : String;

//配置窗體對象

FConfigureForm : TFormHotkeyConfig;

//熱鍵響應窗體引用

FWindow : TWinControl;

//定位到保存熱鍵記錄的XML子樹樹根

function XMLGetKeysetFather(AXML:TXMLDocument):IXMLNode;

//隱藏的構造函數

constructor Create(AOwner: TComponent);override;

public

//獲得對象

class function MGetInstance(AOwner:TWinControl):THotKeyConfig;

//讀入XML配置文件

function LoadConfigFromXML(const AXMLFile:string='hotkey.xml'):boolean;

//保存配置

function SaveConfigToXML(const AXMLFile:string='hotkey.xml'):boolean;

//注冊所有熱鍵設置

function EnableAllHotkeys:Boolean;

//注銷熱鍵

procedure DisableAllHotkeys;

//打開配置窗口

procedure OpenConfigWindow;

published

property WindowHandlesHotkey : TWinControl write FWindow;

end;

在該類中主要完成如下幾個功能:

1. 讀寫解析XML配置文件

2. 注冊注銷系統熱鍵

3. 提供熱鍵修改窗體的入口

4. 通過類方法和類變量,管理類的對象在應用程序中的唯一性

4.4.1 解析XML文檔因爲XML文檔結構相對簡單因此使用TXMLDocument類來實現,在LoadConfigFromXML方法中通過XMLGetKeysetFather函數定位到Hotkey節點,這樣如果XML結構位置改變,只需要修改XMLGetKeysetFather函數就可以。讀出的熱鍵記錄將保存到靜態變量FkeyInfo和FkeyInfoCount中,他們是ThotKeyStatus的數組和計數器。

4.4.2 注冊注銷系統熱鍵兩個對象方法負責自動完成熱鍵的注冊和注銷:EnableAllHotkeys和DisableAllHotkeys。

熱鍵注冊時從FkeyInfo數組中讀入鍵位信息並調用WIN32 API函數RegisterHotKey注冊熱鍵,如果注冊成功則返回true。

在RegisterHotKey中需要一個窗體句柄來接受系統消息WM_HOTKEY,因此在調用EnableAllHotkeys之前需要爲屬性WindowHandlesHotkey賦一個窗體的引用值。或者在MgetInstance方法的參數中傳遞該窗體的引用。如果沒有定義WindowHandlesHotkey會使熱鍵無法注冊。

4.4.3 熱鍵編輯窗體執行OpenConfigWindow方法將彈出模式窗體,提供用戶編輯熱鍵,該窗體就是TformHotKeyConfig的實例。

在窗體打開之前,爲了不在編輯時觸發熱鍵消息,需要調用DisableAllHotkeys取消所有熱鍵。

在窗體別關閉後檢查靜態變量isXMLNeedSave判斷用戶按下的是確認還是取消。如果是確認,則要保存熱鍵配置到靜態變量FkeyInfo和XML文檔。最後根據FkeyInfo重新注冊熱鍵。

4.4.4 對象唯一性因爲一個應用程序中,對于ThotkeyConfig對象通常只需要一個就夠了,如果在每個需要用到的地方都重新創建會影響程序執行效率。所以,我使用一個靜態變量保存唯一對象的引用,然後公開一個方法MgetInstance讓程序員得到ThotKeyConfig的實例對象。具體概念請訪問我的blog。

因此類的編程模式如下:

with THotKeyConfig.MGetInstance(Form1) do begin

LoadConfigFromXML;

EnableAllHotkeys ;

//……

end;

5 程序源代碼爲了便于使用,我將3個類定義和1個記錄體聲明寫在一個單獨的UNIT中,這樣會帶來一些訪問上的安全隱患,但是作爲學習只用,程序員在調用時“自覺”一點就可以了 :-P

//--------------------------------------------------------------------------

//UNIT: UnitHotkeyConfigClass.pas

//SUMM: 熱鍵控制類

//AUTH: CST

//DATE: 2005-8-15

//DESC: 本單元文件定義了一個保存熱鍵項目的記錄體、後台控制類、一個設定窗口類

// 以及一個需要用到的自定義控件THotKeyEdit。

//REFE: HotKeyConfig類使用到了自定義控件HotKeyEdit

//BUGS: No checking for duplicated hotkey sets

// No checking for duplicated hotkey_id in xml

//

//USES: 用戶只需使用THotKeyConfig類,該類不能創建實例。

// 請使用THotKeyConfig.MGetInstance(Owner)方法來訪問對象。

//--------------------------------------------------------------------------

unit UnitHotkeyConfigClass;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls, ExtCtrls, Buttons, StrUtils, Contnrs, xmldom, XMLIntf,

msxmldom, XMLDoc;

type

//---------------------------------------

// 熱鍵組合

//---------------------------------------

THotKeyStatus = record

FCaption:String[20]; //熱鍵標題

FHKID :Integer; //唯一ID

FMod :Integer; //組合鍵

FVK :Integer; //虛擬鍵碼

end;

//---------------------------------------

// 熱鍵編輯控件

//---------------------------------------

THotKeyEdit = class(TLabeledEdit)

private

//當前控件接收到的熱鍵組合是否合法

FKeySetValid:Boolean;

//組合鍵

FModValue:Integer;

//虛擬鍵碼

FVirtualKeyValue:Integer;

//修改合法後顯示的顔色

FValidateColor:TColor;

//用來覆蓋OnExit事件的函數

procedure LostFocusEvent(Sender:TObject);

//用來覆蓋OnKeyDown事件的函數

procedure GetHotKeyDownEvent(Sender: TObject; var Key: Word; Shift: TShiftState);

//將熱鍵數據轉換爲直觀文字

function GetDisplayText:string;

//熱鍵組合合法執行的代碼

procedure ActionOnHotKeyValid;

//熱鍵組合非法執行的代碼

procedure ActionOnHotKeyInvalid;

public

//覆蓋構造函數

constructor Create(AOwner: TComponent); override;

//外部請求將內部數據表現爲直觀文字

procedure DisplayHotKey;

published

property HasValidKeySet:boolean read FKeySetValid;

property VirtualKeyValue:integer read FVirtualKeyValue write FVirtualKeyValue;

property KeyModValue:integer read FModValue write FModValue;

end;

//---------------------------------------

// 熱鍵設定窗體

//---------------------------------------

TFormHotkeyConfig = class(TForm)

GroupBoxLeft: TGroupBox;

PanelRight: TPanel;

ButtonYes: TButton;

ButtonNo: TButton;

procedure ButtonYesClick(Sender: TObject);

procedure ButtonNoClick(Sender: TObject);

private

//用來保存動態創建的THotKeyEdit控件的對象列表

FEditList:TObjectList;

public

constructor Create(AOwner: TComponent); override;

end;

//---------------------------------------

// 主類:提供熱鍵注冊和編輯功能

//---------------------------------------

THotkeyConfig = class (TComponent)

private

//如果用戶自定義配置文件路徑則記錄它

FAssociatedXML : String;

//配置窗體對象

FConfigureForm : TFormHotkeyConfig;

//熱鍵響應窗體引用

FWindow : TWinControl;

//定位到保存熱鍵記錄的XML子樹樹根

function XMLGetKeysetFather(AXML:TXMLDocument):IXMLNode;

//隱藏的構造函數

constructor Create(AOwner: TComponent);override;

public

//獲得對象

class function MGetInstance(AOwner:TWinControl):THotKeyConfig;

//讀入XML配置文件

function LoadConfigFromXML(const AXMLFile:string='hotkey.xml'):boolean;

//保存配置

function SaveConfigToXML(const AXMLFile:string='hotkey.xml'):boolean;

//注冊所有熱鍵設置

function EnableAllHotkeys:Boolean;

//注銷熱鍵

procedure DisableAllHotkeys;

//打開配置窗口

procedure OpenConfigWindow;

published

property WindowHandlesHotkey : TWinControl write FWindow;

end;

procedure Register;

implementation

{$R *.dfm}

//-----------------------------------------------------------------------

// 單元內全局變量

//-----------------------------------------------------------------------

var

//共享從XML中讀入的熱鍵配置信息

FKeyInfo : array of THotKeyStatus;

//讀入的熱鍵記錄個數

FKeyInfoCount: Integer;

//是否需要保存到XML中

isXMLNeedSave:Boolean;

//實體

HK_Instance:THotkeyConfig;

//-----------------------------------------------------------------------

// 自定義控件可以被注冊

//-----------------------------------------------------------------------

procedure Register;

begin

RegisterComponents('CST', [THotKeyEdit]);

end;

{********************************************************

*********************************************************

******************* THotkeyConfig *********************

*********************************************************

********************************************************}

//-----------------------------------------------------------------------

// 構造函數

//-----------------------------------------------------------------------

constructor THotKeyConfig.Create (AOwner: TComponent);

begin

inherited;

end;

//-----------------------------------------------------------------------

//NAME: MGetInstance

//SUMM: 獲得類的唯一實例

//PARA: AOwner

//RETN: 唯一實例

//AUTH: CST

//DATE: 2005-8-18

//DESC: 類方法實現對象唯一性控制

//-----------------------------------------------------------------------

class function THotKeyConfig.MGetInstance(AOwner:TWinControl):THotKeyConfig;

begin

if HK_Instance = nil then begin

HK_Instance:=Create(AOwner);

HK_Instance.WindowHandlesHotkey := AOwner;

end;

Result:=HK_Instance;

end;

//-----------------------------------------------------------------------

//NAME: EnableAllHotkeys

//SUMM: 注冊所有熱鍵

//PARA: N/A

//RETN: TRUE-成功

//AUTH: CST

//DATE: 2005-8-15

//DESC: 在應用程序加載時由用戶顯式調用。熱鍵配置修改後被類自動調用重新注冊

// 先判斷熱鍵Listener窗體是否賦值,然後調用WIN32 API注冊

//-----------------------------------------------------------------------

function THotkeyConfig.EnableAllHotkeys:Boolean;

var

M_Index:integer;

M_ErrText:string;

begin

Result:=True;

//CHECK HOTKEY HANDLE WINDOW DEFINED

if FWindow=nil then begin

ShowMessage('熱鍵處理窗體未定義。'+#13+'請使用WindowHandlesHotkey方法。');

result:=false;

exit;

end;

//REGISTER BY LOOP

for M_Index := 0 to FKeyInfoCount - 1 do begin

//SKIP UNDEFINED HOTKEY EVENTS

if FKeyInfo[M_Index].FMod < 1 then continue;

if FKeyInfo[M_Index].FVK < 1 then continue;

//START TO REGISTER HOTKEY

if not RegisterHotKey( FWindow.Handle,

FKeyInfo[M_Index].FHKID,

FKeyInfo[M_Index].FMod ,

FKeyInfo[M_Index].FVK ) then begin

//REGISTER FAILURE PROCEDURE

Result:=False;

M_ErrText:=Format('無法注冊名爲%s的熱鍵。',[FKeyInfo[M_Index].FCaption]);

//ShowMessage(M_ErrText);

end; //end of if

end; //end of for

end;

//-----------------------------------------------------------------------

//NAME: DisableAllHotkeys

//SUMM: 注銷所有熱鍵

//PARA: N/A

//RETN: TRUE-成功

//AUTH: CST

//DATE: 2005-8-15

//DESC: 在進入熱鍵編輯之前要調用此方法注銷熱鍵。

//-----------------------------------------------------------------------

procedure THotkeyConfig.DisableAllHotkeys;

var

M_Index:integer;

begin

for M_Index := 0 to FKeyInfoCount - 1 do

UnRegisterHotKey( FWindow.Handle, FKeyInfo[M_Index].FHKID);

end;

//-----------------------------------------------------------------------

//NAME: XMLGetKeysetFather

//SUMM: 定位到保存熱鍵記錄的XML子樹樹根

//PARA: AXML-XML文檔

//RETN: 樹根節點

//AUTH: CST

//DATE: 2005-8-18

//DESC: 定位到保存熱鍵記錄的XML子樹樹根。

// 如果要改變XML結構,則只要修改這裏的定位語句。

//-----------------------------------------------------------------------

function THotkeyConfig.XMLGetKeysetFather(AXML:TXMLDocument):IXMLNode;

var

M_SearchNode:IXMLNode;

begin

//NAVIGATE THROUGH XML CONFIGURE FILE

M_SearchNode:=AXML.Node;

M_SearchNode:=M_SearchNode.ChildNodes.Nodes['configure'];

M_SearchNode:=M_SearchNode.ChildNodes.Nodes['hotkeys'];

Result:= M_SearchNode;

end;

//-----------------------------------------------------------------------

//NAME: LoadConfigFromXML

//SUMM: 從XML文檔中讀取熱鍵設置,並注冊生效

//PARA: AXMLFile-XML文檔路徑,默認爲EXE同根的hotkey.xml

//RETN: TRUE-成功

//AUTH: CST

//DATE: 2005-8-15

//DESC: 使用TXMLDocuement對象解析配置文檔,將讀取的記錄保存到類變量中

// FKeyInfo數組記錄讀入的熱鍵組合,FKeyInfoCount記錄動態數組大小

//-----------------------------------------------------------------------

function THotkeyConfig.LoadConfigFromXML(const AXMLFile:string='hotkey.xml'):boolean;

var

M_ConfigXML:TXMLDocument;

M_SearchNode, M_PropNode:IXMLNODE;

M_Index :integer;

begin

result:=False;

//Q:爲何構造方法參數爲nil就會無法解析節點?

M_ConfigXML:=TXMLDocument.Create(Self);

try

//OPEN XML CONFIGURE FILE

with M_ConfigXML do begin

LoadFromFile(AXMLFile);

Options := [];

Active := True;

end;

//RECORD ASSOCIATED XML CONFIGURATION FILE

FAssociatedXML := AXMLFile;

//GET THE ROOT WE WANT

M_SearchNode:=XMLGetKeysetFather(M_ConfigXML);

//GET COUNT FOR HOTKEY SETS

FKeyInfoCount:=M_SearchNode.ChildNodes.Count ;

SetLength(FKeyInfo, FKeyInfoCount);

//LOOP TO READ EVERY KEYSET

for M_Index := 0 to FKeyInfoCount - 1 do begin

M_PropNode:=M_SearchNode.ChildNodes.Nodes[M_Index];

with FKeyInfo[M_Index] do begin

FCaption := M_PropNode.ChildValues['caption'];

FHKID := M_PropNode.ChildValues['hkid'];

FMod := M_PropNode.ChildValues['mod'];

FVK := M_PropNode.ChildValues['vk'];

end; //end of with

end; //end of for

finally

M_ConfigXML.Active := False;

FreeAndNil(M_ConfigXML);

end;

end;

//-----------------------------------------------------------------------

//NAME: SaveConfigToXML

//SUMM: 保存修改的熱鍵配置到XML文檔

//PARA: AXMLFile-XML文檔路徑

//RETN: TRUE-成功

//AUTH: CST

//DATE: 2005-8-15

//DESC: 配置窗口確認關閉後調用

//-----------------------------------------------------------------------

function THotkeyConfig.SaveConfigToXML(const AXMLFile:string='hotkey.xml'):boolean;

var

M_ConfigXML:TXMLDocument;

M_SearchNode, M_PropNode:IXMLNODE;

M_Index :integer;

begin

result:=False;

M_ConfigXML:=TXMLDocument.Create(Self );

try

//OPEN XML CONFIGURE FILE

with M_ConfigXML do begin

LoadFromFile(AXMLFile);

Options := [];

Active := True;

end;

//GET THE ROOT WE WANT

M_SearchNode:=XMLGetKeysetFather(M_ConfigXML);

//LOOP TO READ EVERY KEYSET

for M_Index := 0 to FKeyInfoCount - 1 do begin

M_PropNode:=M_SearchNode.ChildNodes.Nodes[M_Index];

with FKeyInfo[M_Index] do begin

M_PropNode.ChildValues['caption']:=FCaption;

M_PropNode.ChildValues['hkid']:=FHKID;

M_PropNode.ChildValues['mod']:=FMod;

M_PropNode.ChildValues['vk']:=FVK;

end; //end of with

end; //end of for

//SAVE CHANGES

M_ConfigXML.SaveToFile(AXMLFile);

finally

M_ConfigXML.Active := False;

FreeAndNil(M_ConfigXML);

end;

end;

//-----------------------------------------------------------------------

//NAME: OpenConfigWindow

//SUMM: 打開配置窗口

//PARA: N/A

//RETN: N/A

//AUTH: CST

//DATE: 2005-8-15

//DESC: 窗體對象爲 FConfigureForm 成員

//-----------------------------------------------------------------------

procedure THotKeyConfig.OpenConfigWindow ;

var

M_ErrMsg:String;

begin

if FConfigureForm = nil then FConfigureForm:=TFormHotkeyConfig.Create(nil);

try

//默認是不要保存修改

isXMLNeedSave:=False;

//設置之前先注銷所有熱鍵

DisableAllHotkeys ;

//打開設置窗口

FConfigureForm.ShowModal;

if isXMLNeedSave then begin

//修改後按下『確認』生效並保存

if EnableAllHotkeys then

begin

//新設置熱鍵注冊成功

MessageBox(Application.Handle, '所有熱鍵都成功注冊。'+#13+'點擊確認保存所有熱鍵設置。', '提示', MB_OK + MB_ICONINFORMATION);

SaveConfigToXML(FAssociatedXML);

end //end of if

else

begin

//新設置熱鍵有沖突

M_ErrMsg:='您設置的熱鍵組合中有一項或多項沒有注冊成功。' + #13 +

'也許是和其他應用程序産生了沖突,您可以嘗試更換其他按鍵組合。' + #13 +

'請問是否仍然要保存這次的設置,如果保存請按“是”,我們將在下次軟件啓動的時候'+

'再次嘗試注冊您的熱鍵配置,您可以在這之前注銷或修改其他應用程序的沖突設置。';

if MessageBox(Application.Handle, PChar(M_ErrMsg), '提示',MB_YESNO+MB_ICONQUESTION)=IDYES then SaveConfigToXML(FAssociatedXML);

end;

end

else begin

//按下『取消』按鈕,但是還是要恢複原先的熱鍵

EnableAllHotkeys;

end;

finally

FreeAndNil(FConfigureForm);

end;

end;

{********************************************************

*********************************************************

**************** TFormHotkeyConfig ********************

*********************************************************

********************************************************}

//-----------------------------------------------------------------------

//NAME: Create

//SUMM: TFormHotkeyConfig的構造函數

//AUTH: CST

//DATE: 2005-8-15

//DESC: 繼承TForm的構造函數,動態創建THotKeyEdit控件。

// 將窗體上的熱鍵接受控件的OnKeyDown事件改寫。

//-----------------------------------------------------------------------

constructor TFormHotkeyConfig.Create(AOwner: TComponent);

var

M_Index, M_Top:integer;

HKEdit:THotkeyEdit;

const

MLEFT = 10;

MWIDTH = 200;

MHEIGHT = 21;

MMARGIN = 30;

begin

inherited;

//HOTKEYEDITORS

FEditList := TObjectList.Create ;

M_Top := 0;

for M_Index := 0 to FKeyInfoCount - 1 do begin

//計算控件位置,縱向排列

M_Top:= MMARGIN + M_Index * (MHEIGHT+MMARGIN);

//根據讀入的XML節點動態創建熱鍵編輯控件

HKEdit:=THotKeyEdit.Create(Self);

with HKEdit do begin

//定義樣式

Parent:=Self.GroupBoxLeft;

SetBounds(MLEFT,M_Top,MWIDTH,MHEIGHT);

LabelPosition := lpAbove ;

EditLabel.Caption := FKeyInfo[M_Index].FCaption;

EditLabel.Width := MWIDTH;

//定義初始數據

VirtualKeyValue := FKeyInfo[M_Index].FVK;

KeyModValue := FKeyInfo[M_Index].FMod;

//按照定義的數據顯示熱鍵組合

DisplayHotKey;

end; //end of with

//保存組件到對象列表

FEditList.Add(HKEdit);

end; //end of for

Height:= M_Top + MHEIGHT + MMARGIN;

end;

//------------------------------------------------------------

// 確定

//------------------------------------------------------------

procedure TFormHotkeyConfig.ButtonYesClick(Sender: TObject);

var

M_Index:integer;

begin

//CONVERT HK_EDITOR DATA TO HOTKEY INFO ARRAY

for M_Index := 0 to FKeyInfoCount - 1 do begin

FKeyInfo[M_Index].FMod := (FEditList.Items[M_Index] as THotKeyEdit).KeyModValue ;

FKeyInfo[M_Index].FVK := (FEditList.Items[M_Index] as THotKeyEdit).VirtualKeyValue;

end;

//END OF CONVERT

Close;

isXMLNeedSave:=True;

end;

//------------------------------------------------------------

// 取消

//------------------------------------------------------------

procedure TFormHotkeyConfig.ButtonNoClick(Sender: TObject);

begin

if MessageBox(Self.Handle,'是否要放棄修改並關閉窗口?','提示',MB_YESNO+mb_iconinformation) = IDYES then

begin

Close;

isXMLNeedSave:=False;

end;

end;

{********************************************************

*********************************************************

********************* THotKeyEdit *********************

*********************************************************

********************************************************}

//-----------------------------------------------------------------------

// HotKeyEdit控件構造函數

//-----------------------------------------------------------------------

constructor THotKeyEdit.Create(AOwner: TComponent);

begin

inherited;

ReadOnly := True;

OnKeyDown := GetHotKeyDownEvent;

OnExit := LostFocusEvent;

FValidateColor := clSkyBlue;

end;

//-----------------------------------------------------------------------

//NAME: GetDisplayText

//SUMM: 將熱鍵信息轉換爲顯示字串

//PARA: N/A

//RETN: 熱鍵轉換的顯示結果

//AUTH: CST

//DATE: 2005-8-15

//DESC: 型如:"Ctrl + Alt + Shift + A "爲正確

// 數據來源 FVirtualKeyValue, FModValue

// 判斷組合是否合法,記錄在FKeySetValid中

//-----------------------------------------------------------------------

function THotKeyEdit.GetDisplayText:string;

var

M_strDisplay:String;

const

SPLUS = ' + ';

begin

FKeySetValid := True;

//處理按鍵組合

case FModValue of

1: M_strDisplay:='Alt + ';

2: M_strDisplay:='Ctrl + ';

3: M_strDisplay:='Ctrl + Alt + ';

4: M_strDisplay:='Shift + ';

5: M_strDisplay:='Shift + Alt + ';

6: M_strDisplay:='Ctrl + Shift + ';

7: M_strDisplay:='Ctrl + Shift + Alt + ';

else

begin

M_strDisplay := '';

FKeySetValid := False;

end;

end;

//處理鍵碼

case FVirtualKeyValue of

VK_F1..VK_F12:

M_strDisplay := M_strDisplay + 'F'+IntToStr(FVirtualKeyValue - VK_F1 + 1);

Ord('A')..Ord('Z'), Ord('0')..Ord('9'):

M_strDisplay := M_strDisplay + Chr(FVirtualKeyValue);

else

begin

M_strDisplay := M_strDisplay ;

FKeySetValid := False;

end;

end;

result:=M_strDisplay;

end;

//-----------------------------------------------------------------------

//NAME: LostFocusEvent

//SUMM: 控件失去焦點時檢查熱鍵合法性

//PARA: Sender-控件

//RETN: N/A

//AUTH: CST

//DATE: 2005-8-15

//DESC: 此函數將用來覆蓋4個TLabelEdit的OnExit事件

//-----------------------------------------------------------------------

procedure THotKeyEdit.LostFocusEvent(Sender:TObject);

begin

if not FKeySetValid then begin

Text:='';

FModValue := 0;

FVirtualKeyValue := 0;

end;

end;

//-----------------------------------------------------------------------

//NAME: GetHotKeyDownEvent

//SUMM: 接受用戶輸入的熱鍵並判斷是否合法的時間函數

//PARA: Sender-控件 Key-虛擬鍵碼 Shift-輔助鍵信息

//RETN: N/A

//AUTH: CST

//DATE: 2005-8-15

//DESC: 此函數將用來覆蓋OnKeyDown事件

//

//-----------------------------------------------------------------------

procedure THotKeyEdit.GetHotKeyDownEvent(Sender: TObject; var Key: Word; Shift: TShiftState);

var

M_StrDisplay:String;

begin

//READ HOTKEY SET MODE

FModValue := 0;

if (ssCtrl in Shift) then FModValue := FModValue + 2;

if (ssAlt in Shift) then FModValue := FModValue + 1;

if (ssShift in Shift) then FModValue := FModValue + 4;

//READ HOTKEY SET VIRTUAL KEY

FVirtualKeyValue := Key;

//GET DISPLAY TEXT AND JUDGE WHETHER KEYSET IS VALIDATE

M_StrDisplay := GetDisplayText;

//REFLECTION

if FKeySetValid then

ActionOnHotKeyValid

else

ActionOnHotKeyInvalid ;

Text := M_StrDisplay;

end;

//---------------------------------------

// 在動態創建時顯示組合鍵

//---------------------------------------

procedure THotKeyEdit.DisplayHotKey;

begin

Text := GetDisplayText ;

end;

//---------------------------------------

// 熱鍵組合合法執行的代碼

//---------------------------------------

procedure THotKeyEdit.ActionOnHotKeyValid;

begin

Color:=FValidateColor;

end;

//---------------------------------------

// 熱鍵組合非法執行的代碼

//---------------------------------------

procedure THotKeyEdit.ActionOnHotKeyInvalid;

begin

Color := clWhite;

end;

end.

6 小結6.1 沒有解決的一些問題TXMLDocument的對象在創建時如果Owner參數爲nil則無法解析到節點,如果使用帶文檔路徑參數的重載的構造函數也會如此,因爲在TXMLDocument的源碼中重載的版本Owner也是nil。爲了規避這個問題,我犧牲了效率而將Owner置爲Application並手動釋放了文檔對象。考慮到如果使用self可能會因爲釋放兩次而産生錯誤,而Application的釋放影響不會很大。

沒有實現對于XML文檔合法性的檢驗,僅過濾了超出範圍的MOD和VK值,對于HKID是否唯一沒有做檢查。

沒有實現對于用戶定義的熱鍵之間的沖突,在TformHotKeyConfig中沒有判斷是否設置的了相同的熱鍵。

熱鍵編輯控件可以注冊到Pallete中,ThotKeyConfig類尚未控件化,如果控件化可能需要改變對象調用方式,公開構造函數允許創建多個實例。取消MgetInstance方法。

6.2 程序心得雖然Delphi中對于熱鍵的使用也不繁瑣,但是使用本方法可以利用流行的xml記錄熱鍵是挺誘人的,只要稍加修改就可以繼承到應用程序中。而且這樣自由度比較高,熱鍵數量、名稱、布局都是可以自定義的。

在組件化上,我只封裝了ThotKeyEdit控件,而沒有將ThotKeyConfig類嚴格封裝。因此只能通過代碼手動創建和調用。熱鍵編輯窗口是一個挺方便的設計,可以讓使用該類的用戶不必關心熱鍵編輯的實現。

在不斷的OO開發中,我也在摸索,程序中難免會有一些不如意之處,我誠心希望各位給我提出意見,我也很高興能在相關的問題上和大家一起討論討論。

本程序的相關代碼和測試示例可以在我的YAHOO公文包上下載。

 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
實現一個熱鍵注冊編輯的類 CST(http://blog.csdn.net/mrtechno) 2005-8-19 [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237148]1 文檔目的... 1[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237149]2 熱鍵編程基礎... 1[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237150]2.1 API函數... 1[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237151]2.2 編程方法... 2[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237152]3 實現概述... 4[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237153]4 實現細節... 4[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237154]4.1 XML配置文檔結構... 4[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237155]4.2 熱鍵編輯控件 ThotKeyEdit 5[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237156]4.3 熱鍵自定義窗體類TformHotKeyconfig. 6[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237157]4.4 主類ThotKeyConfig. 6[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237158]4.4.1 解析XML文檔... 7[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237159]4.4.2 注冊注銷系統熱鍵... 8[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237160]4.4.3 熱鍵編輯窗體... 8[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237161]4.4.4 對象唯一性... 8[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237162]5 程序源代碼... 9[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237163]6 小結... 25[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237164]6.1 沒有解決的一些問題... 25[/url] [url=http://blog.csdn.net/fckeditor/editor/fckeditorarea.html#_Toc112237165]6.2 程序心得... 26[/url] 1 文檔目的本文檔介紹了在Delphi 7中注冊、注銷、使用熱鍵(Hot Key)的基本函數和方法,並在此基礎上介紹了一個熱鍵控制的類THotKeyConfig。該類可以從指定的xml配置文檔中讀入熱鍵配置信息,並在程序指定的位置注冊、注銷、修改熱鍵。 本文將不涉及XML文檔的讀寫方法,也不會詳述控件開發的方法。如果您對這些內容不了解,推薦您先略讀一下相關的文章。關于xml文檔的解析,可以到我的blog找到文章。 2 熱鍵編程基礎2.1 API函數在Delphi7中使用熱鍵要用到如下幾個函數: //注冊熱鍵 BOOL RegisterHotKey( HWND hWnd, // 接受熱鍵消息的窗口句柄 int id, // 熱鍵ID UINT fsModifiers, // 按鍵組合整數 UINT vk // 案件虛擬鍵碼VK ); 其中fsModifiers 值如下: 1: M_strDisplay:='Alt + '; 2: M_strDisplay:='Ctrl + '; 3: M_strDisplay:='Ctrl + Alt + '; 4: M_strDisplay:='Shift + '; 5: M_strDisplay:='Shift + Alt + '; 6: M_strDisplay:='Ctrl + Shift + '; 7: M_strDisplay:='Ctrl + Shift + Alt + '; //注銷熱鍵 BOOL UnregisterHotKey( HWND hWnd, //接受熱鍵消息的窗口句柄 int id //熱鍵ID ); 注銷時,根據注冊時賦予的熱鍵ID進行注銷,因此在注冊時必須保證ID唯一。 關于這兩個WIN32 API函數的具體說明可以參考WIN32 SDK文檔。 2.2 編程方法基本的熱鍵編程方法是定義2個窗體過程,和一個消息響應函數: Procedure HotKeyOn; Procedure HotKeyOff; procedure HotKeyDown(var Msg: Tmessage); message WM_HOTKEY; 在HotKeyOn過程中調用API函數注冊熱鍵,代碼可以是這樣的: procedure TfrmMain.HotKeyOn; begin HKStep := 1; HKScreen := 2; HKComponent := 3; HKShowMain := 4; HKShowOI := 5; if not RegisterHotKey(Handle, HKStep, MOD_CONTROL, Ord('C')) then showmessage('can not register the hotkey "Ctrl-C"'); if not RegisterHotKey(Handle, HKScreen, MOD_CONTROL, Ord('V')) then showmessage('can not register the hotkey "Ctrl-V"'); if not RegisterHotKey(Handle, HKComponent, MOD_CONTROL, Ord('B')) then showmessage('can not register the hotkey "Ctrl-B"'); if not RegisterHotKey(Handle, HKShowMain, MOD_CONTROL, VK_F11) then showmessage('can not register the hotkey "Ctrl-F11"'); if not RegisterHotKey(Handle, HKShowOI, MOD_CONTROL, VK_F12) then showmessage('can not register the hotkey "Ctrl-F12"'); end; 在HotKeyOff過程中調用API函數注銷熱鍵,代碼可以是這樣的: procedure TfrmMain.HotKeyOff; begin UnRegisterHotKey(handle, HKStep); UnRegisterHotKey(handle, HKScreen); UnRegisterHotKey(handle, HKComponent); UnRegisterHotKey(handle, HKShowMain); UnRegisterHotKey(handle, HKShowOI); end; 在HotKeyDown消息處理函數中判斷系統消息,根據不同的熱鍵組合執行響應的語句,代碼可以是這樣的: procedure TfrmMain.HotKeyDown(var Msg: Tmessage); begin if (Msg.LParamHi = Ord('C')) and (Msg.LParamLo = MOD_CONTROL) then ShowMessage('"Ctrl-C"') else if (Msg.LParamHi = Ord('V')) and (Msg.LParamLo = MOD_CONTROL) then ShowMessage('"Ctrl-V"') else if (Msg.LParamHi = Ord('B')) and (Msg.LParamLo = MOD_CONTROL) then ShowMessage('"Ctrl-B"') else if (Msg.LParamHi = VK_F11) and (Msg.LParamLo = MOD_CONTROL) then ShowMessage('"Ctrl-11"') else if (Msg.LParamHi = VK_F12) and (Msg.LParamLo = MOD_CONTROL) then ShowMessage('"Ctrl-12"') end; 如果系統熱鍵數量少、穩定不變,則適合使用這種方法。如果系統熱鍵較多,而軟件需求又要求熱鍵可以由用戶設置修改,則需要有一個自動化管理的模塊來實現。因此我在學習了如上的方法後實現了一個熱鍵自動管理的類。 3 實現概述實現這個熱鍵管理類我定義了1個記錄體和3個類。可以將熱鍵配置信息保存在一個獨立的xml文檔中,也作爲子樹加入到應用程序的配置文檔中。 記錄體ThotKeyStatus保存從XML配置樹中讀入的熱鍵記錄,該記錄體的數組變量將被整個單元文件內的對象所共享。 類ThotKeyEdit是一個自定義的控件,用于接受用戶輸入的熱鍵組合,一方面轉化爲系統可以接受的形式,另一方面也給用戶一個即時反饋。 類TformHotkeyConfig是一個窗體類,該窗體類將根據從XML中讀入的熱鍵配置動態創建ThotKeyEdit控件,提供用戶查看和修改熱鍵。 類ThotKeyConfig是我們要使用和直接訪問的類,它提供一個後台操作的功能,用戶在引入該類後可以選擇在程序指定位置讀入XML配置文件、生效熱鍵配置、打開TformHotKeyConfig提供的編輯窗體、保存配置到XML文件。另外該類在編程上爲了控制對象的唯一性,采用了類方法MgetInstance來獲得唯一對象,關于用類方法控制對象唯一性的方法可以參考我blog中的文章。 4 實現細節4.1 XML配置文檔結構XML配置文檔的結構可以如下: <?xml version="1.0" encoding="UTF-8"?> <configure> <hotkeys> <hotkey> <caption>添加SCREEN</caption> <hkid>101</hkid> <mod>2</mod> <vk>49</vk> </hotkey> <hotkey> <caption>新建STEP</caption> <hkid>102</hkid> <mod>2</mod> <vk>50</vk> </hotkey> </hotkeys> </configure> 其中,<hotkeys>爲保存熱鍵配置的節點的子樹樹根。每個<hotkey>子樹記錄一個熱鍵配置。 caption爲熱鍵名稱,將顯示在TformHotKeyConfig實例中的ThotKeyEdit對象的標題位置。 Hkid爲熱鍵唯一標識,對應上文API函數中的ID值,該值必須局部唯一。 Mod爲熱鍵模式,對應上文API函數中的fsModifier值。 Vk爲熱鍵虛擬鍵碼,對應上文API函數中的VK值。 4.2 熱鍵編輯控件 ThotKeyEdit該控件的聲明如下: //--------------------------------------- // 熱鍵編輯控件 //--------------------------------------- THotKeyEdit = class(TLabeledEdit) private //當前控件接收到的熱鍵組合是否合法 FKeySetValid:Boolean; //組合鍵 FModValue:Integer; //虛擬鍵碼 FVirtualKeyValue:Integer; //修改合法後顯示的顔色 FValidateColor:TColor; //用來覆蓋OnExit事件的函數 procedure LostFocusEvent(Sender:TObject); //用來覆蓋OnKeyDown事件的函數 procedure GetHotKeyDownEvent(Sender: TObject; var Key: Word; Shift: TShiftState); //將熱鍵數據轉換爲直觀文字 function GetDisplayText:string; //熱鍵組合合法執行的代碼 procedure ActionOnHotKeyValid; //熱鍵組合非法執行的代碼 procedure ActionOnHotKeyInvalid; public //覆蓋構造函數 constructor Create(AOwner: TComponent); override; //外部請求將內部數據表現爲直觀文字 procedure DisplayHotKey; published property HasValidKeySet:boolean read FKeySetValid; property VirtualKeyValue:integer read FVirtualKeyValue write FVirtualKeyValue; property KeyModValue:integer read FModValue write FModValue; end; ThotKeyEdit控件繼承自TlabeledEdit控件,包含一個顯示熱鍵名稱的LABEL和一個只讀的EDIT區,在該區將顯示用戶輸入的熱鍵組合。控件的OnKeyDown事件被GetHotKeyDownEvent過程重寫,在該過程中捕捉用戶按下的按鍵組合,先將捕捉到的鍵位信息保存到私有字段中,然後調用GetDisplayText函數判斷私有字段中的鍵位是否合法,並且返回由這些信息轉換得到的熱鍵字串。合法性將保存在一個私有布爾字段FKeySetValid中。 對于用戶提供的熱鍵布局,如果可以接受則控件edit區會變色,如果不能接受則會在失去焦點時清除內容,並恢複默認顔色。 4.3 熱鍵自定義窗體類TformHotKeyconfig該窗體類繼承自Tform類,並需要UnitHotkeyConfigClass.dfm資源文件的支持。 類的聲明代碼如下: //--------------------------------------- // 熱鍵設定窗體 //--------------------------------------- TFormHotkeyConfig = class(TForm) GroupBoxLeft: TGroupBox; PanelRight: TPanel; ButtonYes: TButton; ButtonNo: TButton; procedure ButtonYesClick(Sender: TObject); procedure ButtonNoClick(Sender: TObject); private //用來保存動態創建的THotKeyEdit控件的對象列表 FEditList:TObjectList; public constructor Create(AOwner: TComponent); override; end; 該類重寫了構造方法,並在構造方法中根據從xml中讀入的熱鍵個數動態創建和初始化響應數量的ThotKeyEdit控件,因此需要一個私有成員FeditList來維護控件數組。 4.4 主類ThotKeyConfigThotKeyConfig的聲明如下: //--------------------------------------- // 主類:提供熱鍵注冊和編輯功能 //--------------------------------------- THotkeyConfig = class (TComponent) private //如果用戶自定義配置文件路徑則記錄它 FAssociatedXML : String; //配置窗體對象 FConfigureForm : TFormHotkeyConfig; //熱鍵響應窗體引用 FWindow : TWinControl; //定位到保存熱鍵記錄的XML子樹樹根 function XMLGetKeysetFather(AXML:TXMLDocument):IXMLNode; //隱藏的構造函數 constructor Create(AOwner: TComponent);override; public //獲得對象 class function MGetInstance(AOwner:TWinControl):THotKeyConfig; //讀入XML配置文件 function LoadConfigFromXML(const AXMLFile:string='hotkey.xml'):boolean; //保存配置 function SaveConfigToXML(const AXMLFile:string='hotkey.xml'):boolean; //注冊所有熱鍵設置 function EnableAllHotkeys:Boolean; //注銷熱鍵 procedure DisableAllHotkeys; //打開配置窗口 procedure OpenConfigWindow; published property WindowHandlesHotkey : TWinControl write FWindow; end; 在該類中主要完成如下幾個功能: 1. 讀寫解析XML配置文件 2. 注冊注銷系統熱鍵 3. 提供熱鍵修改窗體的入口 4. 通過類方法和類變量,管理類的對象在應用程序中的唯一性 4.4.1 解析XML文檔因爲XML文檔結構相對簡單因此使用TXMLDocument類來實現,在LoadConfigFromXML方法中通過XMLGetKeysetFather函數定位到Hotkey節點,這樣如果XML結構位置改變,只需要修改XMLGetKeysetFather函數就可以。讀出的熱鍵記錄將保存到靜態變量FkeyInfo和FkeyInfoCount中,他們是ThotKeyStatus的數組和計數器。 4.4.2 注冊注銷系統熱鍵兩個對象方法負責自動完成熱鍵的注冊和注銷:EnableAllHotkeys和DisableAllHotkeys。 熱鍵注冊時從FkeyInfo數組中讀入鍵位信息並調用WIN32 API函數RegisterHotKey注冊熱鍵,如果注冊成功則返回true。 在RegisterHotKey中需要一個窗體句柄來接受系統消息WM_HOTKEY,因此在調用EnableAllHotkeys之前需要爲屬性WindowHandlesHotkey賦一個窗體的引用值。或者在MgetInstance方法的參數中傳遞該窗體的引用。如果沒有定義WindowHandlesHotkey會使熱鍵無法注冊。 4.4.3 熱鍵編輯窗體執行OpenConfigWindow方法將彈出模式窗體,提供用戶編輯熱鍵,該窗體就是TformHotKeyConfig的實例。 在窗體打開之前,爲了不在編輯時觸發熱鍵消息,需要調用DisableAllHotkeys取消所有熱鍵。 在窗體別關閉後檢查靜態變量isXMLNeedSave判斷用戶按下的是確認還是取消。如果是確認,則要保存熱鍵配置到靜態變量FkeyInfo和XML文檔。最後根據FkeyInfo重新注冊熱鍵。 4.4.4 對象唯一性因爲一個應用程序中,對于ThotkeyConfig對象通常只需要一個就夠了,如果在每個需要用到的地方都重新創建會影響程序執行效率。所以,我使用一個靜態變量保存唯一對象的引用,然後公開一個方法MgetInstance讓程序員得到ThotKeyConfig的實例對象。具體概念請訪問我的blog。 因此類的編程模式如下: with THotKeyConfig.MGetInstance(Form1) do begin LoadConfigFromXML; EnableAllHotkeys ; //…… end; 5 程序源代碼爲了便于使用,我將3個類定義和1個記錄體聲明寫在一個單獨的UNIT中,這樣會帶來一些訪問上的安全隱患,但是作爲學習只用,程序員在調用時“自覺”一點就可以了 :-P //-------------------------------------------------------------------------- //UNIT: UnitHotkeyConfigClass.pas //SUMM: 熱鍵控制類 //AUTH: CST //DATE: 2005-8-15 //DESC: 本單元文件定義了一個保存熱鍵項目的記錄體、後台控制類、一個設定窗口類 // 以及一個需要用到的自定義控件THotKeyEdit。 //REFE: HotKeyConfig類使用到了自定義控件HotKeyEdit //BUGS: No checking for duplicated hotkey sets // No checking for duplicated hotkey_id in xml // //USES: 用戶只需使用THotKeyConfig類,該類不能創建實例。 // 請使用THotKeyConfig.MGetInstance(Owner)方法來訪問對象。 //-------------------------------------------------------------------------- unit UnitHotkeyConfigClass; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Buttons, StrUtils, Contnrs, xmldom, XMLIntf, msxmldom, XMLDoc; type //--------------------------------------- // 熱鍵組合 //--------------------------------------- THotKeyStatus = record FCaption:String[20]; //熱鍵標題 FHKID :Integer; //唯一ID FMod :Integer; //組合鍵 FVK :Integer; //虛擬鍵碼 end; //--------------------------------------- // 熱鍵編輯控件 //--------------------------------------- THotKeyEdit = class(TLabeledEdit) private //當前控件接收到的熱鍵組合是否合法 FKeySetValid:Boolean; //組合鍵 FModValue:Integer; //虛擬鍵碼 FVirtualKeyValue:Integer; //修改合法後顯示的顔色 FValidateColor:TColor; //用來覆蓋OnExit事件的函數 procedure LostFocusEvent(Sender:TObject); //用來覆蓋OnKeyDown事件的函數 procedure GetHotKeyDownEvent(Sender: TObject; var Key: Word; Shift: TShiftState); //將熱鍵數據轉換爲直觀文字 function GetDisplayText:string; //熱鍵組合合法執行的代碼 procedure ActionOnHotKeyValid; //熱鍵組合非法執行的代碼 procedure ActionOnHotKeyInvalid; public //覆蓋構造函數 constructor Create(AOwner: TComponent); override; //外部請求將內部數據表現爲直觀文字 procedure DisplayHotKey; published property HasValidKeySet:boolean read FKeySetValid; property VirtualKeyValue:integer read FVirtualKeyValue write FVirtualKeyValue; property KeyModValue:integer read FModValue write FModValue; end; //--------------------------------------- // 熱鍵設定窗體 //--------------------------------------- TFormHotkeyConfig = class(TForm) GroupBoxLeft: TGroupBox; PanelRight: TPanel; ButtonYes: TButton; ButtonNo: TButton; procedure ButtonYesClick(Sender: TObject); procedure ButtonNoClick(Sender: TObject); private //用來保存動態創建的THotKeyEdit控件的對象列表 FEditList:TObjectList; public constructor Create(AOwner: TComponent); override; end; //--------------------------------------- // 主類:提供熱鍵注冊和編輯功能 //--------------------------------------- THotkeyConfig = class (TComponent) private //如果用戶自定義配置文件路徑則記錄它 FAssociatedXML : String; //配置窗體對象 FConfigureForm : TFormHotkeyConfig; //熱鍵響應窗體引用 FWindow : TWinControl; //定位到保存熱鍵記錄的XML子樹樹根 function XMLGetKeysetFather(AXML:TXMLDocument):IXMLNode; //隱藏的構造函數 constructor Create(AOwner: TComponent);override; public //獲得對象 class function MGetInstance(AOwner:TWinControl):THotKeyConfig; //讀入XML配置文件 function LoadConfigFromXML(const AXMLFile:string='hotkey.xml'):boolean; //保存配置 function SaveConfigToXML(const AXMLFile:string='hotkey.xml'):boolean; //注冊所有熱鍵設置 function EnableAllHotkeys:Boolean; //注銷熱鍵 procedure DisableAllHotkeys; //打開配置窗口 procedure OpenConfigWindow; published property WindowHandlesHotkey : TWinControl write FWindow; end; procedure Register; implementation {$R *.dfm} //----------------------------------------------------------------------- // 單元內全局變量 //----------------------------------------------------------------------- var //共享從XML中讀入的熱鍵配置信息 FKeyInfo : array of THotKeyStatus; //讀入的熱鍵記錄個數 FKeyInfoCount: Integer; //是否需要保存到XML中 isXMLNeedSave:Boolean; //實體 HK_Instance:THotkeyConfig; //----------------------------------------------------------------------- // 自定義控件可以被注冊 //----------------------------------------------------------------------- procedure Register; begin RegisterComponents('CST', [THotKeyEdit]); end; {******************************************************** ********************************************************* ******************* THotkeyConfig ********************* ********************************************************* ********************************************************} //----------------------------------------------------------------------- // 構造函數 //----------------------------------------------------------------------- constructor THotKeyConfig.Create (AOwner: TComponent); begin inherited; end; //----------------------------------------------------------------------- //NAME: MGetInstance //SUMM: 獲得類的唯一實例 //PARA: AOwner //RETN: 唯一實例 //AUTH: CST //DATE: 2005-8-18 //DESC: 類方法實現對象唯一性控制 //----------------------------------------------------------------------- class function THotKeyConfig.MGetInstance(AOwner:TWinControl):THotKeyConfig; begin if HK_Instance = nil then begin HK_Instance:=Create(AOwner); HK_Instance.WindowHandlesHotkey := AOwner; end; Result:=HK_Instance; end; //----------------------------------------------------------------------- //NAME: EnableAllHotkeys //SUMM: 注冊所有熱鍵 //PARA: N/A //RETN: TRUE-成功 //AUTH: CST //DATE: 2005-8-15 //DESC: 在應用程序加載時由用戶顯式調用。熱鍵配置修改後被類自動調用重新注冊 // 先判斷熱鍵Listener窗體是否賦值,然後調用WIN32 API注冊 //----------------------------------------------------------------------- function THotkeyConfig.EnableAllHotkeys:Boolean; var M_Index:integer; M_ErrText:string; begin Result:=True; //CHECK HOTKEY HANDLE WINDOW DEFINED if FWindow=nil then begin ShowMessage('熱鍵處理窗體未定義。'+#13+'請使用WindowHandlesHotkey方法。'); result:=false; exit; end; //REGISTER BY LOOP for M_Index := 0 to FKeyInfoCount - 1 do begin //SKIP UNDEFINED HOTKEY EVENTS if FKeyInfo[M_Index].FMod < 1 then continue; if FKeyInfo[M_Index].FVK < 1 then continue; //START TO REGISTER HOTKEY if not RegisterHotKey( FWindow.Handle, FKeyInfo[M_Index].FHKID, FKeyInfo[M_Index].FMod , FKeyInfo[M_Index].FVK ) then begin //REGISTER FAILURE PROCEDURE Result:=False; M_ErrText:=Format('無法注冊名爲%s的熱鍵。',[FKeyInfo[M_Index].FCaption]); //ShowMessage(M_ErrText); end; //end of if end; //end of for end; //----------------------------------------------------------------------- //NAME: DisableAllHotkeys //SUMM: 注銷所有熱鍵 //PARA: N/A //RETN: TRUE-成功 //AUTH: CST //DATE: 2005-8-15 //DESC: 在進入熱鍵編輯之前要調用此方法注銷熱鍵。 //----------------------------------------------------------------------- procedure THotkeyConfig.DisableAllHotkeys; var M_Index:integer; begin for M_Index := 0 to FKeyInfoCount - 1 do UnRegisterHotKey( FWindow.Handle, FKeyInfo[M_Index].FHKID); end; //----------------------------------------------------------------------- //NAME: XMLGetKeysetFather //SUMM: 定位到保存熱鍵記錄的XML子樹樹根 //PARA: AXML-XML文檔 //RETN: 樹根節點 //AUTH: CST //DATE: 2005-8-18 //DESC: 定位到保存熱鍵記錄的XML子樹樹根。 // 如果要改變XML結構,則只要修改這裏的定位語句。 //----------------------------------------------------------------------- function THotkeyConfig.XMLGetKeysetFather(AXML:TXMLDocument):IXMLNode; var M_SearchNode:IXMLNode; begin //NAVIGATE THROUGH XML CONFIGURE FILE M_SearchNode:=AXML.Node; M_SearchNode:=M_SearchNode.ChildNodes.Nodes['configure']; M_SearchNode:=M_SearchNode.ChildNodes.Nodes['hotkeys']; Result:= M_SearchNode; end; //----------------------------------------------------------------------- //NAME: LoadConfigFromXML //SUMM: 從XML文檔中讀取熱鍵設置,並注冊生效 //PARA: AXMLFile-XML文檔路徑,默認爲EXE同根的hotkey.xml //RETN: TRUE-成功 //AUTH: CST //DATE: 2005-8-15 //DESC: 使用TXMLDocuement對象解析配置文檔,將讀取的記錄保存到類變量中 // FKeyInfo數組記錄讀入的熱鍵組合,FKeyInfoCount記錄動態數組大小 //----------------------------------------------------------------------- function THotkeyConfig.LoadConfigFromXML(const AXMLFile:string='hotkey.xml'):boolean; var M_ConfigXML:TXMLDocument; M_SearchNode, M_PropNode:IXMLNODE; M_Index :integer; begin result:=False; //Q:爲何構造方法參數爲nil就會無法解析節點? M_ConfigXML:=TXMLDocument.Create(Self); try //OPEN XML CONFIGURE FILE with M_ConfigXML do begin LoadFromFile(AXMLFile); Options := []; Active := True; end; //RECORD ASSOCIATED XML CONFIGURATION FILE FAssociatedXML := AXMLFile; //GET THE ROOT WE WANT M_SearchNode:=XMLGetKeysetFather(M_ConfigXML); //GET COUNT FOR HOTKEY SETS FKeyInfoCount:=M_SearchNode.ChildNodes.Count ; SetLength(FKeyInfo, FKeyInfoCount); //LOOP TO READ EVERY KEYSET for M_Index := 0 to FKeyInfoCount - 1 do begin M_PropNode:=M_SearchNode.ChildNodes.Nodes[M_Index]; with FKeyInfo[M_Index] do begin FCaption := M_PropNode.ChildValues['caption']; FHKID := M_PropNode.ChildValues['hkid']; FMod := M_PropNode.ChildValues['mod']; FVK := M_PropNode.ChildValues['vk']; end; //end of with end; //end of for finally M_ConfigXML.Active := False; FreeAndNil(M_ConfigXML); end; end; //----------------------------------------------------------------------- //NAME: SaveConfigToXML //SUMM: 保存修改的熱鍵配置到XML文檔 //PARA: AXMLFile-XML文檔路徑 //RETN: TRUE-成功 //AUTH: CST //DATE: 2005-8-15 //DESC: 配置窗口確認關閉後調用 //----------------------------------------------------------------------- function THotkeyConfig.SaveConfigToXML(const AXMLFile:string='hotkey.xml'):boolean; var M_ConfigXML:TXMLDocument; M_SearchNode, M_PropNode:IXMLNODE; M_Index :integer; begin result:=False; M_ConfigXML:=TXMLDocument.Create(Self ); try //OPEN XML CONFIGURE FILE with M_ConfigXML do begin LoadFromFile(AXMLFile); Options := []; Active := True; end; //GET THE ROOT WE WANT M_SearchNode:=XMLGetKeysetFather(M_ConfigXML); //LOOP TO READ EVERY KEYSET for M_Index := 0 to FKeyInfoCount - 1 do begin M_PropNode:=M_SearchNode.ChildNodes.Nodes[M_Index]; with FKeyInfo[M_Index] do begin M_PropNode.ChildValues['caption']:=FCaption; M_PropNode.ChildValues['hkid']:=FHKID; M_PropNode.ChildValues['mod']:=FMod; M_PropNode.ChildValues['vk']:=FVK; end; //end of with end; //end of for //SAVE CHANGES M_ConfigXML.SaveToFile(AXMLFile); finally M_ConfigXML.Active := False; FreeAndNil(M_ConfigXML); end; end; //----------------------------------------------------------------------- //NAME: OpenConfigWindow //SUMM: 打開配置窗口 //PARA: N/A //RETN: N/A //AUTH: CST //DATE: 2005-8-15 //DESC: 窗體對象爲 FConfigureForm 成員 //----------------------------------------------------------------------- procedure THotKeyConfig.OpenConfigWindow ; var M_ErrMsg:String; begin if FConfigureForm = nil then FConfigureForm:=TFormHotkeyConfig.Create(nil); try //默認是不要保存修改 isXMLNeedSave:=False; //設置之前先注銷所有熱鍵 DisableAllHotkeys ; //打開設置窗口 FConfigureForm.ShowModal; if isXMLNeedSave then begin //修改後按下『確認』生效並保存 if EnableAllHotkeys then begin //新設置熱鍵注冊成功 MessageBox(Application.Handle, '所有熱鍵都成功注冊。'+#13+'點擊確認保存所有熱鍵設置。', '提示', MB_OK + MB_ICONINFORMATION); SaveConfigToXML(FAssociatedXML); end //end of if else begin //新設置熱鍵有沖突 M_ErrMsg:='您設置的熱鍵組合中有一項或多項沒有注冊成功。' + #13 + '也許是和其他應用程序産生了沖突,您可以嘗試更換其他按鍵組合。' + #13 + '請問是否仍然要保存這次的設置,如果保存請按“是”,我們將在下次軟件啓動的時候'+ '再次嘗試注冊您的熱鍵配置,您可以在這之前注銷或修改其他應用程序的沖突設置。'; if MessageBox(Application.Handle, PChar(M_ErrMsg), '提示',MB_YESNO+MB_ICONQUESTION)=IDYES then SaveConfigToXML(FAssociatedXML); end; end else begin //按下『取消』按鈕,但是還是要恢複原先的熱鍵 EnableAllHotkeys; end; finally FreeAndNil(FConfigureForm); end; end; {******************************************************** ********************************************************* **************** TFormHotkeyConfig ******************** ********************************************************* ********************************************************} //----------------------------------------------------------------------- //NAME: Create //SUMM: TFormHotkeyConfig的構造函數 //AUTH: CST //DATE: 2005-8-15 //DESC: 繼承TForm的構造函數,動態創建THotKeyEdit控件。 // 將窗體上的熱鍵接受控件的OnKeyDown事件改寫。 //----------------------------------------------------------------------- constructor TFormHotkeyConfig.Create(AOwner: TComponent); var M_Index, M_Top:integer; HKEdit:THotkeyEdit; const MLEFT = 10; MWIDTH = 200; MHEIGHT = 21; MMARGIN = 30; begin inherited; //HOTKEYEDITORS FEditList := TObjectList.Create ; M_Top := 0; for M_Index := 0 to FKeyInfoCount - 1 do begin //計算控件位置,縱向排列 M_Top:= MMARGIN + M_Index * (MHEIGHT+MMARGIN); //根據讀入的XML節點動態創建熱鍵編輯控件 HKEdit:=THotKeyEdit.Create(Self); with HKEdit do begin //定義樣式 Parent:=Self.GroupBoxLeft; SetBounds(MLEFT,M_Top,MWIDTH,MHEIGHT); LabelPosition := lpAbove ; EditLabel.Caption := FKeyInfo[M_Index].FCaption; EditLabel.Width := MWIDTH; //定義初始數據 VirtualKeyValue := FKeyInfo[M_Index].FVK; KeyModValue := FKeyInfo[M_Index].FMod; //按照定義的數據顯示熱鍵組合 DisplayHotKey; end; //end of with //保存組件到對象列表 FEditList.Add(HKEdit); end; //end of for Height:= M_Top + MHEIGHT + MMARGIN; end; //------------------------------------------------------------ // 確定 //------------------------------------------------------------ procedure TFormHotkeyConfig.ButtonYesClick(Sender: TObject); var M_Index:integer; begin //CONVERT HK_EDITOR DATA TO HOTKEY INFO ARRAY for M_Index := 0 to FKeyInfoCount - 1 do begin FKeyInfo[M_Index].FMod := (FEditList.Items[M_Index] as THotKeyEdit).KeyModValue ; FKeyInfo[M_Index].FVK := (FEditList.Items[M_Index] as THotKeyEdit).VirtualKeyValue; end; //END OF CONVERT Close; isXMLNeedSave:=True; end; //------------------------------------------------------------ // 取消 //------------------------------------------------------------ procedure TFormHotkeyConfig.ButtonNoClick(Sender: TObject); begin if MessageBox(Self.Handle,'是否要放棄修改並關閉窗口?','提示',MB_YESNO+mb_iconinformation) = IDYES then begin Close; isXMLNeedSave:=False; end; end; {******************************************************** ********************************************************* ********************* THotKeyEdit ********************* ********************************************************* ********************************************************} //----------------------------------------------------------------------- // HotKeyEdit控件構造函數 //----------------------------------------------------------------------- constructor THotKeyEdit.Create(AOwner: TComponent); begin inherited; ReadOnly := True; OnKeyDown := GetHotKeyDownEvent; OnExit := LostFocusEvent; FValidateColor := clSkyBlue; end; //----------------------------------------------------------------------- //NAME: GetDisplayText //SUMM: 將熱鍵信息轉換爲顯示字串 //PARA: N/A //RETN: 熱鍵轉換的顯示結果 //AUTH: CST //DATE: 2005-8-15 //DESC: 型如:"Ctrl + Alt + Shift + A "爲正確 // 數據來源 FVirtualKeyValue, FModValue // 判斷組合是否合法,記錄在FKeySetValid中 //----------------------------------------------------------------------- function THotKeyEdit.GetDisplayText:string; var M_strDisplay:String; const SPLUS = ' + '; begin FKeySetValid := True; //處理按鍵組合 case FModValue of 1: M_strDisplay:='Alt + '; 2: M_strDisplay:='Ctrl + '; 3: M_strDisplay:='Ctrl + Alt + '; 4: M_strDisplay:='Shift + '; 5: M_strDisplay:='Shift + Alt + '; 6: M_strDisplay:='Ctrl + Shift + '; 7: M_strDisplay:='Ctrl + Shift + Alt + '; else begin M_strDisplay := ''; FKeySetValid := False; end; end; //處理鍵碼 case FVirtualKeyValue of VK_F1..VK_F12: M_strDisplay := M_strDisplay + 'F'+IntToStr(FVirtualKeyValue - VK_F1 + 1); Ord('A')..Ord('Z'), Ord('0')..Ord('9'): M_strDisplay := M_strDisplay + Chr(FVirtualKeyValue); else begin M_strDisplay := M_strDisplay ; FKeySetValid := False; end; end; result:=M_strDisplay; end; //----------------------------------------------------------------------- //NAME: LostFocusEvent //SUMM: 控件失去焦點時檢查熱鍵合法性 //PARA: Sender-控件 //RETN: N/A //AUTH: CST //DATE: 2005-8-15 //DESC: 此函數將用來覆蓋4個TLabelEdit的OnExit事件 //----------------------------------------------------------------------- procedure THotKeyEdit.LostFocusEvent(Sender:TObject); begin if not FKeySetValid then begin Text:=''; FModValue := 0; FVirtualKeyValue := 0; end; end; //----------------------------------------------------------------------- //NAME: GetHotKeyDownEvent //SUMM: 接受用戶輸入的熱鍵並判斷是否合法的時間函數 //PARA: Sender-控件 Key-虛擬鍵碼 Shift-輔助鍵信息 //RETN: N/A //AUTH: CST //DATE: 2005-8-15 //DESC: 此函數將用來覆蓋OnKeyDown事件 // //----------------------------------------------------------------------- procedure THotKeyEdit.GetHotKeyDownEvent(Sender: TObject; var Key: Word; Shift: TShiftState); var M_StrDisplay:String; begin //READ HOTKEY SET MODE FModValue := 0; if (ssCtrl in Shift) then FModValue := FModValue + 2; if (ssAlt in Shift) then FModValue := FModValue + 1; if (ssShift in Shift) then FModValue := FModValue + 4; //READ HOTKEY SET VIRTUAL KEY FVirtualKeyValue := Key; //GET DISPLAY TEXT AND JUDGE WHETHER KEYSET IS VALIDATE M_StrDisplay := GetDisplayText; //REFLECTION if FKeySetValid then ActionOnHotKeyValid else ActionOnHotKeyInvalid ; Text := M_StrDisplay; end; //--------------------------------------- // 在動態創建時顯示組合鍵 //--------------------------------------- procedure THotKeyEdit.DisplayHotKey; begin Text := GetDisplayText ; end; //--------------------------------------- // 熱鍵組合合法執行的代碼 //--------------------------------------- procedure THotKeyEdit.ActionOnHotKeyValid; begin Color:=FValidateColor; end; //--------------------------------------- // 熱鍵組合非法執行的代碼 //--------------------------------------- procedure THotKeyEdit.ActionOnHotKeyInvalid; begin Color := clWhite; end; end. 6 小結6.1 沒有解決的一些問題TXMLDocument的對象在創建時如果Owner參數爲nil則無法解析到節點,如果使用帶文檔路徑參數的重載的構造函數也會如此,因爲在TXMLDocument的源碼中重載的版本Owner也是nil。爲了規避這個問題,我犧牲了效率而將Owner置爲Application並手動釋放了文檔對象。考慮到如果使用self可能會因爲釋放兩次而産生錯誤,而Application的釋放影響不會很大。 沒有實現對于XML文檔合法性的檢驗,僅過濾了超出範圍的MOD和VK值,對于HKID是否唯一沒有做檢查。 沒有實現對于用戶定義的熱鍵之間的沖突,在TformHotKeyConfig中沒有判斷是否設置的了相同的熱鍵。 熱鍵編輯控件可以注冊到Pallete中,ThotKeyConfig類尚未控件化,如果控件化可能需要改變對象調用方式,公開構造函數允許創建多個實例。取消MgetInstance方法。 6.2 程序心得雖然Delphi中對于熱鍵的使用也不繁瑣,但是使用本方法可以利用流行的xml記錄熱鍵是挺誘人的,只要稍加修改就可以繼承到應用程序中。而且這樣自由度比較高,熱鍵數量、名稱、布局都是可以自定義的。 在組件化上,我只封裝了ThotKeyEdit控件,而沒有將ThotKeyConfig類嚴格封裝。因此只能通過代碼手動創建和調用。熱鍵編輯窗口是一個挺方便的設計,可以讓使用該類的用戶不必關心熱鍵編輯的實現。 在不斷的OO開發中,我也在摸索,程序中難免會有一些不如意之處,我誠心希望各位給我提出意見,我也很高興能在相關的問題上和大家一起討論討論。 本程序的相關代碼和測試示例可以在我的YAHOO公文包上下載。
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 
 熱帖排行
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有