安徽合肥智能機械研究所 張建軍
在開發Windows應用程序時,軟件人員希望所編制的程序具有風格獨特的用戶界面,為此不惜采用一些占用系統內存資源頗多的第三方OCX控件,結果導致程序運行速度變慢或者打包后的安裝程序體積太大的缺點。其實,如果我們仔細研究一下Windows提供的幾百個WinAPI,就不難發現,通過直接調用API函數,發送、接收或者攔截系統消息等方法,同樣可以實現在某些情況下只能依靠調用OCX才能達到的界面效果。
例如:為我們所熟知的屏幕抓圖軟件HyperSnap,在其強大的屏幕抓圖功能背后,還具有一項比較特殊的界面效果。
通常情況下,當用鼠標點擊一個Windows窗體左上角的Icon時,所看到的系統菜單一般都是固定不變的。
HyperSnap的窗體改變了標準“系統菜單”,增加了多個新菜單項,并分別賦予它們不同的功能。其實這種效果的實現并不復雜,主要通過調用GetSystemMenu、AppendMenu等API函數完成。下面,我們就以C++Builder為例,討論一下如何在自己的應用程序中實現類似HyperSnap的界面效果,并給出完整代碼實例。
1.API函數介紹
⑴ GetSystemMenu
① 功能:
允許訪問(拷貝或修改)系統菜單,普通Windows窗體如果未改變其菜單項狀態,自動采用標準Windows菜單,即“恢復”、“移動”、“最大化”、“最小化”、“關閉”等。
② 原形:
HMENU GetSystemMenu(
HWND hWnd,
BOOL bRevert
);
③ 入口參數:
HWND為預改變系統菜單的窗體句柄。
bRevert為標志。
當bRevert為假,GetSystemMenu返回HWND代表窗體的拷貝,初始狀態下,拷貝與原窗體一致,但允許修改。
當bRevert為真,GetSystemMenu將HWND代表的窗體菜單恢復默認狀態,之前對菜單的修改被取消。
④ 返回值:
當bRevert為假,返回HWND代表的窗體拷貝的句柄,當bRevert為真,返
回值為Null。
⑵ AppendMenu
①功能:
在指定菜單的最后插入一個菜單項,并可規定該菜單項的文字內容、外觀和觸發事件。
② 原形:
BOOL AppendMenu(
HMENU hMenu
UINT uFlags
UINT uIDNewItem
LPCTSTR lpNewItem
);
③ 入口參數:
hMenu為欲增加菜單項的菜單句柄。
uFlags為新增菜單項的標志,可以是幾種系統常量的組合。
UIDNewItem為新增菜單項的標識。
lpNewItem為新增菜單項的文字內容,可取MF_STRING、MF_SEPARATOR等值。
④ 返回值:
成功返回0,失敗返回非0。
⑶ WM_SYSCOMMAND
當點擊菜單項時觸發的系統消息。
⒉ 編程實例
⑴ 新建工程
在C++ Builder 5.0 IDE 中新建工程Project1,Project1中包含Form1。
⑵ Form_Click事件
void __fastcall TForm1::FormClick(TObject *Sender)
{
ChangeSystemMenu(Form1, "-", 0);
ChangeSystemMenu(Form1, "自定義項目...", 99);
Application->OnMessage = Form1->RegisterMsg;//指定窗體消息處理函數
}
⑶ 自定義消息處理過程
void __fastcall TForm1::RegisterMsg(tagMSG &Msg, bool &Handled)
{
if (Msg.message == WM_SYSCOMMAND)
if (Msg.wParam == 99)
ShowMessage("你點擊了自定義菜單");//自定義菜單響應代碼
}
⑷ 改變系統菜單過程
void __fastcall ChangeSystemMenu(TForm *Form, AnsiString Item, Word ItemID)
{
void* NormalSystemMenu;
void* MinSystemMenu;
char* AItem = new char[255];
PChar PItem;
NormalSystemMenu = GetSystemMenu(Form->Handle, false);
MinSystemMenu = GetSystemMenu(Application->Handle, false);
if (Item == "-")
{
AppendMenu(NormalSystemMenu, MF_SEPARATOR, 0, 0);//增加菜單分隔線
AppendMenu(MinSystemMenu, MF_SEPARATOR, 0, 0);//增加菜單分隔線
}
else
{
PItem = StrPCopy(AItem, Item);
AppendMenu(NormalSystemMenu, MF_STRING, ItemID, PItem);//增加菜單項文字
AppendMenu(MinSystemMenu, MF_STRING, ItemID, PItem);//增加菜單項文字
}
}
⒊ 實例代碼
⑴ Unit1.h文件
//---------------------------------------------------------------------------
#ifndef unitAppendMenuH
#define unitAppendMenuH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
void __fastcall RegisterMsg(tagMSG &Msg, bool &Handled);//自定義菜單響應事件
void __fastcall FormClick(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
⑵ Unit1.cpp文件
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "unitAppendMenu.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall ChangeSystemMenu(TForm *Form, AnsiString Item, Word ItemID)
{
void* NormalSystemMenu;
void* MinSystemMenu;
char* AItem = new char[255];
PChar PItem;
NormalSystemMenu = GetSystemMenu(Form->Handle, false);
MinSystemMenu = GetSystemMenu(Application->Handle, false);
if (Item == "-")
{
AppendMenu(NormalSystemMenu, MF_SEPARATOR, 0, 0);//增加菜單分隔線
AppendMenu(MinSystemMenu, MF_SEPARATOR, 0, 0);//增加菜單分隔線
}
else
{
PItem = StrPCopy(AItem, Item);
AppendMenu(NormalSystemMenu, MF_STRING, ItemID, PItem);//增加菜單項文字
AppendMenu(MinSystemMenu, MF_STRING, ItemID, PItem);//增加菜單項文字
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::RegisterMsg(tagMSG &Msg, bool &Handled)
{
if (Msg.message == WM_SYSCOMMAND)
if (Msg.wParam == 99)
ShowMessage("你點擊了自定義菜單");//自定義菜單響應代碼
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClick(TObject *Sender)
{
ChangeSystemMenu(Form1, "-", 0);
ChangeSystemMenu(Form1, "自定義項目...", 99);
Application->OnMessage = Form1->RegisterMsg;//指定窗體消息處理函數
}
//---------------------------------------------------------------------------
4.實例效果
以上代碼在Win98、C++Builder 5.0環境下調試通過
|