Windows编程系列——第二讲:创建窗口(上)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Neo_kh/article/details/81952781

上一讲:Windows编程系列——第一讲:预备知识


Windows编程系列——第二讲:创建窗口(上)

1.窗口

上一节我们创建了一个Windows桌面应用程序。这个程序可以直接编译运行,运行后如图:这里写图片描述

这就是Windows最基本的元素——窗口。下面介绍它的基本元素:
        首先,窗口最外侧是边框;最上方是标题栏;标题栏的左侧是图标,紧挨着是标题(就是图片中的”WindowsProject1”);标题栏右侧依次是最小化按钮、最大化按钮、关闭按钮;标题栏的下方是菜单,准确的说是”下拉菜单”。中间很大的空白区域就是客户区

        可以说,对话框、复选框、滚动条、文本框都是各种各样的窗口,或者更准确的说,是”子窗口”、”控件窗口”或”子窗口控件”。


        接下来,我们对照代码,解释代码的含义

2.入口函数

        初学C/C++我们知道,main()函数是程序的入口;而在编写Windows应用程序时,要求入口函数名是WinMain,对应的Unicode则是wWinMain,如下:

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)

这就是入口函数。
        你可能会问,wWinMain前面有一个修饰APIENTRY是什么东西?我们可以在系统头文件windef.h中找到它的定义,它和后面马上会出现的CALLBACK都是__stdcall(注意是两个连续的下划线)。这是一种函数调用方式,规定了参数传递(例如从左到右还是从右到左)、退出时的操作等细节问题。与__stdcall对应的还有__cdecl、__fastcall、__thiscall等等,初学者不必深究。
        言归正传,WinMain或wWinMain函数有四个参数,我们去MSDN搜一下这个函数:
这里写图片描述
点击第一个条目。下面是参数解释:

  • hInstance是指当前应用程序的实例句柄。
  • hPrevInstance.现在这个参数不再使用了,永远为NULL。以前用它来跟踪应用程序的前一个实例。
  • lpCmdLine。类似于main(int argc,char*argv)中的argv,接收命令行参数。
  • nCmdShow,主窗口初始化时的显示方式,即如何打开程序的窗口。此参数可以取以下值:
参数 含义
SW_MAXIMIZE 3 最大化指定的窗口
SW_MINIMIZE 6 最小化指定的窗口并且激活在Z序中的下一个顶层窗口
SW_SHOW 5 在窗口原来的位置以原来的尺寸激活和显示窗口
SW_HIDE 0 隐藏窗口并激活其他窗口
SW_SHOWMINNOACTIVE 7 窗口最小化,激活窗口仍然维持激活状态
SW_SHOWNA 8 以窗口原来的状态显示窗口。激活窗口仍然维持激活状态
SW_RESTORE 9 激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志
SW_SHOWMAXIMIZED 3 激活窗口并将其最大化
SW_SHOWMINIMIZED 2 激活窗口并将其最小化
SW_SHOWNOACTIVATE 4 以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态
SW_SHOWNORMAL 1 激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志

关于返回值,我把翻译结果贴出来:如果该函数成功, 则在接收到‎‎ ‎‎WM_QUIT‎‎ ‎‎消息时终止, 它应返回该消息的‎‎wParam‎‎参数中包含的退出值。如果函数在输入消息循环之前终止, 它应该返回零。至于什么意思,我暂时不去弄懂。

3.消息和窗口函数

        创建窗口后,就要对窗口的行为负责。例如:当用鼠标拖动窗口的边框时,窗口的大小会随之改变;当用户拖拽窗口的标题栏时,窗口会随之移动;当点击最大化按钮时,窗口会最大化……
        但是,应用程序如何知道用户在窗口上的动作呢?是不是应用程序完成了这些动作?不是。是Windows本身而不是应用程序处理了窗口的所有命令,只不过Windows会以“消息”的形式通知应用程序:“窗口被拖拽啦”、“窗口最大化啦”。在接收到这些“消息”后,应用程序会根据需要重新绘制窗口。
        那么,Windows是怎么向应用程序发送消息的呢?对于程序来说,所谓发送消息就是调用某一个函数,并把消息的内容作为函数的参数进行传递。对于Windows应用程序来说,除了要求必须有主函数(Win Main)外,还要求必须有一个窗口函数。当Windows向应用程序发送消息时,它会调用程序中的窗口函数。窗口函数原型如下:

