精华内容
下载资源
问答
  • Windows窗口高级编程

    2018-06-25 15:20:53
    但是对于要在最短的时间内迅速掌握窗口编程的技术,则需要一个实用而系统的教程。本视频教程就是要完成这个目标,看完这个系列的视频教程后,大家就可以熟练地完成本讲座的综合题,也就打下了界面编程的扎实基础。
  • 12.3.2 多文档文本编辑器 例12.6创建多文档文本编辑器的具体步骤如下运行效果如图12.9图中主窗体中的子窗体为层叠排列 1新建项目修改Form1窗体属性IsMdiContainer=true表示主窗体是子...3为菜单增加"窗口"顶级菜单项Me
  • 这里我们要制作一个复杂一点的Windows程序 - 显示一个空白窗口。出于稳定性考量,Visual C++编译器中int、long等基本类型基本上没有变化(16->32仅int变化了一次,64位没有变化),但是指针则16位、32位、64位一直...

    (三) 窗口的创建与消息处理

    原来那个程序是不是感觉有点简单?这里我们要制作一个复杂一点的Windows程序 - 显示一个空白窗口。

    出于稳定性考量,Visual C++编译器中int、long等基本类型基本上没有变化(16->32仅int变化了一次,64位没有变化),但是指针则16位、32位、64位一直在变化,为了更好地适应指针的变化,以及方便地与指针相互转换,Windows中定义了平台相关整数,它们随指针长度而变化:

    INT_PTR 和 UINT_PTR - 16/32/64位平台相关整数,前者有符号,后者无符号

    LONG_PTR 和 ULONG_PTR - 32/32/64位平台相关整数,前者有符号,后者无符号

    这四个类型在以后的编程中要经常用到,务必明白它们的意思。

    关于调用约定:调用约定表示调用函数时参数的传递方式。在Windows中绝大多数WinAPI都是__stdcall,只有wsprintf等参数数量可变的函数是__cdecl,自己定义的各种Win32函数也最好采用__stdcall。关于调用约定的内部信息请参阅相关资料,这里不详述。

    一、准备一个窗口消息处理函数

    Windows中窗口事件的处理是靠窗口消息来完成的,为了处理窗口消息,每一个窗口都至少对应一个窗口消息处理函数,窗口消息处理函数的定义如下:

    <code class="lang-cpp">LONG_PTR __stdcall WndProc(void* hWnd, unsigned int msg, UINT_PTR wp, LONG_PTR lp)

    {

    &nbsp;&nbsp;&nbsp;&nbsp;return DefWindowProc(hWnd, msg, wp, lp);

    }</code>

    程序在处理完消息之后,return 0;直接返回,否则应该调用DefWindowProc来处理不想处理的消息。

    常用的消息如下:

    WM_CREATE - 窗口创建时被调用

    WM_DESTROY - 窗口销毁时被调用

    WM_PAINT - 窗口绘制时被调用

    WM_COMMAND - 控件或窗口有消息时被调用

    WM_SIZE - 窗口大小改变时被调用

    为了在同一个函数中处理不同消息,我们一般使用switch (msg) { case WM_XXX: ... }分支来编写WndProc函数:

    <code class="lang-cpp">// 窗口消息处理函数 - WndProc

    LONG_PTR __stdcall WndProc(void* hWnd, unsigned int msg, UINT_PTR wp, LONG_PTR lp)

    {

    &nbsp;&nbsp;&nbsp;&nbsp;switch (msg) // 判断窗口消息的种类

    &nbsp;&nbsp;&nbsp;&nbsp;{

    &nbsp;&nbsp;&nbsp;&nbsp;case WM_CREATE: // 窗口创建

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ...

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;

    &nbsp;&nbsp;&nbsp;&nbsp;case WM_DESTROY: // 窗口销毁

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ...

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;

    &nbsp;&nbsp;&nbsp;&nbsp;// case ...

    &nbsp;&nbsp;&nbsp;&nbsp;}

    &nbsp;&nbsp;&nbsp;&nbsp;return DefWindowProc(hWnd, msg, wp, lp);

    }</code>

    在这里,我们只需处理WM_DESTROY即可:

    <code class="lang-cpp">// 窗口消息处理函数 - WndProc

    LONG_PTR __stdcall WndProc(void* hWnd, unsigned int msg, UINT_PTR wp, LONG_PTR lp)

    {

    &nbsp;&nbsp;&nbsp;&nbsp;switch (msg) // 判断窗口消息的种类

    &nbsp;&nbsp;&nbsp;&nbsp;{

    &nbsp;&nbsp;&nbsp;&nbsp;case WM_DESTROY: // 窗口销毁

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ...

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;

    &nbsp;&nbsp;&nbsp;&nbsp;}

    &nbsp;&nbsp;&nbsp;&nbsp;return DefWindowProc(hWnd, msg, wp, lp);

    }</code>

    二、全局变量

    我们需要两个全局变量保存模块和主窗口的句柄:

    <code class="lang-cpp">void* hInst; // 模块句柄

    void* hMainWnd; // 主窗口句柄</code>

    在wWinMain中,第一个参数提供了模块句柄,现在保存到全局变量:

    <code class="lang-cpp">// 入口点 - wWinMain

    int __stdcall wWinMain(void* hInstance, void* reserved, wchar_t* cmdline, int nshow)

    {

    &nbsp;&nbsp;&nbsp;&nbsp;hInst = hInstance; // 保存模块句柄

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    &nbsp;&nbsp;&nbsp;&nbsp;// ... 注册窗口类 建立窗口 显示和更新窗口 消息循环 ...

    }</code>

    三、注册窗口类

    在Windows中,窗口的部分特性需要与窗口类(WNDCLASS)进行自定义。WNDCLASS是一个C语言结构体,我们需要填写它们的内容。

    WNDCLASS {

    样式 函数(样式=窗口类样式,常用的有CS_HREDRAW和CS_VREDRAW;函数=窗口处理函数)

    类增 窗增(高级参数,表示窗口类和每个窗口附加数据的字节数,一般填0)

    模块 图标 光标(模块=模块句柄;图标=左上角图标;光标=常说的鼠标指针)

    背景 菜单 类名(背景=背景画刷;菜单=菜单资源标识,字符串或小于65536的整数;类名=窗口类的名称,随便写)

    }

    在这里如下填写,这些内容一般情况下是比较固定的:

    <code class="lang-cpp">// 窗口类设定

    // 样式、函数

    // 类增、窗增&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(高级参数)

    // 模块、图标、光标&nbsp;&nbsp;&nbsp;&nbsp; (光标=鼠标指针)

    // 背景、菜单、类名

    WNDCLASS wc = {

    &nbsp;&nbsp;&nbsp;&nbsp;CS_HREDRAW | CS_VREDRAW, // 样式:横向、纵向改变大小时重绘

    &nbsp;&nbsp;&nbsp;&nbsp;WndProc, // 窗口消息处理函数

    &nbsp;&nbsp;&nbsp;&nbsp;0, 0,

    &nbsp;&nbsp;&nbsp;&nbsp;hInst, // 模块句柄

    &nbsp;&nbsp;&nbsp;&nbsp;LoadIcon(NULL, IDI_APPLICATION), // 图标:默认图标

    &nbsp;&nbsp;&nbsp;&nbsp;LoadCursor(NULL, IDC_ARROW), // 光标:箭头

    &nbsp;&nbsp;&nbsp;&nbsp;GetStockObject(WHITE_BRUSH), // 背景画刷:白色

    &nbsp;&nbsp;&nbsp;&nbsp;NULL, // 菜单:无

    &nbsp;&nbsp;&nbsp;&nbsp;L"MyWindow", // 窗口类名称

    };</code>

    填写完这个类之后,我们可以调用RegisterClass函数注册这个窗口类:

    <code class="lang-cpp">if (!RegisterClass(&amp;wc)) // 注册窗口类

    &nbsp;&nbsp;&nbsp;&nbsp;return 1;</code>

    四、新建窗口

    新建窗口需要使用CreateWindowEx函数,这个函数有12个参数,看似比较多,其实也不难记:

    CreateWindowEx(

    扩展样式, 窗口类名, 窗口标题, 窗口样式, // 窗口样式常用WS_OVERLAPPEDWINDOW

    左, 上, 宽, 高, // 不想填写可以使用CW_USEDEFAULT

    父窗句柄, 菜单句柄, 模块句柄, 可选参数

    )

    不是所有参数都是必要的,部分参数可以填0或NULL。

    在这里,我们这样建立一个标准的窗口:

    <code class="lang-cpp">// 创建主窗口 - CreateWindowEx

    // 扩展样式、窗口类名、窗口标题、窗口样式(样式=覆盖式窗口)

    // 左、上、宽、高

    // 父窗句柄、菜单句柄、模块句柄、可选参数

    hMainWnd = CreateWindowEx(

    &nbsp;&nbsp;&nbsp;&nbsp;0, L"MyWindow", L"这是主窗口", WS_OVERLAPPEDWINDOW,

    &nbsp;&nbsp;&nbsp;&nbsp;CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

    &nbsp;&nbsp;&nbsp;&nbsp;NULL, NULL, hInst, NULL);</code>

    建立窗口以后,我们一般需要显示并更新窗口,这一步比较简单:

    <code class="lang-cpp">ShowWindow(hMainWnd, nshow); // 显示窗口

    UpdateWindow(hMainWnd); // 更新窗口</code>

    五、进入消息循环

    窗口显示以后,我们的程序并没有就此停住并继续接收窗口消息,因此我们要在wWinMain中不停地等待消息,并让系统进行处理。

    其中GetMessage等待并获取消息,TranslateMessage将虚拟键码转换为Unicode字符,DispatchMessage将消息分发到处理函数

    代码如下:

    <code class="lang-cpp">MSG msg;

    int rslt;

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    // 消息循环 - 等待和处理各种消息

    while (rslt = GetMessage(&amp;msg, NULL, 0, 0)) // 获取消息

    {

    &nbsp;&nbsp;&nbsp;&nbsp;if (rslt == -1) // 错误则退出

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;

    &nbsp;&nbsp;&nbsp;&nbsp;TranslateMessage(&amp;msg); // 将虚拟键码转换为Unicode字符

    &nbsp;&nbsp;&nbsp;&nbsp;DispatchMessage(&amp;msg); // 分发消息到窗口消息处理函数

    }</code>

    六、退出消息循环

    接收到一般消息时,GetMessage会返回TRUE,这时消息循环继续运行。当接收到WM_QUIT消息时,GetMessage会返回FALSE,程序将退出。退出代码保存在msg.wParam中:

    <code class="lang-cpp">return (int)msg.wParam;</code>

    在窗口被销毁时,我们期望消息循环退出,因此要向消息循环发送WM_QUIT消息,方法是调用PostQuitMessage(n)函数,n为退出码。在WndProc中添加以下代码:

    <code class="lang-cpp">// 窗口消息处理函数 - WndProc

    LONG_PTR __stdcall WndProc(void* hWnd, unsigned int msg, UINT_PTR wp, LONG_PTR lp)

    {

    &nbsp;&nbsp;&nbsp;&nbsp;switch (msg) // 判断窗口消息的种类

    &nbsp;&nbsp;&nbsp;&nbsp;{

    &nbsp;&nbsp;&nbsp;&nbsp;case WM_DESTROY: // 窗口销毁

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PostQuitMessage(0); // 发送WM_QUIT,退出消息循环

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;

    &nbsp;&nbsp;&nbsp;&nbsp;}

    &nbsp;&nbsp;&nbsp;&nbsp;return DefWindowProc(hWnd, msg, wp, lp);

    }</code>七、运行效果

    f740ba37c394d6018b076e85580773c5.png

    八、完整的程序

    <code class="lang-cpp">// 不严格区分句柄,均定义为void*

    #define NO_STRICT

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    // 包含WinAPI定义

    #include &lt;windows.h&gt;

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    // 平台相关的整数类型:

    // INT_PTR 16 -&gt; 32 -&gt; 64

    // UINT_PTR 16 -&gt; 32 -&gt; 64

    // LONG_PTR 32 -&gt; 32 -&gt; 64

    // ULONG_PTR 32 -&gt; 32 -&gt; 64

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    void* hInst; // 模块句柄

    void* hMainWnd; // 主窗口句柄

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    // 窗口消息处理函数 - WndProc

    LONG_PTR __stdcall WndProc(void* hWnd, unsigned int msg, UINT_PTR wp, LONG_PTR lp)

    {

    &nbsp;&nbsp;&nbsp;&nbsp;switch (msg) // 判断窗口消息的种类

    &nbsp;&nbsp;&nbsp;&nbsp;{

    &nbsp;&nbsp;&nbsp;&nbsp;case WM_DESTROY: // 窗口被销毁时

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PostQuitMessage(0); // 发送WM_QUIT,退出消息循环

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;

    &nbsp;&nbsp;&nbsp;&nbsp;}

    &nbsp;&nbsp;&nbsp;&nbsp;// 如果消息未经处理,则由DefWindowProc处理

    &nbsp;&nbsp;&nbsp;&nbsp;return DefWindowProc(hWnd, msg, wp, lp);

    }

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    // 入口点 - wWinMain

    int __stdcall wWinMain(void* hInstance, void* reserved, wchar_t* cmdline, int nshow)

    {

    &nbsp;&nbsp;&nbsp;&nbsp;hInst = hInstance; // 保存模块句柄

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    &nbsp;&nbsp;&nbsp;&nbsp;// 窗口类设定

    &nbsp;&nbsp;&nbsp;&nbsp;// 样式、函数

    &nbsp;&nbsp;&nbsp;&nbsp;// 类增、窗增&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(高级参数)

    &nbsp;&nbsp;&nbsp;&nbsp;// 模块、图标、光标&nbsp;&nbsp;&nbsp;&nbsp; (光标=鼠标指针)

    &nbsp;&nbsp;&nbsp;&nbsp;// 背景、菜单、类名

    &nbsp;&nbsp;&nbsp;&nbsp;WNDCLASS wc = {

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CS_HREDRAW | CS_VREDRAW, // 样式:横向、纵向改变大小时重绘

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WndProc, // 窗口消息处理函数

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0, 0,

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hInst, // 模块句柄

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LoadIcon(NULL, IDI_APPLICATION), // 图标:默认图标

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LoadCursor(NULL, IDC_ARROW), // 光标:箭头

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GetStockObject(WHITE_BRUSH), // 背景画刷:白色

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL, // 菜单:无

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;L"MyWindow", // 窗口类名称

    &nbsp;&nbsp;&nbsp;&nbsp;};

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    &nbsp;&nbsp;&nbsp;&nbsp;if (!RegisterClass(&amp;wc)) // 注册窗口类

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    &nbsp;&nbsp;&nbsp;&nbsp;// 创建主窗口 - CreateWindowEx

    &nbsp;&nbsp;&nbsp;&nbsp;// 扩展样式、窗口类名、窗口标题、窗口样式(样式=覆盖式窗口)

    &nbsp;&nbsp;&nbsp;&nbsp;// 左、上、宽、高

    &nbsp;&nbsp;&nbsp;&nbsp;// 父窗句柄、菜单句柄、模块句柄、可选参数

    &nbsp;&nbsp;&nbsp;&nbsp;hMainWnd = CreateWindowEx(

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0, L"MyWindow", L"这是主窗口", WS_OVERLAPPEDWINDOW,

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL, NULL, hInst, NULL);

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    &nbsp;&nbsp;&nbsp;&nbsp;ShowWindow(hMainWnd, nshow); // 显示窗口

    &nbsp;&nbsp;&nbsp;&nbsp;UpdateWindow(hMainWnd); // 更新窗口

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    &nbsp;&nbsp;&nbsp;&nbsp;MSG msg;

    &nbsp;&nbsp;&nbsp;&nbsp;int rslt;

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    &nbsp;&nbsp;&nbsp;&nbsp;// 消息循环 - 等待和处理各种消息

    &nbsp;&nbsp;&nbsp;&nbsp;while (rslt = GetMessage(&amp;msg, NULL, 0, 0)) // 获取消息

    &nbsp;&nbsp;&nbsp;&nbsp;{

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (rslt == -1) // 错误则退出

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 1;

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TranslateMessage(&amp;msg); // 将虚拟键码转换为Unicode字符

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DispatchMessage(&amp;msg); // 分发消息到窗口消息处理函数

    &nbsp;&nbsp;&nbsp;&nbsp;}

    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

    &nbsp;&nbsp;&nbsp;&nbsp;return (int)msg.wParam;

    }&lt;/windows.h&gt;</code>

    展开全文
  • 以基础的windows编程开发知识、windows图形窗口编程、基于TCP/IP协议的网络编程原理与实现方法,多线程编程的运用,再结合前面的实例为你详解一个win窗口应用程序应该如何编写的,需要注意事项有哪些?类QQ聊天工具...

    本文以Visual C++2015软件为例编写一个类似QQ聊天工具的程序。以基础的windows编程开发知识、windows图形窗口编程、基于TCP/IP协议的网络编程原理与实现方法,多线程编程的运用,再结合前面的实例为你详解一个win窗口应用程序应该如何编写的,需要注意事项有哪些?

    类QQ聊天工具程序开发,原文引用如下:

    下面介绍一个综合的例子:聊天程序。这是一个类似于QQ的聊天程序,为了简化起见,把服务器端程序和客户端程序合二为一了。这个程序既是服务器程序,同时又是客户端程序。

    首先先建立一个项目,点击菜单“新建项目”,如下图所示:

    cf50f2d92fc9adafdf656a7a30dd19e0.png

    将项目的类型设置为“Windows窗体应用程序”,项目的名称设置为“ChatDemo”,如下图所示:

    9c989a6a9163461a8eb585337946dbc1.png

    项目建好后,首先在窗体中添加一个TextBox控件。在工具箱中点中“TextBox”控件,如下图所示:

    5e7032723daded42296fadddf06b92ee.png

    在窗体中拖拉出一个TextBox,以后所有的聊天内容就显示在这个窗口里面。把它的名字设置为“ShowBox”,并且把它的“MulTIline”属性设置为“True”,同时把它的“Scrollbar”属性设置为“VerTIcal”(垂直滚行条),如下图所示:

    dc8b5b5c0083164fa5ed4abc806bc700.png

    将窗体的标题设置为“聊天”,在“ShowBox”的下面添加一个名为“InputBox”的TextBox,用户可以在这个输入框里面输入想说的话。另外再添加一个“发送”按钮,用于发送想说的话,把这个按钮命名为“SendTextButton”,如下图所示:

    33e229114e6dbf6a9a4ecdde9d0aa221.png

    将显示聊天内容的控件的“TabIndex”属性设置为“2”,这样程序运行时输入的焦点就会定位于下面的输入框里面,如下图所示:

    6a8060e4a520d54bfc1b9fa3306133e5.png

    程序的界面就完成了。

    下面是程序实际运行时的截图,下图是服务器端的程序:

    d23f137ead908ac54f829230be0bb9b2.png

    想看更多关于VC2005聊天工具程序实现内容,点击此链接下载原文阅读(点击标题):VC2005教程

    展开全文
  • windows 实用编程指南

    2009-09-05 14:29:37
    现在我们已经知道,一个Widnows程序一般都具有一个窗口,微软之所以将他们的操作系统叫做Windows,也是因为他们认为运行于他们的操作系统之上的程序都...这本书就是关于windows界面编程的C语言教程,希望给大家方便。
  • 刚开始学 Windows API 编程,参考了小甲鱼的教程,写了个程序玩玩。运行截图:目前实现了: 自动获取屏幕分辨率和 DPI,并且根据 DPI 缩放文字 点击窗口(客户区)可以轮流改变颜色 点击关闭按钮弹出退出提示 这个...

    刚开始学 Windows API 编程,参考了小甲鱼的教程,写了个程序玩玩。

    运行截图:

    运行截图

    目前实现了:

    • 自动获取屏幕分辨率和 DPI,并且根据 DPI 缩放文字
    • 点击窗口(客户区)可以轮流改变颜色
    • 点击关闭按钮弹出退出提示

    这个程序并没有太大的实用意义,只是我学习 Windows 编程的一个实验产物。

    代码

    #include <Windows.h>
    #include <strsafe.h>
    
    #define RGBVALUE(hex) ((hex & 0xff) << 16 | (hex & 0xff00) | hex >> 16)
    #define BUFFSIZE 128
    
    // The size of textColor and bgColor must be equal.
    const COLORREF textColor[] = {
        RGBVALUE(0xffffff),
        RGBVALUE(0xffffff),
        RGBVALUE(0xffffff),
        RGBVALUE(0xffffff),
        RGBVALUE(0x66ccff)
    };
    const COLORREF bgColor[] = {
        RGBVALUE(0x305066),
        RGBVALUE(0x5d65a7),
        RGBVALUE(0x0067a6),
        RGBVALUE(0xde9dd6),
        RGBVALUE(0xffffff)
    };
    int colorIndex = 0;
    const int textColorMax = sizeof(textColor) / sizeof(textColor[0]);
    const int bgColorMax = sizeof(bgColor) / sizeof(bgColor[0]);
    const int colorMax = textColorMax <= bgColorMax ? textColorMax : bgColorMax;
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
        static TCHAR szAppName[] = TEXT("MyWindow");
        HWND hwnd;
        MSG msg;
        WNDCLASS wndclass;
    
        wndclass.style = CS_HREDRAW | CS_VREDRAW;
        wndclass.lpfnWndProc = WndProc;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hInstance = hInstance;
        wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground = NULL;
        wndclass.lpszMenuName = NULL;
        wndclass.lpszClassName = szAppName;
    
        if (!RegisterClass(&wndclass))
        {
            MessageBox(NULL, TEXT("这个程序需要在 Windows NT 才能执行!"), szAppName, MB_ICONERROR);
            return 0;
        }
    
        hwnd = CreateWindow(szAppName,
            NULL,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            NULL,
            NULL,
            hInstance,
            NULL);
    
        ShowWindow(hwnd, iCmdShow);
        UpdateWindow(hwnd);
    
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        HDC hdc;
        HFONT hfont;
        PAINTSTRUCT ps;
        RECT rect;
        TCHAR szBuffer[BUFFSIZE];
        size_t iTarget;
        TEXTMETRIC tm;
        static int cxChar, cyChar;
        static int cxClient, cyClient;
        static int dpiX, dpiY;
        static double scale;
        static HBRUSH hb;
    
        HDC screen = GetDC(0);
        dpiX = GetDeviceCaps (screen, LOGPIXELSX);
        dpiY = GetDeviceCaps (screen, LOGPIXELSY);
        scale = dpiX * 100.0 / 96;
        scale /= 100;
        ReleaseDC(0, screen);
        switch (message)
        {
        case WM_CREATE:
            hdc = GetDC(hwnd);
            GetTextMetrics(hdc, &tm);
            cxChar = tm.tmAveCharWidth;
            cyChar = tm.tmHeight + tm.tmExternalLeading;
            ReleaseDC(hwnd, hdc);
    
            return 0;
    
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            GetClientRect(hwnd, &rect);
            cxClient = GetSystemMetrics(SM_CXSCREEN);
            cyClient = GetSystemMetrics(SM_CYSCREEN);
            TCHAR wndTitle[BUFFSIZE];
            StringCchPrintf(wndTitle, BUFFSIZE, TEXT("分辨率:%d × %d 颜色序号:%d / %d"), cxClient, cyClient, colorIndex + 1, colorMax);
            SetWindowText(hwnd, wndTitle);
            hb = CreateSolidBrush(bgColor[colorIndex]);
            SelectObject(hdc, hb);
            PatBlt(hdc, 0, 0, cxClient, cyClient, PATCOPY);
            hfont = CreateFont(
                    36 * scale, 0,    //高度 36 乘以缩放比例, 宽取 0 表示由系统选择最佳值
                    0, 0,    //文本倾斜,与字体倾斜都为 0
                    FW_HEAVY,    //粗体
                    0,0,0,        //非斜体,无下划线,无中划线
                    UNICODE,    //字符集
                    OUT_DEFAULT_PRECIS,        
                    CLIP_DEFAULT_PRECIS,        
                    DEFAULT_QUALITY,        //一系列的默认值
                    DEFAULT_PITCH | FF_DONTCARE,    
                    TEXT("宋体")    //字体名称
            );
            SetTextColor(hdc, textColor[colorIndex]);
            SetBkColor(hdc, bgColor[colorIndex]);
            SelectObject(hdc, hfont);
            StringCchPrintf(szBuffer, BUFFSIZE, TEXT("屏幕分辨率是 %d × %d px (%.f %% 缩放)"), cxClient, cyClient, scale * 100);
            DrawText(hdc, szBuffer, -1, &rect,
                DT_SINGLELINE | DT_CENTER | DT_VCENTER);
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_LBUTTONUP:
            // 颜色索引加一,并判断是否超过数组限度
            if (++colorIndex >= colorMax)
            {
                // 如果超过数组限度,重设为 0
                colorIndex = 0;
            }
            GetClientRect(hwnd, &rect);
            InvalidateRect(hwnd, &rect, 1);
            UpdateWindow(hwnd);
            return 0;
    
        case WM_CLOSE:
            if (MessageBox(hwnd, TEXT("真的要关闭嘛~~~~"), TEXT("请确认"), MB_YESNO | MB_ICONQUESTION) == IDYES)
                DestroyWindow(hwnd);
            else
                return 0;
    
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
    
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    用 VS 2010 编译通过。

    为了在高 DPI 下显示清晰,需要在生成之前修改工程配置:
      配置属性→清单工具→输入和输出→启动 DPI 识别功能【是】

    展开全文
  • 2.1 Windows编程回顾  提到Windows编程,简单地说...基本上所有的相关入门教程,都会用以下这样一个小例子,来演示一个最简单的Windows应用: 双击代码全选 1 2 3 4 5 6 7 8 9 10 11 12 13
    2.1 Windows编程回顾
    

      提到Windows编程,简单地说,就是调用WIndows API做Windows应用程序。比如画个窗口,写个菜单,放个按钮,响应响应鼠标之类的。基本上所有的相关入门教程,都会用以下这样一个小例子,来演示一个最简单的Windows应用:

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //------------Start---------------
    #include ...
    //回调函数
    LRESULT   WndProc(){
      //switch msg
      ...
      WM_PAINT:
      OnPaint();
      ...
    }
     
    void OnPaint(){ //draw }
     
    //入口
    int WinMain(){
      //1:注册窗口类,并将该窗口的回调函数调为WndProc
      //2:建立并显示窗口
      //3:进入消息循环
    }
     
    //------------End---------------

      从上面程序可以看出,正常的Windows程序编写,都会有上述的1、2、3步。这样一来,运行时一个Win窗体就会诞生,并且源源不断地接收系统和用户发给它的各种消息,比如单击、移动、关闭等。然后在此基础上,我们就可以编写自己的功能,比如每当单击窗口的某一处就显示一个图片、每当用户点关闭按钮,就弹出一个提示框,等等诸如此类的操作。这些功能都需要在WndProc的switch语句中添加。由此就产生了一个问题。

      “我是不是需要经常改动WndProc或者它所调用的函数(如OnPaint)的内容?”

      OK,一般说来,是这样的。所以这会给开发造成很多麻烦,比如需要经常修改同一段代码,又比如每建立一个应用程序,都要重复写以上的那个结构…等等等等。于是我们就郁闷了,开始考虑怎么才能来点儿一劳永逸的办法,使得上述那样3步可以固化下来,以后再要开发,只需要写功能,不需要对已经写好的东西再复制或者修改了。幸运的是,面向对象的开发方法给了我们很好的解决方案。

      2.2图解程序结构

      结过分析,我们发现Window应用程序,一般都有着如下的结构。

      即入口WinMain通过一个全局的Application * application来调用Application的InitInstance()方法,而Application::InitInstance()中又调用Window::Create()方法。这样一来,Window被创建,而系统、用户消息,如WM_PAINT之类的就可以传由Window的相应处理函数来处理。这样一来,程序底层就完成了,简单地说,这是一个没有任何功能的,但是可以接受各种消息的Windows应用。

      当我们想添加自己的功能时,只需要按照下图所示,分别继承Application和Window类。并在WinMain执行之前让全局的application指向MyApp的实例,这样一来,新程序中所有的消息就会转到我们自己的MyWin类中来处理,我们就可以随心所欲地添加自己的功能。

      到此,可能有人会有疑问:“在WinMain执行之前让全局的application指向MyApp的实例”?WinMain不是程序入口吗,怎么能在它执行之前还能做别的操作?

      这个问题甚至不需要回答,如果有此疑问的,请运行下面这样一段小程序,看看输出就明白了,为什么在WinMain之前还可以做很多很多操作:

      Code 001

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //------------Start---------------
    #include <iostream>
    using namespace std;
     
    int main() {
        cout << "我是 main()中第一行,我总是会第一个输出的吧! " << endl; // prints !!!Hello World!!!
        return 0;
    }
    class A{
    public:
        A(){
            cout<<"哈哈,那可不一定,我就会比main()早执行哦~"<<endl;
        }
    };
    A a;
    //--------------End---------------

      2.3用对象封装WindowsAPI

      面向对象编程的重点在于需要进行抽象。

      来看看上述的WIndows程序的建立过程,都是那样3步,于是我们把它总结出来,写成这样几个部分。

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    //----------------------------
    class App{
      App(){ app = this; }
      init();//调用Window的create方法
      run();//3:进入消息循环
      Window * MainWin;
    }
    App * app;
    //----------------------------
     
    //----------------------------
    class Window{
      create();//1:注册窗口类,并将该窗口的回调函数调为WndProc 2:建立并显示窗口
      virtual WndProc();//将消息映射到具体的处理函数 如WM_PAINT映射到OnPaint()
      virtual OnPaint();
      ...
    }    
    //----------------------------
     
    //----------------------------
    //入口
    int WinMain(){
      app->init();
      app->run()
    }
    //----------------------------


    展开全文
  • 欢迎加入 Windows 编程的世界! 在这里,我将一步一步地引导你进入这个神奇而有趣的世界。在开始之前,需要注意的是本教程中所有的例子都是在 Visual C++ 6.0 中调试通过,因此最好不要使用 Visual C++ 5.0 以下的...
  • Windows窗口的实现过程

    千次阅读 2006-01-03 20:33:00
    一个典型的用C和Win32 API写的窗口程序// 该示例描述了一个Windows窗口的实现过程,是应用Windows API函数进行编程的入门教程//// on_road// 
  • 不知道为什么,几乎所有的C++编程教程都是从命令行版(控制台应用程序)的Hello World开始的。然而,对于现在的年轻人来说,从小就用鼠标点击窗口或图标操作电脑,对于那个神秘黑色的窗口中的文字就像天书。对于我们...
  • 第4版面向C# 2005,在全面展示.NET新特性的同时继续完善原有的内容,是有一些C#基础知识的学习者或者想迁移到C#的其他程序员全面掌握C#的首选教程。 <br/>C#和.NET全面革新了编写程序的方式。本书以最新的...
  • 跟我一起学图形编程 作者:姚明联系方式:欢迎使用我的图形学教程。我是计算机专业的学生,对图形图像技术有浓厚的兴趣,就读期间广泛的涉及相关知识,但始终没有深入研究。原因很简单,我认为广度可以决定深度,...
  • VS2010_MFC编程入门教程

    2014-09-01 23:44:31
    比如各种窗口、工具栏、菜单的生成和管理等,不需要开发者再去解决那些很复杂很乏味的难题,比如每个窗口都要使用Windows API注册、生成与管理。这样就大大减少了软件开发者的工作量,提高了开发效率。
  • 现在我们要学的是Windows32的编程,与DOS不同的是,实现的目标是一个具有你所需要的功能的“窗口”。这个“窗口”时时刻刻都在与操作系统之间,通过一个称之为“消息队列”的东西传送数据。因此处理好各种消息便成了...
  • 第4章 Windows CE窗口和消息机制 第5章 Windows CE资源与控件编程 第7章 多线程编程 第7章 多线程编程 第8章 文件操作与通信编程 第8章 文件操作与通信编程 第10章 Windows CE系统定制 第11章 Windows CE内核机制 第...
  • 这篇博客主要记录一些在平时编程学习以及生活过程中会用到的一些Windows设置。 1. win10环境下时钟设置到秒 win10环境下桌面右下角的时钟默认是只显示到分钟的,有些时候我们需要时钟显示到秒,我们可以通过修改...
  • EXCEL编程VBA高级教程

    2015-04-16 11:40:55
    目录 一、VBA语言基础...................................................................................................................1 第一节标识符.....................................................
  • IDL编程语言入门教程

    2009-04-14 22:11:35
    Windows计算机上打印PostScript文件 156 生成封装的PostScript文件输出 156 封装PostScript图形的预览 157 生成彩色的PostScript输出 157 PostScript中的彩色图像与灰度图像 158 在PostScript设备上创建高质量的...
  • xcode是一款运行在Mac OS X上的集成开发工具,具有统一的用户界面设计,且编码、测试、调试都在一个简单的窗口内完成,还能够与Swift编程语言相结合,使开发应用程序比以往更轻松,更有趣,便有许多用户也想要进行...
  • OpenGL教程(2):编程初步

    千次阅读 2011-10-22 15:29:10
    配置完GLUT开发环境。就可以在VS2010中进行OpenGL编程了。下面的教程综合了网上已有的教程和本人自己的体会。 一、 创建工程 ...由于GLUT已经为你处理了windows窗口,所以你不必要重复引用window
  • 妙用SendKeys简化重复操作1 每次开机的时候,你想自动登陆你的QQ或者博客吗?巧妙使用VBS中的SendKeys命令(这个命令的作用就是模拟键盘操作,将一个或多个按键指令发送到指定Windows窗口来控制应用程序运行),
  • python的GUI界面编程常用的几个python库包含如下 Tkinter Tkinter 模块(Tk 接口)是 Python 的标准 Tk GUI 工具包的接口 .Tk 和 Tkinter可以在大多数的 Unix 平台下使用,同样可以应用在 Windows 和 Macintosh 系统里...
  • 个人博客地址:KsGin Blog 哈哈哈哈哈哈是不是超熟悉的。继 OpenGL 基础学完后...在很久之前,写者也是接触了一些 Windows 编程的,当然仅仅只是一点。也就写出来了几个窗口,还是跟着教程的。现在在学习了 OpenGL ...
  • 中文Windows 2000 Server 24学时教程 下载次数:1560 点击次数:649 读者评价: 购物车 查看购物 修改购物 清空购物 购书指南 英文原书名: Sams Teach Yourself Microsoft...
  • 在这个预备教程中,我们学习创建一个Win32程序的必要步骤,并创建一个空白窗体用于Direct3D 10。 源代码 文件位置:(SDK root)\Samples\C++\Direct3D10\Tutorials\Tutorial00。 本网站下载:Tutorial00.zip。 ...
  • python GUI编程(Tkinter)(高级教程

    千次阅读 2017-08-12 15:26:40
    Tkinter: Tkinter模块("Tk 接口")是Python的标准Tk GUI工具包的接口.Tk和Tkinter可以在大多数的Unix平台下使用,同样可以应用在Windows和Macintosh系统里.,Tk8.0的后续版本可以实现本地窗口风格,并良好地
  • 教程无KEY wmv版本,手机平板等移动设备均可观看! 第1部分 入门 第1章 学习开发游戏的基础知识 1.1 认识视频游戏 1.1.1 为什么人们如此沉迷于开发视频游戏 1.1.2 视频游戏的类型 1.2 学习游戏设计的要素 ...
  • 常见的图形编程库,除了 GDI 外还有 GDI+、OpenGL、DirectX等等,GDI 是其中最基础的一个库。所以 GDI 注定了不会有高级应用,有兴趣的就当刷低级怪吧。 在教程的最开始,需要简单的说明一些前置条件。 开发环境与...
  • Tkinter: Tkinter模块("Tk 接口")是Python的标准Tk GUI工具包的接口.Tk和Tkinter可以在大多数的Unix平台下使用,同样可以应用在Windows和Macintosh系统里.,Tk8.0的 后续版本可以实现本地窗口风格,并良好地运行在

空空如也

空空如也

1 2 3 4 5 ... 14
收藏数 268
精华内容 107
关键字:

windows窗口编程教程