按钮和组合框 WinAPI

Push button and combo box WinAPI

我正在尝试做一些 windows 编程。我创建了一个组合框和一个按钮。我的 objective 是,当用户 select 在组合框中添加一个项目时,按钮被激活,需要单击才能继续。到目前为止我已经做了这样的事情:

这就是我创建组合框的方式:

Func.h

#ifndef FUNCS_H

#define FUNCS_H

// Winapi headers....
#include <windows.h>
#include <windowsx.h>
#include <shlobj.h>

//created lib
#include "Resource.h"

// Standard C/C++ headers...
#include <iostream>
#include <string>
#include <dirent.h> // directory manipulation....
#include <cstring>
#include <fstream>


using std::cout;
using std::endl;
using std::string;
using std::ofstream;


HWND hselectOK;
HWND hComboBox1;




void createControls(HWND hwnd) // Create our combo box
{

    HWND hselectFeature;



    HINSTANCE hInstance = GetModuleHandle(NULL);

    // Create our List box
    hComboBox1 = CreateWindow(WC_COMBOBOX,"", CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_CHILD |WS_OVERLAPPED |WS_VISIBLE , 7, 20, 300, 100, hwnd, NULL, hInstance, NULL);
    SendMessage(hComboBox1, CB_ADDSTRING, 0,(LPARAM)"Histogram of Oriented Gradients (HOG)");
    SendMessage(hComboBox1, CB_ADDSTRING, 0,(LPARAM)"Scale Invariant Feature Transform (SIFT)");
    SendMessage(hComboBox1, CB_ADDSTRING, 0,(LPARAM)"Speeded Up Robust Features (SURF)");

   // SendMessage(hComboBox1, CB_SETCURSEL, (WPARAM)2,(LPARAM)0); //CB_SETCURSEL

    // Create our push bottons
    hselectFeature = CreateWindow("STATIC", "Select Feature", SS_LEFT | WS_CHILD, 320,20, 100, 21,hwnd, (HMENU)1, hInstance, NULL);
    ShowWindow(hselectFeature,1);

    hselectOK = CreateWindow("BUTTON", "Ok", WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON | WS_DISABLED, 320,45, 100, 21,hwnd, NULL, hInstance, NULL);


}

#endif // FUNCS_H

WinProc.h

#ifndef WINPROC_H

#define WINPROC_H

// Winapi Headers
#include <CommDlg.h>
#include <winuser.h>

// OpenCV headers
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

// Standard C/C++ headers
#include <iostream>
#include <string>

// Created headers;
#include "Funcs.h"
#include "Resource.h"

using std::cout;
using std::endl;
using std::string;

using namespace cv;

int classNumber;


LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

    string dirPath;
    int comboIndex;

    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:

            createControls(hwnd);
            break;

        case WM_COMMAND:
            {

                switch(HIWORD(wParam))
                    {
                        case  CBN_SELCHANGE: // When user select item in combo box, enable the button.
                            {

                                EnableWindow(hselectOK, TRUE); // enable the button

                            }

                            break;

                            case BN_CLICKED: // When user has chosen a list, the button is used to proceed with further task associated to the selected item.
                            {


                                char listName[200];
                                comboIndex = SendMessage(hComboBox1, (UINT) CB_GETCURSEL, 0, 0);
                                SendMessage(hComboBox1, (UINT)CB_GETLBTEXT, (WPARAM)comboIndex, (LPARAM)listName);

                                if(comboIndex == 0)
                                {
                                   MessageBox(hwnd,listName, "You chose", MB_OK);
                                   // Want to Do some function here.

                                }

                                else if(comboIndex == 1)
                                {
                                   MessageBox(hwnd,listName, "You chose", MB_OK);
                                    // Want to Do some function here.

                                }

                                else if(comboIndex == 2)
                                {
                                    MessageBox(hwnd,listName, "You chose", MB_OK);
                                          // Want to Do some function here.
                                }

                            }

                            break;
                     }





                switch LOWORD(wParam)
                    {
                        case IDM_IMG_PATH:
                            {
                               dirPath = browseFolder(hwnd);

                               DialogBox(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_CLASS),hwnd, ClassDlgProcedure);
                               createClassLabelFile(hwnd, dirPath, classNumber);

                               return 0;
                            }

                        case IDM_EXIT:
                            {

                               PostMessage(hwnd, WM_CLOSE,0 , 0);

                            }

                            break;

                    }
            }
            break;

        case WM_DESTROY:
            PostQuitMessage(0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}




#endif // WINPROC_H

这些部分只是代码的一些相关部分。

问题是,当我使用caseIDM_EXIT退出程序时,总是出现caseBN_CLICKED下的消息框,然后程序关闭。我期望当我们关闭程序时,不会出现这样的消息框,但事实并非如此。我的意思是,消息框出现两次,一次是在您 select 单击按钮时,一次是在您要关闭程序时。为什么会这样。有什么想法或建议吗?

问题是您假设 WM_COMMAND 是您的 ComboBox 独有的消息,但事实并非如此。

看看这个老而金的blog post

引自作者,

The high-order word of the wParam parameter "specifies the notification code if the message is from a control". What does "control" mean here? Remember that you have to take things in context. The WM_COMMAND message is being presented in the context of Win32 in general, and in the context of the window manager in particular. Windows such as edit boxes, push buttons, and list boxes are commonly called "controls", as are all the window classes in the "common controls library". In the world of the window manager, a "control" is a window whose purpose is to provide some degree of interactivity (which, in the case of the static control, might be no interactivity at all) in the service of its parent window. The fact that the WM_COMMAND is used primarily in the context of dialog boxes further emphasizes the point that the term "control" here is just a synonym for "child window".

总而言之,在您的应用程序 window 中单击任何按钮都将转换为带有 BN_CLICKED wParam 的 WM_COMMAND。这包括 window.

的关闭按钮

要处理来自组合框的特定点击,您有两种选择。简单的方法是过滤发送消息的控件的 hWnd,您应该已经知道组合框的 window 句柄,与它进行比较应该没有问题。

另一种选择是定义您自己的消息并检查您的 WndProc 处理程序中的消息。网络上充满了如何定义您自己的 application/control 特定消息的示例。

当您单击 'Exit' 菜单时,windows 还会向 'WindowProcedure' 函数发送 'BN_CLICKED' 消息,这就是出现消息框的原因。您应该为按钮使用 ID 而不是像这样制作 'hmenu' 参数 'NULL':

    hselectOK = CreateWindow("BUTTON", "Ok", WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON | WS_DISABLED, 320,45, 100, 21,hwnd, 
(HMENU)305, // Here is the ID of your button ( You may use your own ID )
hInstance, NULL);

并且您必须像这样在 'case BN_CLICKED' 中添加一些身份验证代码:

case BN_CLICKED: // When user has chosen a list, the button is used to proceed with further task associated to the selected item.
{
    // You must do this check otherwise the message box will appear again when you click the 'Exit' menu
    if ( LOWORD(wParam) == 305 ) // '305' is the ID which I have used as the button ID in above code
    {
        // Now add your click event code here
    }
}
break;