LRESULT CALLBACK WndProc(
    HWND hWnd,//窗口句柄
    UINT uMsg,//消息类型
    WPARAM wParam,//消息参数
    LPARAM lParam //消息参数)

        注意官方文档和一些参考书中也会把窗口函数定义为WindowProc。

        第一个参数表示接收消息的窗口的句柄;

        第二个参数表示消息的类型,例如WM_LBUNTTONDOWN(鼠标左键按下)、WM_CLOSE(关闭窗口)、WM_KEYDOWN(键盘按下)、WM_TIMER(定时器消息),等等;

        第三、四个参数针对不同的消息会有不同的含义,例如针对WM_MOUSEMOVE(鼠标移动)消息,两个参数就用来表示鼠标位置;而针对WM_KEYUP(按键弹起)消息,两个参数就用来表示键码信息。
        下一讲我们会详细讲述窗口函数。

4.进队消息与不进队消息

WinMain里面有一个消息循环,它调用GetMessage从消息队列中取出消息,并且调用DispatchMessage讲消息发送给窗口函数。

 // 主消息循环:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

Windows把消息分为“进队消息”和“不进队消息”:

  • 进队消息是指Windows把消息放入程序的消息队列中,通过消息循环把消息发送给窗口函数

  • 不进队消息在Windows调用窗口函数时直接发送给窗口函数

            殊途同归,窗口函数都将获得窗口的所有信息——包括进队和不进队的。
            进队消息主要是各种输入,例如各种按键消息、字符消息、鼠标消息、定时器消息以及刷新消息和退出消息。
            不进队消息来自于调用特定的API函数。例如,
    当WinMain函数调用CreateWindow函数时,Windows将创建窗口并给窗口函数发送一个WM_CREATE消息
    当WinMain函数调用ShowWindow函数时,Windows将创建窗口并给窗口函数发送一个WM_SIZE和WM_SHOWWINDOWS消息
    当WinMain函数调用UpdateWindow函数时,Windows将创建窗口并给窗口函数发送一个WM_PAINT消息

        总结一下,各种消息都是以一种有序的、同步的方式进出的,窗口函数可以处理它们(也可以调用DefWindowProc进行默认的处理)。在这里,“有序的、同步的”的含义是当窗口函数在处理一个消息时,不会被其他的消息所中断。

5.MessageBox

        MessageBox的作用是弹出一个小的对话框,向用户显示短信息,并将用户的选择返回给调用者。尝试在代码中添加如下一行代码:

// TODO: 在此处放置代码。
MessageBox(NULL, L"Hello World!", L"My First Windows APP", MB_OKCANCEL);

运行结果如下图:
这里写图片描述
函数原型:

int MessageBox(
  HWND    hWnd,
  LPCTSTR lpText,
  LPCTSTR lpCaption,
  UINT    uType
);

        解释一下函数参数:hWnd参数是指父窗口句柄,这里为NULL,表示没有父窗口;lpText参数是将要显示的字符串;lpCaption参数是对话框的标题栏名称;uType参数用来指定对话框的内容和行为。
        这里针对第四个参数说明一下,我们在MSDN中可以找到这个参数的详细说明。例如上面的实例中,我们使用了MB_OKCANCEL,表示对话框出现“确定”和“取消”两个按钮。这里,MB_OKCANCEL是一个字符常量。更多的uType常量可以点击这里查看。


下一讲:Windows编程系列——第三讲:创建窗口(下)

猜你喜欢

转载自blog.csdn.net/Neo_kh/article/details/81952781