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

Win32開發入門(5) 具有單選標記的菜單

編輯:關於C++

帥哥們,美女們,下午好,我又來誤人子弟,請做好准備。

今天,我們的目的是,想要實現 下圖中的這種菜單效果。

就是一種類似單選按鈕的菜單,多個菜單項中,同時只有一個會被選中。

首先,我們 在資源編輯器中,設計一個菜單資源。這個資源編輯器在管理資源ID的時候,有些問題,有時候不同步 更新,有時候會保存不到,反正就會混亂。如果遇到問題,你可以先把菜單設計好,接著打開 resource.h,手動把這些ID和它的值改一下。為了使這三個菜單項能形成一個組,必須讓它們的ID值是 連續的,比如我這裡讓它們分別為501,502,503。

101指的是整個菜單資源,後三個都是子菜單項。如果想更保險的話,可以在【 解決方案資源管理器】中右擊資源文件(.rc結尾),選擇【查看代碼】,然後檢查一下是否正確就可 以了。

現在菜單弄好了,下面我們來了解一下把菜單添加到窗口的兩個類型。

第一種是類級別的, 也就是我們在設計窗口類時,直接指定給WNDCLASS結構的lpszMenuName成員,這樣做意味著,在調用 CreateWindow函數創建窗口時,無論你是否為窗口指定菜單,最終顯示的窗口上都會有菜單,因為它是 基於整個窗口類的。

// 在這裡把菜單附加上,成為類級別     
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAIN);//整個菜單資源的ID,不是菜單項
HWND 

hm = CreateWindow(     
    L"MainWd",     
    L"我的應用程序",     
    WS_OVERLAPPEDWINDOW,     
    25,     
    18,     
    380,     
    280,     
    NULL,     
    NULL,     
    hthisInstance,     
    NULL);

這樣在我們創建窗口時,哪怕你把hMenu參數設為NULL,最後顯示的窗口都會有菜 單,因為菜單是屬於窗口類本身的。

另一種方式,就是不設置為類級別的菜單,而是在調用 CreateWindow時指定給hMenu參數。

HWND hm = CreateWindow(     
    L"MainWd",     
    L"我的應用程序",     
    WS_OVERLAPPEDWINDOW,     
    25,     
    18,     
    380,     
    280,     
    NULL,     
    LoadMenu(hthisInstance,MAKEINTRESOURCE(IDR_MAIN)),     
    hthisInstance,     
    NULL);

同時我們把設計窗口類時設置菜單的代碼注釋掉。

// 在這裡把菜單附

加上,成為類級別     
//wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAIN);//整個菜單資源的ID,不是菜單項

然後, 我們運行這個程序,它還是有菜單的。

接著,我們把CreateWindow的hMenu參數設置為NULL,

HWND hm = CreateWindow(   

  
    L"MainWd",     
    L"我的應用程序",     
    WS_OVERLAPPEDWINDOW,     
    25,     
    18,     
    380,     
    280,     
    NULL,     
    /*LoadMenu(hthisInstance,MAKEINTRESOURCE(IDR_MAIN))*/ 
    NULL,     
    hthisInstance,     
    NULL);

看看這時候運行程序,還能不能看到菜單。



現在就看不到菜單了,這兩種加載菜單的方式,就區別在這裡。

要為菜單實現單選標 記,調用CheckMenuRadioItem函數,第一個參數是要在其子項中設置的單選的菜單的句柄,第二個參數 和第三個參數指定合並為一個組的ID范圍,在這個范圍內的菜單項被看人為同一組,這一組中,每一次 只能有一項被checked,第四個參數就指定在這組項中哪一個被選中,最後一個參數決定是用ID來標識 還用從0開始的索引。

但是,我們在改變菜單項單選狀態前,必須獲得【水果】彈出菜單的句柄 。

我們先來看一下,一般菜單欄的層次結構。

它就像一個樹形結構,一層一層往下展開,上圖中,紅色矩形畫的部分是菜單的根,即整個 菜單欄,藍色矩形標注的是菜單欄的下一級,彈出菜單,如【文件】、【編輯】、【視圖】這些,它們 一般只負責彈出子項列表,自身不響應用戶選擇命令,這也是我們在資源編輯器中設計菜單時,不需要 給它們ID號的原因。

在【文件】下面又有了項,如圖中黃色矩形標注的地方,如【新建】、【 打開】。

知道這個後,我們的思路就有了。

1、調用GetMenu( 窗口句柄 )獲取窗口中菜 單欄的句柄;

2、調用GetSubMenu(  菜單欄句柄,0 )獲得【水果】彈出菜單的句柄,0表 示菜單欄中的第一個元素,如果第二個就是1,我們的彈出菜只有【水果】一項;

3、調用 CheckMenuRadioItem函來來Check菜單。

因為我們是在響應WM_COMMAND消息時作出響應的,所以 這些代碼應寫在WindowProc中。

