按钮和组合框 WinAPI

Posted

技术标签:

【中文标题】按钮和组合框 WinAPI【英文标题】:Push button and combo box WinAPI 【发布时间】:2015-01-20 09:05:02 【问题描述】:

我正在尝试做一些 Windows 编程。我创建了一个组合框和一个按钮。我的目标是,当用户在组合框中选择一个项目时,按钮被激活并且需要单击才能继续。到目前为止,我已经做了类似的事情:

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

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

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

问题是,当我使用 case IDM_EXIT 退出程序时,总是出现 case BN_CLICKED 下的消息框,然后程序关闭。我期待当我们关闭程序时,不会出现这样的消息框,但事实并非如此。我的意思是,消息框出现两次,一次是选择单击按钮时,一次是要关闭程序时。为什么会这样。任何想法或建议?

【问题讨论】:

【参考方案1】:

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

看看这个古老但黄金的blog post。

引自作者,

wParam 参数的高位字“指定 如果消息来自控件,则通知代码”。什么是 这里的“控制”是什么意思?请记住,您必须根据上下文来看待事情。 WM_COMMAND 消息在 Win32 的上下文中呈现 一般,特别是在窗口管理器的上下文中。 编辑框、按钮和列表框等窗口通常是 称为“控件”,就像“通用”中的所有窗口类一样 控件库”。在窗口管理器的世界中,“控件”是 一个窗口,其目的是提供某种程度的交互性 (在静态控件的情况下,可能没有交互性 完全)在其父窗口的服务中。事实是 WM_COMMAND 主要在对话框的上下文中进一步使用 强调一点,这里的“控制”一词只是一个同义词 对于“子窗口”。

总而言之,在应用程序窗口内单击的任何按钮都将转换为带有 BN_CLICKED wParam 的 WM_COMMAND。这包括窗口的关闭按钮。

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

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

【讨论】:

很好的解释。我很感激您为我指明了正确的方向。【参考方案2】:

当您单击“退出”菜单时,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);

您必须在您的“案例 BN_CLICKED”中添加一些 ID 检查代码,如下所示:

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;

【讨论】:

非常感谢。现在我明白为什么会这样了。再次感谢

以上是关于按钮和组合框 WinAPI的主要内容,如果未能解决你的问题,请参考以下文章

子类化组合框时如何抑制自动搜索(Win32/WinAPI)

带有按钮、组合框和文本框的 C# WinForms (.NET Framework) DataGridView:使用按钮添加新行以添加组合框项时出错

单击单选按钮或更改 PyQt 中的旋转框时,组合框索引值返回默认值 0

从组合框和命令按钮 VBA 添加到工作表

获取从单选按钮到组合框的数据搜索

Forge Viewer 自定义组合框/组合按钮