程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> Win32開發入門(4) 創建菜單

Win32開發入門(4) 創建菜單

編輯:關於C++

我們當然知道 ,現在,在實際開發中肯定不會像我這樣寫Win32程序的,你看,連個WinMain都要N行代碼。但很多人 不明白什麼叫學習,什麼叫探索。實際上,通常能用於實際開發中的技巧只是占我們對客觀世界的認識 總和不到20%,所以,如果你有興趣計算一下,估計有80%的知識你不知道用到哪裡去了。就算我們今後 不會把Win32程序投入到實際操作中,然而如果你了解過這東西,你會發現很多時候對我們是有幫助的 。

哪怕只是簡單認識一下Win32的一些原理,相信對於日後編程的學習和成長,是有益處的。

為了提高誤人子弟的效果,上面我說了幾段F話,下面開始今天的正題。

要在窗口上添 加菜單,當然你可能會研究出N種方法,不過,這裡我說兩種,一種相當復雜,另一種稍微簡單。

方法一,用代碼添加菜單

這種方法的思路是:首先在全局范圍內定義一個HMENU的變量 ,用來保存窗口中菜單欄的句柄,根菜單(菜單欄)可以CreateMenu函數來創建,接著可以使用 AppendMenu函數或者InsertMenuItem函數來創建菜單項。

句柄就是內存中各種資源的ID,比如 圖標,圖片,字符串等。我們的菜單也是一種資源。

下面我寫了一個函數,用來動態創建菜單 。

void CreateMyMenu()     
{     
    hRoot = CreateMenu();     
    if(!hRoot)     
        return;     
    HMENU pop1 = CreatePopupMenu();     
    AppendMenu(hRoot,     
        MF_POPUP,     
        (UINT_PTR)pop1,     
        L"操作");     
    // 一種方法是使用AppendMenu函數     
    AppendMenu(pop1,     
        MF_STRING,     
        IDM_OPT1,     
        L"飛機");     
         
    // 另一種方法是使用InsertMenuItem函數     
    MENUITEMINFO mif;     
    mif.cbSize = sizeof(MENUITEMINFO);     
    mif.cch = 100;     
    mif.dwItemData  = NULL;     
    mif.dwTypeData = L"機關槍";     
    mif.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;     
    mif.fState = MFS_ENABLED;     
    mif.fType = MIIM_STRING;     
    mif.wID = IDM_OPT2;     
         
    InsertMenuItem(pop1,IDM_OPT2,FALSE,&mif);     
         
}

hRoot是在外部定義的全局變量,保存菜單欄的標識。完整的代碼如下:

#include 

<Windows.h>     
         
#define IDM_OPT1     301     
#define IDM_OPT2     302     
         
HMENU hRoot;     
void CreateMyMenu();//創建菜單     
         
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);     
         
         
int CALLBACK WinMain(HINSTANCE hInstance,     
                    HINSTANCE hPrevInstance,     
                    LPSTR cmdLine,     
                    int nShow)     
{     
    CreateMyMenu();//創建菜單     
    WCHAR* cn = L"Myapp";     
    WNDCLASS wc={   };     
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;     
    wc.lpszClassName = cn;     
    wc.style = CS_HREDRAW | CS_VREDRAW;     
    wc.hInstance = hInstance;     
    wc.lpfnWndProc = (WNDPROC)MyWinProce;     
    RegisterClass(&wc);     
    HWND hm = CreateWindow(cn,     
        L"我的應用程序",     
        WS_OVERLAPPEDWINDOW,     
        20,     
        15,     
        420,     
        360,     
        NULL,     
        hRoot,     
        hInstance,     
        NULL);     
    if( hm == NULL )     
        return 0;     
    ShowWindow(hm,nShow);     
    MSG msg;     
    while(GetMessage(&msg,NULL,0,0))     
    {     
        TranslateMessage(&msg);     
        DispatchMessage(&msg);     
    }     
         
    return 0;     
}     
         
         
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)     
{     
    switch(msg)     
    {     
    case WM_DESTROY:     
        //DestroyMenu(hRoot);     
        PostQuitMessage(0);     
        return 0;     
    default:     
        return DefWindowProc(hwnd, msg, wParam,lParam);     
    }     
}     
         
