吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2526|回复: 12
收起左侧

[系统底层] win32笔记十四 子窗口

[复制链接]
huchen 发表于 2024-5-7 10:14
之前的笔记索引

子窗口

在上面的学习中,我们知道了窗口的创建,但在windows中,为了方便使用,他预先定义了一些常见的窗口,我们称这些窗口为子窗口或者子窗口控件或者直接叫控件

比如说按钮、复选框、文本框等等

子窗口控件:

  • Windows提供了几个预定义的窗口类似方便我们使用,我们一般就他们叫做子窗口控件,简称控件
  • 控件会自己处理消息,并在自己状态发生改变时通知父窗口
  • 预定义的控件有:按钮、复选框、编辑框、静态字符串标签和滚动条等

通知父窗口比如说,我在子窗口画了个按钮,点击这个按钮他的状态就会发生变化,发生变化的时候他就会告诉父窗口,所以从消息处理上看,我们就能在父窗口过程里获取到子窗口发生的这种变化

但是直接用win32来画界面的很少,因为很难看且效率不高,所以就出现了MFC,但MFC也只是在win32的基础上封装出来的

本次就演示按钮与文本框的代码编写

image-20240428100909534.png

还是上次的代码,运行出来会看到只有这么一个窗口,首先在左边大部分弄上文本框,然后右边弄上按钮

目的知道了,想想怎么实现,首先要在这个窗口上弄,那就要先知道这个窗口何时被建立了起来

文本框

在代码中,我们可以在winmain函数里刚创建主窗口时就可以创建子窗口,那我也可以在窗口回调函数(也叫窗口过程)里创建子窗口,在窗口过程里有各种各样的消息,也包括创建窗口,还记得WM_CREATE吗,这就是所以

HINSTANCE g_hInstance;  //在全局
g_hInstance = hInstance;//在Winmain函数
case WM_CREATE:
        {
            //创建文本框
            CreateWindow(
            "EDIT",
            "",
            WS_CHILD|WS_VISIBLE|WS_VSCROLL|ES_MULTILINE,
            0,
            0,
            500,
            300,
            hwnd,
            NULL,
            g_hInstance,
            NULL
        );
            //创建2个按钮
        CreateWindow(
            "BUTTON",
            "设置",
            WS_CHILD|WS_VISIBLE,
            520,
            180,
            60,
            30,
            hwnd,
            NULL,
            g_hInstance,
            NULL
        );
            CreateWindow(
            "BUTTON",
            "获取",
            WS_CHILD|WS_VISIBLE,
            520,
            220,
            60,
            30,
            hwnd,
            NULL,
            g_hInstance,
            NULL
        );
        }

首先看创建文本框

第一参数就是写windows预定义好的,有那些预定义好的,参考下面的图,也可以在文档里查看

image-20240428102635674.png

第二个参数不需要标题,那就直接给个空串

第三个参数是指你希望文本框以什么形式显示,这里需要查下文档,就不贴图了代码中的属性依次是,子窗口(由于你是子窗口,这是必须要的)、创建后立马就能显示、带有滚动条、可换行(这是子窗口独有的特性在MSDN中可以看到

image-20240428104736616.png

),中间用与符号连接

第四、五个参数是指,相对于父窗口的左上角的那个点在什么位置展现

第六、七参数是指子窗口的宽和高

第八个参数是父窗口的句柄

第九个参数是指子窗口的编号,目前用不上,写上NULL

第十个参数是指当前这个窗口属于那个进程,由于这个参数是在winmain函数里定义的,是个局部变量,所以在外面定义一个全局变量

所以按钮同理,就不多赘述了

然后写完后运行,成功,但是点击那些按钮,有点击效果,却没点击反馈,接下来就是写点击反馈的代码了

首先,记得这句话

  • 控件会自己处理消息,并在自己状态发生改变时通知父窗口

所以当我们点击按钮就会发送消息,而这个消息是可以被捕获的

char OutBuff[0x80];
sprintf(OutBuff,"消息类型:%x\n",uMsg);
OutputDebugString(OutBuff);

我们不是写过捕获消息的代码吗,直接拿过来用,这里要注意,点击的时候别有其他动作,首先长按,然后松开

image-20240428105847644.png

多试几次,就会知道111,就是这个按钮的类型,然后再去查文档

image-20240428105958783.png