LRESULT CALLBACK WindowMainProc(HWND hwnd, UINT msg, 

WPARAM wParam, LPARAM lParam)     
{     
    // 獲取窗口上的整個菜單欄的句柄     
    HMENU hmm = GetMenu(hwnd);     
    // 獲取第一個彈出菜單,即[水果]菜單     
    HMENU hfmn = GetSubMenu(hmm, 0);     
    switch(msg)     
    {     
    case WM_COMMAND:     
        {     
        .......

菜單句柄是HMENU類型,所以GetMenu和GetSubMenu函數都返回HMENU類型的 值。其實,這裡我給大家推薦一個技巧,就是使用auto關鍵字,我們無需管它函數什麼,統一用auto關 鍵字,它會根據代碼上下文推斷數據類型,就像C#裡面的var聲明變量一樣。所以,我們上面的代碼可 以改為:

LRESULT CALLBACK WindowMainProc(HWND hwnd, UINT msg, WPARAM wParam, 

LPARAM lParam)     
{     
    // 獲取窗口上的整個菜單欄的句柄     
    auto hmm = GetMenu(hwnd);     
    // 獲取第一個彈出菜單,即[水果]菜單     
    auto hfmn = GetSubMenu(hmm, 0);     
    switch(msg)     
    {     
    case WM_COMMAND:     
        {     
         ........

然後,我們響應命令消息。

switch(msg)     
{     
case WM_COMMAND:     
    {     
        //判斷用戶選了哪個菜單     
        switch(LOWORD(wParam))     
        {     
        case IDM_APPLE:     
            CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_APPLE, MF_BYCOMMAND);     
            MessageBox(hwnd,L"你選擇了蘋果。",L"提示",MB_OK);     
            break;     
        case IDM_PEAR:     
            CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_PEAR, MF_BYCOMMAND);     
            MessageBox(hwnd,L"你選擇了梨子。", L"提示", MB_OK);     
            break;     
        case IDM_BANANA:     
            CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_BANANA, MF_BYCOMMAND);     
            MessageBox(hwnd, L"你選擇了香蕉。", L"提示", MB_OK);     
            break;     
        }     
    }     
    return 0;

這樣就得到單選菜單的效果了。下面是完整的代碼清單。

#include 

<Windows.h>     
#include "resource.h"     
         
// 聲明消息處理函數     
LRESULT CALLBACK WindowMainProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);     
         
//入口點     
int WINAPI WinMain(     
    HINSTANCE hthisInstance,//當前實例句柄     
    HINSTANCE hPrevInstance,//錢一個實例句柄,一般不使用     
    LPSTR cmdline,//命令行參數     
    int nShow)//窗口的顯示方式     
{     
    // 設計窗口類     
    WNDCLASS wc = { };     
    wc.lpszClassName = L"MainWd";     
    wc.hInstance  = hthisInstance;     
    wc.lpfnWndProc = WindowMainProc;     
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);     
    // 在這裡把菜單附加上,成為類級別     
    //wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAIN);//整個菜單資源的ID,不是菜單項     
    // 讓窗口自動重繪     
    wc.style = CS_HREDRAW | CS_VREDRAW;     
    // 注冊窗口類     
    RegisterClass(&wc);     
    // 創建窗口     
    HWND hm = CreateWindow(     
        L"MainWd",     
        L"我的應用程序",     
        WS_OVERLAPPEDWINDOW,     
        25,     
        18,     
        380,     
        280,     
        NULL,     
        LoadMenu(hthisInstance,MAKEINTRESOURCE(IDR_MAIN)),     
        hthisInstance,     
        NULL);     
    if(hm == NULL)     
        return 0;     
    // 顯示窗口     
    ShowWindow(hm, SW_SHOW);     
    // 消息循環     
    MSG msg;     
    while(GetMessage(&msg, NULL, 0, 0))     
    {     
        TranslateMessage(&msg);     
        DispatchMessage(&msg);     
    }     
    return 0;     
}     
         
LRESULT CALLBACK WindowMainProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)     
{     
    // 獲取窗口上的整個菜單欄的句柄     
    auto hmm = GetMenu(hwnd);     
    // 獲取第一個彈出菜單,即[水果]菜單     
    auto hfmn = GetSubMenu(hmm, 0);     
    switch(msg)     
    {     
    case WM_COMMAND:     
        {     
            //判斷用戶選了哪個菜單     
            switch(LOWORD(wParam))     
            {     
            case IDM_APPLE:     
                CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_APPLE, MF_BYCOMMAND);  

   
                MessageBox(hwnd,L"你選擇了蘋果。",L"提示",MB_OK);     
                break;     
            case IDM_PEAR:     
                CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_PEAR, MF_BYCOMMAND);   

  
                MessageBox(hwnd,L"你選擇了梨子。", L"提示", MB_OK);     
                break;     
            case IDM_BANANA:     
                CheckMenuRadioItem(hfmn, IDM_APPLE, IDM_BANANA, IDM_BANANA, MF_BYCOMMAND); 

    
                MessageBox(hwnd, L"你選擇了香蕉。", L"提示", MB_OK);     
                break;     
            }     
        }     
        return 0;     
    case WM_DESTROY:     
        PostQuitMessage(0);     
        return 0;     
    default:     
        return DefWindowProc(hwnd, msg, wParam, lParam);     
    }     
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved