win32程序创建按钮并响应点击

我们可以把控件当成特殊的一类窗口,所以,创建控件与创建窗口一样,使用CreateWindow或CreateWindowEx函数,不过,在窗口样式上面记得用上以下两位帅哥:

a、WS_CHILD:控件是放在我们的窗口上的,自然要作为窗口的子窗口,WS_CHILDWINDOW也一样,为了节约几个字母,用WS_CHILD吧。

b、WS_VISIBLE:既然要使用控件,自然要让别人看得见。

 

到底在啥时候创建控件合适一点呢?一种方法是在WinMain方法中创建,注意要把CreateWindow函数的hWndParent参数设置为窗口的句柄。


这里用第二种方法,我们知道,在窗口创建后,显示之前,即CreateWindow函数返回之前,我们会收到WM_CREATE消息,我们响应它的号召,艰苦奋斗创建一个按钮。


//窗口处理函数
LRESULT CALLBACK WinProc(
	HWND hwnd,			//当前句柄
	UINT msg,			//当前MSG消息
	WPARAM wParam,
	LPARAM lParam)
{
	switch (msg)
	{ 
		case WM_CREATE:
			//创建窗口时调用,我们也可以在这里面创建按钮
			break;

		case WM_CLOSE: //点击关闭按钮
			DestroyWindow(hwnd);
			break;

		case WM_DESTROY:
			PostQuitMessage(0);
			break;

		default:
			return DefWindowProc(hwnd,msg,wParam,lParam);
	} 

	return 0;
}




接下来,新的问题来了,按钮我是创建了,但怎么响应用户点击呢?其实,这按钮与菜单项一样,单击点击后,WindowProc会收到WM_COMMAND消息,和菜单一样。

wParam:低字节位表示ID号,高字节位表示控件通知,比如用户单击了按钮,通知码为BN_CLICKED,这样我们就可以了解到用户具体对按钮干了什么。

lParam中保存了控件的句柄。


问题是,怎么设置控件的ID?我们看看CreateWindow的文档介绍。


