【高级程序设计 实验报告8】MFC菜单和工具栏

上一篇:【高级程序设计 实验报告7】文件读写

目录

一、实验目的

二、实验环境

三、实验内容

四、实验步骤

代码

代码解释

一、实验目的

利用 C++编写两个窗口切换。

二、实验环境

Vc++ 6.0、Windows10

三、实验内容

实现多窗口的创建。

四、实验步骤

1)相关知识

由于对话框是一个特殊的窗口,所以该类是从 CWnd 类中派生出来的。对话框子层次

结构包括通用对话框类 CDialog 以及支持文件选择、颜色选择、字体选择、打印、替换文本

的公共对话框子类。

2)编程要求

实现多窗口的创建。

3)测试说明

4)实验结果:

截图:

代码

cpp 复制代码
#include <windows.h>
#include <commctrl.h>

// 链接 comctl32.lib 库
#pragma comment(lib, "comctl32.lib")

// 定义常量
#define IDR_MENU1 101
#define IDM_SHOW 1001
#define IDM_RED 1002
#define IDM_GREEN 1003
#define IDM_BLUE 1004
#define IDC_TOOLBAR1 1005

// 全局变量
HFONT hFont;
COLORREF textColor = RGB(0, 0, 0);
HWND hToolbar;
const wchar_t* text = L"2252705郑道源";

// 窗口过程函数
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

// 创建窗口类
void create(WNDCLASSEXW* wcex, HINSTANCE hInstance, const wchar_t lpszClassName[]) {
    wcex->cbSize = sizeof(WNDCLASSEXW);
    wcex->style = 0;
    wcex->lpfnWndProc = WndProc;
    wcex->cbClsExtra = 0;
    wcex->cbWndExtra = 0;
    wcex->hInstance = hInstance;
    wcex->hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_APPLICATION));
    wcex->hCursor = LoadCursorW(NULL, IDC_ARROW);
    wcex->hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wcex->lpszMenuName = MAKEINTRESOURCEW(IDR_MENU1);
    wcex->lpszClassName = lpszClassName;
    wcex->hIconSm = LoadIconW(wcex->hInstance, MAKEINTRESOURCEW(IDI_APPLICATION));
}

// 创建工具条
void CreateToolbar(HWND hWnd, HINSTANCE hInstance) {
    hToolbar = CreateWindowExW(
        0, TOOLBARCLASSNAMEW, NULL,
        WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_ALTDRAG,
        0, 0, 0, 0, hWnd, (HMENU)IDC_TOOLBAR1, hInstance, NULL
    );

    // 添加按钮
    TBBUTTON tbButtons[] = {
        { STD_FILENEW, IDM_SHOW, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0}, 0, (INT_PTR)L"显示" },
        { STD_FILENEW, IDM_RED, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0}, 0, (INT_PTR)L"红色" },
        { STD_FILENEW, IDM_GREEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0}, 0, (INT_PTR)L"绿色" },
        { STD_FILENEW, IDM_BLUE, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0}, 0, (INT_PTR)L"蓝色" }
    };

    SendMessageW(hToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
    SendMessageW(hToolbar, TB_ADDBUTTONS, (WPARAM)4, (LPARAM)tbButtons);
    SendMessageW(hToolbar, TB_AUTOSIZE, 0, 0);

    // 设置工具条可停靠
    SendMessageW(hToolbar, TB_SETEXTENDEDSTYLE, 0, (LPARAM)TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_MIXEDBUTTONS);
    RECT rc;
    GetClientRect(hWnd, &rc);
    SetWindowPos(hToolbar, HWND_TOP, 0, 0, rc.right, 0, SWP_SHOWWINDOW);
}