就找到这个类型了,说明了,只要按扭的状态发生变化,就会通过WM_COMMAND的方式向父窗口发送消息,所以我只要,捕获这个消息,在写上自己的代码不就行了吗

    case WM_COMMAND:
        {
            MessageBox(0,0,0,0);
            break;
        }

只要点下按钮就会弹个窗口,运行后成功,但是,两个按钮都会弹,那我要区分这两个,怎么办呢?我们就会想到wParam, lParam这两个参数,这两个参数不就是详细记录了消息的细节吗,那我们就看看这个消息的细节

LRESULT CALLBACK WindowProc(
  HWND hwnd,       // handle to window
  UINT uMsg,       // WM_COMMAND
  WPARAM wParam,   // notification code and identifier
  LPARAM lParam    // handle to control (HWND)
);

The low-order word specifies the identifier of the menu item, control, or accelerator.

低阶字指定了菜单项、控件或加速键的标识符

可以看到第三个参数写的是身份标识,什么是身份标识,还记得子窗口编号吗,这个就是用来区分的,这个编号可以自己写

#define IDC_EDIT_1 0x100
#define IDC_BUTTON_1 0x101
#define IDC_BUTTON_2 0x102

然后别忘了添上编号,如果有问题,把编号的类型强转成(HMENU)类型,因为参数是这个类型的

case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
            case IDC_BUTTON_1:
                {
                    MessageBox(0,"1","按钮",0);
                    break;
                }
            case IDC_BUTTON_2:
                {
                    MessageBox(0,"2","按钮",0);
                    break;
                }

            }
            break;
        }

switch(LOWORD(wParam))这里由于是低16位来指定标识符,所以只需要低16位的即可

运行,可以看到没有问题

然后接下来就是点击按钮可以在文本框内显示文字

这里就需要介绍新的函数了

SetDlgItemText

设置对话框中控件的标题或文本。

BOOL SetDlgItemText(
  HWND hDlg,         // handle to dialog box
  int nIDDlgItem,    // control identifier
  LPCTSTR lpString   // text to set
);

参数一次是,句柄、子窗口编号、要输入的文本,字符串

GetDlgItemText

检索与对话框中的控件关联的标题或文本。可以理解成获取

UINT GetDlgItemTextA(
  [in]  HWND  hDlg,
  [in]  int   nIDDlgItem,
  [out] LPSTR lpString,
  [in]  int   cchMax
);

返回值

类型: UINT

如果函数成功,则返回值将指定复制到缓冲区的字符数,不包括终止 null 字符。

如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError。

参数不多说,都能看懂

case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
            case IDC_BUTTON_1:
                {
                    SetDlgItemText(hwnd,IDC_EDIT_1,"按钮测试");
                    //MessageBox(0,"1","按钮",0);
                    break;
                }
            case IDC_BUTTON_2:
                {
                    GetDlgItemText(hwnd,IDC_EDIT_1,OutBuff,100);
                    OutputDebugString(OutBuff);//在输出窗口显示
                    MessageBox(hwnd,OutBuff,OutBuff,MB_OK);
                    break;
                }

            }
            break;
        }

运行结果

image-20240428150957121.png

成功

这里附上完整的代码

// 第一个窗口程序.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#define IDC_EDIT_1 0x100
#define IDC_BUTTON_1 0x101
#define IDC_BUTTON_2 0x102

HINSTANCE g_hInstance;