void CreateMyMenu()     
{     
    hRoot = CreateMenu();     
    if(!hRoot)     
        return;     
    HMENU pop1 = CreatePopupMenu();     
    AppendMenu(hRoot,     
        MF_POPUP,     
        (UINT_PTR)pop1,     
        L"操作");     
    // 一種方法是使用AppendMenu函數     
    AppendMenu(pop1,     
        MF_STRING,     
        IDM_OPT1,     
        L"飛機");     
         
    // 另一種方法是使用InsertMenuItem函數     
    MENUITEMINFO mif;     
    mif.cbSize = sizeof(MENUITEMINFO);     
    mif.cch = 100;     
    mif.dwItemData  = NULL;     
    mif.dwTypeData = L"機關槍";     
    mif.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;     
    mif.fState = MFS_ENABLED;     
    mif.fType = MIIM_STRING;     
    mif.wID = IDM_OPT2;     
         
    InsertMenuItem(pop1,IDM_OPT2,FALSE,&mif);     
         
}

方法二,通過編輯資源來添加菜單

上面的方法雖然創建了菜單,但你 也看到了,是相當地不方便,所以,下面我重點介紹一下用資源編輯器來創建菜單資源。

在你 的開發工具上,依次找到菜單項【視圖】【資源視圖】。

在資源視圖中,右擊項目根節點,從彈出的菜單中選擇【添加】【資源】。

在隨後彈出的對話框中,選擇Menu,單擊右邊的“新建”按鈕。

可以通過屬性窗口來重命名菜單的ID。

我們可以使用可視化視圖來建立菜單,為了可以在代碼中使用,給需要的菜單一個ID,這個 名字你可以自己喜歡,只是慣用的是以IDM_開頭,意思是Menu ID,比如IDC開頭的,意思是Control ID 等等。

編輯好之後,保存,在【解決方案資源管理器】中你會看到一個resource.h 文件,其實我們為資源定義的ID都以宏的形式聲明的,不信你打開看看。

資源ID都是數字,只是為它定義個名字,方便識別罷了,就好像人們平時只叫你的名字或者 小名,你見過誰會叫你的身份證號碼的?

開發工具生成的ID有時候會有問題,或者有些ID我們 在程序中沒用上,如果你覺得它們留在代碼文件中會影響市容的話,你可以這樣:

1、在【資源 視圖】窗口中,右擊,從彈出的快捷菜單中選擇【資源符號...】,彈出一個窗口,這裡可以看到應用 程序中的資源ID列表,以及哪些ID已被使用,但是,這個窗口中顯示的內容,有時候不准確,有些ID明 明沒有被使用,它右邊卻打上了勾。

這裡可以修改ID的值,也可以新建資源ID,所以,你也可 以在這裡預先為資源分配ID,然後在屬性窗口設置資源的標識時,從下拉列表中選擇指定的ID。資源ID 的名字和數值不能重復,但是,不同的資源是可以使用同一個資源ID的。例如,通常在應用程序中,某 些菜單項的功能和工具欄上的按鈕是一一對應的,功能相同,這種情況下,我們可以考慮讓它們共用一 個ID。

2、你可以直接打開resource.h頭文件,直接在上面修改。

響應菜單命令

當用戶單擊某個菜單項後,窗口處理程序(WindowProc)會收到一條WM_COMMAND消息,它的兩個附加參 數如下:

在收到WM_COMMAND後,我們可以用LOWORD取得它的低數位, 上表中已經說明,wParam的低位值表示菜單的資源ID,我們通過它的值與哪個菜單的ID相等,就知道用 戶點擊了哪個菜單項。

所以,我們的程序代碼現在應為:

#include 

<Windows.h>     
#include "resource.h"     
         
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);     
         
         
int CALLBACK WinMain(HINSTANCE hInstance,     
                    HINSTANCE hPrevInstance,     
                    LPSTR cmdLine,     
                    int nShow)     
{     
    WCHAR* cn = L"Myapp";     
    WNDCLASS wc={   };     
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;     
    wc.lpszClassName = cn;     
    wc.style = CS_HREDRAW | CS_VREDRAW;     
    wc.hInstance = hInstance;     
    wc.lpfnWndProc = (WNDPROC)MyWinProce;     
    RegisterClass(&wc);     
    HWND hm = CreateWindow(cn,     
        L"我的應用程序",     
        WS_OVERLAPPEDWINDOW,     
        20,     
        15,     
        420,     
        360,     
        NULL,     
        // 加載菜單資源     
        LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAIN)),     
        hInstance,     
        NULL);     
    if( hm == NULL )     
        return 0;     
    ShowWindow(hm,nShow);     
    MSG msg;     
    while(GetMessage(&msg,NULL,0,0))     
    {     
        TranslateMessage(&msg);     
        DispatchMessage(&msg);     
    }     
         
    return 0;     
}     
         
         
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)     
{     
    switch(msg)     
    {     
    case WM_COMMAND:     
        {     
            // 取出資源Id值     
            // 並判斷用戶選擇了哪個菜單項     
            switch(LOWORD(wParam))     
            {     
            case IDM_PLANE:     
                MessageBox(hwnd,L"灰機來了。",L"提示",MB_OK);     
                break;     
            case IDM_GUN:     
                MessageBox(hwnd,L"讓炮彈飛。",L"提示",MB_OK);     
                break;     
            case IDM_MT_GUN:     
                MessageBox(hwnd,L"山炮欲來風滿樓。",L"提示",MB_OK);     
                break;     
            default:     
                break;     
            }     
        }     
        return 0;     
    case WM_DESTROY:     
        PostQuitMessage(0);     
        return 0;     
    default:     
        return DefWindowProc(hwnd, msg, wParam,lParam);     
    }     
}

在注冊窗口類時,如要設置菜單,調用LoadMenu函數,第一個參數是當前程序實例的句柄, 從WinMain的參數中獲得,第二個參數是菜單的ID,因為這裡要名字,字符串,而我們的ID都是數值, 可通過MAKEINTRESOURCE宏轉換。至於MessageBox函數就不用我介紹了。

好了,我們的應用程序已經創建了菜單了。

呵,有人說我的編程學習方法很奇特,其 實,我們何苦要墨守成規呢,局限在定勢思維中呢?枯躁無味的東西,你可以人為地讓它變得充滿樂趣 ,關鍵是你的心態罷了。這讓我想起,以前某同學A跟我討論兩個問題:

1、我的程序只想保存 用戶的一些使用設置,用數據庫沒必要,寫注冊不環保;

2、我有一個dll類庫,我希望最後我 的程序既可以引用它,但同時只生成一個exe文件,能做到吧。

我就說了,問題一好辦,你定義 一個存放設置項的類,把它直接進行XML序列化和反序列化就完事了,這既能保存數據,又可以封裝對 象。如果不想讓別人看到XML文件中的內容,就把它用DES算法加密/解密;而第二個問題,你把dll文件 當成資源嵌入到程序的資源文件中,運行時如果要用到類庫的類,那就把它反射出來,動態調用就行了 。

然後他說,這好像沒有人這樣做,老師也沒教過。

我說:靠,你老爸小時候教過你泡 妞嗎?你一上大學怎麼就學會了泡妞?四年大學還換了N個妞,我一個都沒換成,你的愛情事業如此成 功。再說了,呂不韋臨死前有教過秦始皇怎麼統一中華嗎?難道秦始皇會說:以前沒人統一過華夏,我 怎麼統一?最後他老人家還是把六國給干掉了。

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