// 主函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow) {
    INITCOMMONCONTROLSEX icex;
    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    icex.dwICC = ICC_BAR_CLASSES;
    InitCommonControlsEx(&icex);

    WNDCLASSEXW wcex;
    HWND hWnd;
    MSG msg;
    const wchar_t lpszClassName[] = L"window";
    const wchar_t lpszTitle[] = L"My_Windows";

    create(&wcex, hInstance, lpszClassName);

    // 注册窗口类
    if (!RegisterClassExW(&wcex)) {
        MessageBoxW(NULL, L"窗口类注册失败!", L"窗口注册", NULL);
        return 1;
    }

    // 创建窗口
    hWnd = CreateWindowExW(
        0, lpszClassName, lpszTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL,
        hInstance, NULL
    );

    if (!hWnd) {
        MessageBoxW(NULL, L"窗口创建失败!", L"窗口创建", NULL);
        return 1;
    }

    // 创建工具条
    CreateToolbar(hWnd, hInstance);

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    // 消息循环
    while (GetMessageW(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return static_cast<int>(msg.wParam);
}

// 窗口过程函数实现
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
    case WM_CREATE:
        hFont = CreateFontW(24, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
            OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
            DEFAULT_PITCH | FF_SWISS, L"Arial");
        break;
    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case IDM_SHOW:
            InvalidateRect(hwnd, NULL, TRUE);
            break;
        case IDM_RED:
            textColor = RGB(255, 0, 0);
            InvalidateRect(hwnd, NULL, TRUE);
            break;
        case IDM_GREEN:
            textColor = RGB(0, 255, 0);
            InvalidateRect(hwnd, NULL, TRUE);
            break;
        case IDM_BLUE:
            textColor = RGB(0, 0, 255);
            InvalidateRect(hwnd, NULL, TRUE);
            break;
        }
        break;
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        SelectObject(hdc, hFont);
        SetTextColor(hdc, textColor);
        SetBkMode(hdc, TRANSPARENT);
        RECT rect;
        GetClientRect(hwnd, &rect);
        DrawTextW(hdc, text, -1, &rect, DT_CENTER | DT_VCENTER);
        EndPaint(hwnd, &ps);
        break;
    }
    case WM_DESTROY:
        DeleteObject(hFont);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProcW(hwnd, message, wParam, lParam);
    }
    return 0;
}

代码解释

工具条创建时添加样式:在创建工具条的 CreateWindowExW 函数中添加了 TBSTYLE_ALTDRAG 样式,该样式允许工具条被拖动停靠。

设置工具条扩展样式:使用 SendMessageW 函数设置工具条的扩展样式,通过 TB_SETEXTENDEDSTYLE 消息设置为 TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_MIXEDBUTTONS,增强工具条的功能和外观。

初始化公共控件:在 WinMain 函数中添加了 InitCommonControlsEx 函数调用,初始化公共控件类,确保工具条等控件能正常工作。

工具提示功能:之前代码中已经通过 TBSTYLE_TOOLTIPS 样式启用了工具提示功能,当鼠标悬停在工具条按钮上时,会显示按钮的提示信息。

实验心得

本次MFC菜单和工具栏实验,核心任务是利用C++实现多窗口创建及菜单、工具栏的功能开发,通过亲手编写代码、调试程序、验证功能,我不仅掌握了MFC相关的基础编程方法,更对Windows窗口程序的运行机制有了系统认知,在实操能力和问题解决能力上得到了显著提升,同时也深刻认识到程序设计中规范与细节的重要性。

实验开始前,我先系统回顾了对话框与窗口的相关理论知识,了解到对话框作为特殊的窗口,由CWnd类派生而来,而CDialog类及其子类则支持多种公共对话框功能。起初,我对窗口类的注册、创建流程,以及菜单、工具栏的关联方法理解较为模糊,尤其是工具条的样式设置、消息循环的作用,始终存在抽象难懂的问题。但随着实验的推进,我结合代码逐行分析,逐渐理清了核心逻辑,明白窗口程序的运行离不开窗口类注册、窗口创建、消息循环这三个关键步骤,而菜单和工具栏的功能实现,本质上是通过消息响应机制完成用户操作与程序功能的联动。

本次实验的核心是实现多窗口创建、菜单功能和工具栏功能,看似简单的需求,实际编程过程中却遇到了不少难点。在编写代码时,我最初忘记调用InitCommonControlsEx函数初始化公共控件,导致工具条无法正常显示,程序运行后只有窗口框架,没有预期的工具按钮。经过排查资料和反复调试,我意识到公共控件的初始化是工具条、菜单等控件正常工作的前提,缺少这一步会导致控件创建失败。此外,在设置工具条样式时,我曾因遗漏TBSTYLE_TOOLTIPS样式,导致工具条按钮的提示功能无法实现,后来通过补充样式设置,成功解决了这一问题。这些挫折让我明白,Windows窗口编程对规范性要求极高,每一个函数调用、每一个样式设置都有其作用,稍有遗漏就会影响程序功能的正常实现。

在解决各类问题后,我成功完成了程序调试,验证了所有功能:窗口能够正常创建,工具栏上的"显示""红色""绿色""蓝色"按钮可正常响应,点击颜色按钮能切换窗口内文本颜色,点击"显示"按钮可刷新文本显示,菜单功能与工具栏按钮实现联动,程序运行稳定,无报错退出。通过分析代码结构,我对实验核心知识点有了更清晰的掌握:窗口类的创建通过WNDCLASSEXW结构体定义,包含窗口过程函数、图标、光标、背景等属性;工具条的创建通过CreateWindowExW函数实现,添加按钮、设置样式和停靠功能,需借助SendMessageW函数传递消息;消息循环则负责接收和分发用户操作消息,窗口过程函数处理各类消息,实现功能响应。

通过本次实验,我不仅熟练掌握了MFC菜单和工具栏的基本开发方法,掌握了窗口类注册、窗口创建、工具条初始化的核心步骤,还学会了排查Windows编程中的常见错误,比如公共控件未初始化、控件样式设置遗漏等,提升了自身的实操能力和问题解决能力。同时,我也认识到自己的不足:对消息响应机制的理解还不够深入,难以灵活处理复杂的消息交互;对MFC高级功能的了解较少,比如多窗口切换的进阶实现、菜单的多级设置等,还需要进一步学习和实践。此外,在代码编写的规范性上还有提升空间,比如代码注释不够详细、变量命名的逻辑性有待加强,这些细节都需要在今后的实验中加以改进。

本次实验让我深刻体会到,Windows窗口编程是一个注重逻辑、强调规范的过程,每一个步骤都环环相扣,每一个细节都可能影响程序的最终效果。实验不仅巩固了我所学的C++编程知识,更让我认识到理论与实践结合的重要性------脱离实操的理论学习只能停留在表面,只有亲手编写代码、调试错误,才能真正理解窗口程序的运行原理。在今后的学习中,我将更加注重积累Windows编程的相关知识,多动手、多思考、多总结,不断提升自己的编程能力,为后续更复杂的MFC开发和窗口编程打下坚实的基础,同时培养自己严谨细致的编程习惯,写出高效、规范、稳定的程序。

相关推荐
keep intensify2 小时前
康复训练 3
c++
co_wait2 小时前
【C++ STL】list容器的基本使用
开发语言·c++·list
枫叶丹42 小时前
【Qt开发】Qt界面优化(十)->常用控件--复选框
c语言·开发语言·c++·qt
宵时待雨2 小时前
C++笔记归纳9:模板进阶
开发语言·数据结构·c++·笔记
爱装代码的小瓶子2 小时前
【c++与Linux进阶】轻量化进程与虚拟地址和页表
linux·开发语言·c++
零号全栈寒江独钓3 小时前
visual studio编译wxWidgets
c++·visual studio
努力中的编程者3 小时前
哈希表(C语言底层实现)
c语言·数据结构·c++·算法·哈希算法·散列表
mjhcsp3 小时前
C++ 迭代加深搜索(IDDFS):从原理到实战的深度解析
c++·深度优先·迭代加深
摆烂小白敲代码3 小时前
【数据结构与算法】汉诺塔问题(C++)
c语言·开发语言·数据结构·c++·算法·hanoi·汉诺塔问题