HWND WINAPI CreateWindow(  
  _In_opt_  LPCTSTR lpClassName,  
  _In_opt_  LPCTSTR lpWindowName,  
  _In_      DWORD dwStyle,  
  _In_      int x,  
  _In_      int y,  
  _In_      int nWidth,  
  _In_      int nHeight,  
  _In_opt_  HWND hWndParent,  
  _In_opt_  HMENU hMenu,  
  _In_opt_  HINSTANCE hInstance,  
  _In_opt_  LPVOID lpPar


hMenu [in, optional] 
Type: HMENU
A handle to a menu, or specifies a child-window identifier depending on the window style. For an overlapped or pop-up window, hMenu identifies the menu to be used with the window; it can be NULL if the class menu is to be used. For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window. 

简单地说,控件通常不需要菜单,所以,可以用这个参数来设置控件的ID,反正hMenu闲着也没事干,就给个ID它玩玩。ID号是一个整数,不过为了可读性,一般是声明一个宏,其实我们在资源编辑器中使用的资源ID(如IDM_FUCK)就是在resource.h中定义的宏的,既然叫ID了,你就知道它的值不要重复。


我们也来模拟一下,在文件的前面也声明三个宏,分别标识三个按钮。

#define IDB_ONE     3301  
#define IDB_TWO     3302  
#define IDB_THREE   3303  

然后创建三个按钮:

 case WM_CREATE:  
  {  
   //创建三个按钮  
   CreateWindow(L"Button", L"按钮一", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
    35, 10, 120, 60, hwnd, (HMENU)IDB_ONE, hwnd, NULL);  
   CreateWindow(L"Button", L"按钮二", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
    35, 80, 120, 60, hwnd, (HMENU)IDB_TWO, hwnd, NULL);  
   CreateWindow(L"Button", L"按钮三", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
    35, 150, 120, 60, hwnd, (HMENU)IDB_THREE, hwnd, NULL);  
  }  
  break; 

然后我们来响应WM_COMMAND消息。

case WM_COMMAND:  
    {  
        switch(LOWORD(wParam))  
        {  
        case IDB_ONE:  
            MessageBox(hwnd, L"您点击了第一个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
            break;  
        case IDB_TWO:  
            MessageBox(hwnd, L"您点击了第二个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
            break;  
        case IDB_THREE:  
            MessageBox(hwnd, L"您点击了第三个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
            break;  
        default:  
            break;  
        }  
    }  
   break;

看看效果。



这时候,我希望,当我点击了按钮后,按钮上的文本变成“按钮X已点击”,该怎么做呢?Windows系统是基于消息机制的,所以,首先想到,向控件发送消息,要改变控件相关的文本,应当发送WM_SETTEXT消息。

我们把上面的代码改一下。

case WM_COMMAND:  
    {  
        switch(LOWORD(wParam))  
        {  
        case IDB_ONE:  
            //MessageBox(hwnd, L"您点击了第一个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
            SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第一个按鈕已点击");  
            break;  
        case IDB_TWO:  
            //MessageBox(hwnd, L"您点击了第二个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
            SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第二个按鈕已点击");  
            break;  
        case IDB_THREE:  
            //MessageBox(hwnd, L"您点击了第三个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
            SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第三个按鈕已点击");  
            break;  
        default:  
            break;  
        }  
    }  
    break;  

前面我们知道,WM_COMMAND消息的lParam保存控件的句柄,所以,我们传给SendMessage的第一个参数是操作目标的句柄,注意,这里不要传WindowProc回调中的参数,因为我们现在要操作的对象是按钮,不是窗口,WindowProc传进到的句柄是指我们注册的窗口,因为我们在WNDCLASS中已经设定了该WindowProc函数。

要对按钮进行操作,应当使用WM_COMMAND的lParam中包含的值,强制转换为HWND。

运行结果如下图所示。



完整的示例如下:

#include <Windows.h>  
 
  
//按钮ID
#define IDB_ONE     3301  
#define IDB_TWO     3302  
#define IDB_THREE   3303  
 
//函数声明
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  
  
LPCWSTR WINDOWS_CLASS = "MyClass";    //类名  
LPCWSTR WINDOWS_TITLE = "测试按钮";   //窗口标题  


int WINAPI wWinMain(HINSTANCE hThisApp,  
    HINSTANCE hPrevApp,  
    LPWSTR lpCmd,  
    int nShow)  
{  
    WNDCLASSEX wc = { };  
    wc.cbSize = sizeof(WNDCLASSEX);  
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;  
    wc.hInstance = hThisApp;  
    wc.lpfnWndProc = (WNDPROC)WindowProc;  
    wc.lpszClassName = WINDOWS_CLASS;  
    wc.style = CS_HREDRAW | CS_VREDRAW;  
    RegisterClassEx(&wc);  
    
    
    HWND hwnd = CreateWindowEx(WS_EX_WINDOWEDGE,  
                    WINDOWS_CLASS,  
                    WINDOWS_TITLE,  
                    WS_OVERLAPPEDWINDOW,  
                    20,  
                    25,  
                    400,  
                    300,  
                    NULL,  
                    NULL,  
                    hThisApp,  
                    NULL);  
    if (hwnd == NULL)  
    {
        return -1;
    }
          
    ShowWindow(hwnd, nShow);  
    UpdateWindow(hwnd);  

    MSG msg;  
    while(GetMessage(&msg,NULL,0,0))  
    {  
        TranslateMessage(&msg);  
        DispatchMessage(&msg);  
    }  
    
    return 0;  
}  
  
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
{  
    switch(msg)  
    {  
    case WM_DESTROY:  
        PostQuitMessage(0);  
        return 0;  

    case WM_CREATE:  
        {  
            //创建三个按钮  
            CreateWindow(L"Button", L"按钮一", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
                35, 10, 160, 60, hwnd, (HMENU)IDB_ONE, hwnd, NULL);  
                
            CreateWindow(L"Button", L"按钮二", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
                35, 80, 160, 60, hwnd, (HMENU)IDB_TWO, hwnd, NULL); 
                 
            CreateWindow(L"Button", L"按钮三", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,  
                35, 150, 160, 60, hwnd, (HMENU)IDB_THREE, hwnd, NULL);  
        }  
        return 0; 
         
    case WM_COMMAND:  
        {  
            switch(LOWORD(wParam))  
            {  
            case IDB_ONE:  
                //MessageBox(hwnd, L"您点击了第一个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
                SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第一个按鈕已点击");  
                break;  
                
            case IDB_TWO:  
                //MessageBox(hwnd, L"您点击了第二个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
                SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第二个按鈕已点击");  
                break;  
                
            case IDB_THREE:  
                //MessageBox(hwnd, L"您点击了第三个按钮。", L"提示", MB_OK | MB_ICONINFORMATION);  
                SendMessage((HWND)lParam, WM_SETTEXT, (WPARAM)NULL, (LPARAM)L"第三个按鈕已点击");  
                break;  
                
            default:  
                break;  
            }  
        }  
        return 0;  
        
    default:  
        return DefWindowProc(hwnd,msg,wParam,lParam);  
    }  
    
    return 0;  
}  




  • 36
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
Win32程序是指使用Windows操作系统提供的API编写的应用程序。SDI(Single Document Interface)是一种界面设计模式,用于窗口应用程序中只打开一个文档的情况。 在编写Win32程序的过程中,首先需要使用C语言进行编程。C语言是一种面向过程的编程语言,它的优点是执行效率高、灵活性好,适合编写底层的系统程序。 在实现SDI模式的程序中,通常会包含一个主窗口(MainFrame)和一个文档窗口(DocumentFrame)。主窗口是整个应用程序的入口,用于显示菜单、工具栏和状态栏等用户界面元素,并负责响应用户的操作。文档窗口用于显示编辑的文档内容,并提供编辑操作,例如保存文档、复制粘贴等。 在编写程序时,需要处理窗口消息,例如鼠标点击、键盘输入等。可以使用Windows API提供的函数来处理这些消息,并根据具体的处理逻辑来实现相应的功能。例如,当用户点击保存按钮时,可以通过SendMessage函数向程序发送保存消息,并在消息处理函数中实现相应的保存操作。 此外,还可以使用Windows API提供的其他功能来增强应用程序的功能,例如创建对话框、绘制图形等。这些功能都可以根据具体的需求来调用相应的函数,从而实现相应的功能。 综上所述,编写Win32程序SDI模式是一个需要深入了解Windows API的过程,通过使用C语言和相关函数,可以实现一个具有图形界面和编辑功能的应用程序
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值