LRESULT CALLBACK WindowProc(
                    HWND hwnd,      // handle to window
                    UINT uMsg,      // message identifier
                    WPARAM wParam,  // first message parameter
                    LPARAM lParam   // second message parameter
);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    // TODO: Place code here.
    /*
    char OutBuff[0x80];

    DWORD dwAddr = (DWORD)hInstance;
    sprintf(OutBuff,"模块地址:%x\n",dwAddr);

    OutputDebugString(OutBuff);
    */
    //第一步:定义那你的窗口是什么样的?

    char OutBuff[0x80];
    g_hInstance = hInstance;

    TCHAR className[] = TEXT("My First Window");
    WNDCLASS wndclass = {0};
    wndclass.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
    wndclass.lpfnWndProc = WindowProc;
    wndclass.lpszClassName = className;
    wndclass.hInstance = hInstance;

    RegisterClass(&wndclass);

    //第二步:创建并显示窗口
    HWND hwnd = CreateWindow(
        className,
        TEXT("我的第一个窗口"),
        WS_OVERLAPPEDWINDOW,
        10,
        10,
        600,
        300,
        NULL,
        NULL,
        hInstance,
        NULL
        );
    if(hwnd == NULL)
    {
        sprintf(OutBuff,"Error:%d\n",GetLastError());
        OutputDebugString(OutBuff);
        return 0;
    }

    ShowWindow(hwnd,SW_SHOW);

    //第三步:接收消息并处理
    MSG msg;
    BOOL bRet;
    while((bRet = GetMessage(&msg,NULL,0,0)) !=0)
    {
        if(bRet == -1)
        {
            //handle the error and possibly exit
            sprintf(OutBuff,"Error:%d\n",GetLastError());
            OutputDebugString(OutBuff);
        }
        else
        {
            //转换消息
            TranslateMessage(&msg);

            //分发消息
            DispatchMessage(&msg);
        }
    }
    return 0;
}

LRESULT CALLBACK WindowProc(
                    HWND hwnd,      // handle to window
                    UINT uMsg,      // message identifier
                    WPARAM wParam,  // first message parameter
                    LPARAM lParam   // second message parameter
)
{

    char OutBuff[0x80];
    //sprintf(OutBuff,"消息类型:%x\n",uMsg);
    //OutputDebugString(OutBuff);

    switch(uMsg)
    {
    case WM_DESTROY:
        {
            PostQuitMessage(0);
            break;
    }

    case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
            case IDC_BUTTON_1:
                {
                    SetDlgItemText(hwnd,IDC_EDIT_1,"按钮测试");
                    //MessageBox(0,"1","按钮",0);
                    break;
                }
            case IDC_BUTTON_2:
                {
                    GetDlgItemText(hwnd,IDC_EDIT_1,OutBuff,100);
                    OutputDebugString(OutBuff);
                    MessageBox(hwnd,OutBuff,OutBuff,MB_OK);
                    break;
                }

            }
            break;
        }
    case WM_CREATE:
        {
            //创建文本框
            CreateWindow(
            "EDIT",
            "",
            WS_CHILD|WS_VISIBLE|WS_VSCROLL|ES_MULTILINE,
            0,
            0,
            500,
            300,
            hwnd,
            (HMENU)IDC_EDIT_1,
            g_hInstance,
            NULL
        );

        //创建2个按钮
        CreateWindow(
            "BUTTON",
            "设置",
            WS_CHILD|WS_VISIBLE,
            520,
            180,
            60,
            30,
            hwnd,
            (HMENU)IDC_BUTTON_1,
            g_hInstance,
            NULL
        );
        CreateWindow(
            "BUTTON",
            "获取",
            WS_CHILD|WS_VISIBLE,
            520,
            220,
            60,
            30,
            hwnd,
            (HMENU)IDC_BUTTON_2,
            g_hInstance,
            NULL
        );
        }
    }
    return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

免费评分

参与人数 3吾爱币 +9 热心值 +3 收起 理由
allspark + 1 + 1 用心讨论,共获提升!
janken + 1 + 1 热心回复!
willJ + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2024-5-8 11:58
huchen 发表于 2024-5-8 11:29
咋弄到一个主题啊

前面的如果你方便合并都编辑合并到一个最好,不方便就以后的内容通过编辑放到一个主题中。
chuanxing1701 发表于 2024-5-7 12:51
go4399 发表于 2024-5-7 13:19
稻海香 发表于 2024-5-8 09:47
加油,已经刷到这了,必须看完系类。
Hmily 发表于 2024-5-8 11:19
短时间开的主题太多了,我建议放到一个主题中更新,或者回帖更新比较合适。
 楼主| huchen 发表于 2024-5-8 11:29
Hmily 发表于 2024-5-8 11:19
短时间开的主题太多了,我建议放到一个主题中更新,或者回帖更新比较合适。

咋弄到一个主题啊

点评

前面的如果你方便合并都编辑合并到一个最好,不方便就以后的内容通过编辑放到一个主题中。  详情 回复 发表于 2024-5-8 11:58
woaiwozhui 发表于 2024-5-9 11:10
学习一下
lduml 发表于 2024-5-9 16:20
学习了,
PJ997272250 发表于 2024-5-9 17:19
学习学习
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-15 16:37

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表