Qt文本编辑器软件开发项目实战:轻量高效,功能全面,三万字全面解析!!源代码开源分享

 项目地址:

https://gitee.com/fan-wenshan/qt-notebook-project-coursework

NoteBook 项目

这是一个简单的文本编辑器应用程序,基于Qt框架开发。

项目结构

  • main.cpp: 应用程序的入口点。
  • mytextedit.cpp/h: 提供自定义文本编辑组件 MyTextEdit 的实现和定义。
  • widget.cpp/h: 主窗口组件的实现和定义,提供缩放、事件过滤和文件操作等功能。
  • widget.ui: 主窗口的UI设计文件。
  • res.qrc: Qt资源文件。
  • noteBook.pro: 项目配置文件。

主要功能

  • 缩放功能: 支持通过 zoomIn() 和 zoomOut() 方法放大或缩小文本。
  • 文件操作: 包括打开、保存和关闭文件功能,通过 on_btnFileOpen_clicked()on_btnFileSave_clicked(), 和 on_btnFileClose_clicked() 实现。
  • 事件处理: 包括滚轮事件、键盘事件的处理,以及下拉索引改变和光标位置变化的响应。
  • 自定义文本编辑器MyTextEdit 类扩展了 QTextEdit,实现了自定义的滚轮事件和按键事件处理。

编译和运行

确保安装了Qt开发环境(如Qt Creator),然后使用qmake和.pro文件编译项目。

Gitee主页截图:

项目截图:

源代码片段分享:

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mytextedit.cpp \
    widget.cpp

HEADERS += \
    mytextedit.h \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    res.qrc

你提供的这段代码是 Qt 项目中的 .pro 文件,即 Qt 项目配置文件(Project File)。它用于告诉 qmake 工具如何构建你的应用程序,包括需要链接哪些库、使用什么语言标准、包含哪些源文件和资源等。


📄 一、完整带注释版 .pro 文件

# 指定使用的 Qt 模块:core 和 gui
QT       += core gui

# 如果 Qt 主版本号大于 4,则添加 widgets 模块(适用于 Qt5 及以上)
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

# 启用 C++11 标准支持
CONFIG += c++11

# 可选:如果你希望禁用旧版本的废弃 API,可以取消下面这行的注释
# DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # 禁用 Qt 6.0 之前废弃的 API

# 源代码文件列表(.cpp)
SOURCES += \
    main.cpp \
    mytextedit.cpp \
    widget.cpp

# 头文件列表(.h)
HEADERS += \
    mytextedit.h \
    widget.h

# UI 设计文件(由 Qt Designer 生成)
FORMS += \
    widget.ui

# 部署规则:定义程序安装路径
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

# 资源文件(如图片、图标等),通过 :/ 访问
RESOURCES += \
    res.qrc

🧱 二、逐行解释 + 功能说明

✅ 1. 指定使用的 Qt 模块

QT += core gui
  • core:Qt 的核心模块,提供基本类(如 QString、QList、QMap 等);
  • gui:图形界面基础模块,提供窗口系统集成、绘图、窗口部件基类等;
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
  • 如果 Qt 版本大于 4(即 Qt5 或 Qt6),则加入 widgets 模块;
  • widgets 是传统桌面 GUI 开发的核心模块,提供 QWidgetQPushButtonQLabel 等控件;
  • 在 Qt5 及以后版本中,Widgets 模块是可选的,不是默认包含的;

✅ 2. 启用 C++11 支持

CONFIG += c++11
  • 告诉编译器启用 C++11 标准特性;
  • 例如支持 Lambda 表达式、自动类型推导(auto)、范围 for 循环等;

✅ 3. (可选)禁用废弃的 API

#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000
  • 如果你希望在项目中禁止使用过时的函数或类,可以取消这一行的注释;
  • 这样可以让编译器在使用了 Qt 6.0 之前被标记为“废弃”的 API 时报错;
  • 有助于提前发现兼容性问题,特别是在升级 Qt 版本时;

✅ 4. 源文件列表

SOURCES += \
    main.cpp \
    mytextedit.cpp \
    widget.cpp
  • 列出所有 .cpp 源代码文件;
  • main.cpp 是程序入口;
  • mytextedit.cpp 是你自定义的文本编辑控件实现;
  • widget.cpp 是主窗口的实现;

✅ 5. 头文件列表

HEADERS += \
    mytextedit.h \
    widget.h
  • 列出所有 .h 头文件;
  • mytextedit.h 是自定义文本编辑控件的头文件;
  • widget.h 是主窗口的头文件;

✅ 6. UI 设计文件

FORMS += \
    widget.ui
  • 使用 Qt Designer 创建的 .ui 文件;
  • 会被 uic 工具自动转换为 C++ 代码;
  • 例如:widget.ui → 自动生成 ui_widget.h 文件;

✅ 7. 安装路径设置(部署规则)

qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
  • 设置程序在不同平台上的安装路径;
  • $${TARGET} 是项目名称(从 TARGET = xxx 中获取,默认是项目目录名);
  • INSTALLS += target 表示要安装目标可执行文件;
平台安装路径
QNX 系统/tmp/项目名/bin
其他 Unix 系统(非 Android)/opt/项目名/bin

⚠️ 注意:这个功能主要用于嵌入式开发或 Linux 环境下的部署。


✅ 8. 资源文件

RESOURCES += \
    res.qrc
  • .qrc 是 Qt 的资源文件,用于将图片、图标、翻译文件等打包进可执行文件;
  • 通过 :/ 路径访问资源,例如:
    QIcon(":/icons/app_icon.png")

📌 三、总结:.pro 文件的作用

配置项作用
QT += ...指定项目使用的 Qt 模块
CONFIG += c++11启用 C++11 标准
SOURCES添加源代码文件
HEADERS添加头文件
FORMS添加 Qt Designer 设计的 UI 文件
RESOURCES添加资源文件(如图标、图片)
INSTALLS设置部署安装路径
DEFINES定义预处理宏(如禁用废弃 API)

🧩 四、扩展建议

你可以在这个 .pro 文件基础上添加更多高级配置:

功能示例代码
自定义输出目录DESTDIR = bin
添加调试信息CONFIG += console debug
构建静态库TEMPLATE = lib + CONFIG += staticlib
添加第三方库LIBS += -L/path/to/lib -lmylib
添加预处理器宏DEFINES += MY_CUSTOM_DEFINE
支持多语言TRANSLATIONS += myapp_zh.ts

如果你希望我帮你:

  • 把这个 .pro 文件改造成适合发布项目的结构;
  • 教你如何添加图标、菜单栏、工具栏;
  • 或者教你如何跨平台构建(Windows/Linux/macOS); 欢迎继续提问 😊
#ifndef MYTEXTEDIT_H
#define MYTEXTEDIT_H

#include <QTextEdit>

class MyTextEdit : public QTextEdit
{
public:
    MyTextEdit(QWidget *parent);
protected:

    void wheelEvent(QWheelEvent *e) override;
    void keyPressEvent(QKeyEvent *e) override;
    void keyReleaseEvent(QKeyEvent *e) override;
private:
    bool ctrlKeyPressed = 0;

};

#endif // MYTEXTEDIT_H

这段代码定义了一个名为 MyTextEdit 的类,它是基于 Qt 框架的自定义文本编辑控件。通过继承 QTextEdit 类并重写其事件处理函数,该类实现了对 Ctrl 键加鼠标滚轮操作的特殊处理(比如放大或缩小文本)。下面是对每一部分代码的详细解释和功能阐述。

代码解释

#ifndef MYTEXTEDIT_H
#define MYTEXTEDIT_H

#include <QTextEdit>
  • 这两行是头文件保护宏,防止重复包含。
  • #include <QTextEdit> 引入了 QTextEdit 类的定义,MyTextEdit 将继承自这个类。
class MyTextEdit : public QTextEdit {
public:
    MyTextEdit(QWidget *parent);
  • 定义了 MyTextEdit 类,它公开继承自 QTextEdit
  • 提供了一个构造函数,接受一个指向父控件的指针作为参数。这在Qt中用于设置控件的父子关系,便于内存管理和布局。
protected:
    void wheelEvent(QWheelEvent *e) override;
    void keyPressEvent(QKeyEvent *e) override;
    void keyReleaseEvent(QKeyEvent *e) override;
  • 在 protected 部分声明了三个成员函数,它们分别重写了 QTextEdit 的相应事件处理函数:
    • wheelEvent: 当鼠标滚轮被滚动时调用。在这个例子中,可能会根据是否按下了Ctrl键来改变字体大小。
    • keyPressEvent: 当键盘按键被按下时调用。这里可以用来检测Ctrl键是否被按下,并更新内部状态。
    • keyReleaseEvent: 当键盘按键被释放时调用。可用于检测Ctrl键是否被释放,并相应地更新内部状态。
private:
    bool ctrlKeyPressed = 0;
};
#endif // MYTEXTEDIT_H
  • 在 private 部分定义了一个布尔类型的变量 ctrlKeyPressed,初始值为 false (使用整数0初始化),用于跟踪Ctrl键的状态。
  • 最后,#endif 结束了头文件保护宏。

功能阐述

核心功能

MyTextEdit 类的主要目的是提供一种机制,允许用户通过按住Ctrl键并滚动鼠标滚轮来调整文本的大小(即缩放文本)。这是通过对鼠标滚轮事件(wheelEvent)、按键按下事件(keyPressEvent)以及按键释放事件(keyReleaseEvent)进行重写实现的。

  • Ctrl键状态追踪:通过 keyPressEvent 和 keyReleaseEvent 方法监听Ctrl键的状态变化,并更新 ctrlKeyPressed 变量。
  • 滚轮事件处理:在 wheelEvent 方法中,检查 ctrlKeyPressed 是否为真,如果为真,则根据滚轮滚动的方向(向上或向下)调整文本的大小。

这种设计使得 MyTextEdit 控件能够提供类似许多现代应用程序中的便捷功能,如浏览器中的Ctrl+滚轮缩放网页内容。这样的交互方式提高了用户体验,特别是在需要频繁调整文本大小的应用场景中。

请注意,为了使上述功能完全工作,还需要在 .cpp 文件中实现这些方法的具体逻辑,例如如何在 wheelEvent 中根据滚轮方向调用 zoomIn()zoomOut() 方法来调整文本大小。

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include<QDebug>
#include <QFile>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    QFile file;
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void zoomIn();
    void zoomOut();
//    bool eventFilter(QObject *watched, QEvent *event);

private slots:

    void on_btnFileOpen_clicked();

    void on_btnFileSave_clicked();

    void on_btnFileClose_clicked();

    void oncurrentIndexChanged(int index);

    void oncursorPositionChanged();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

你提供的这段代码是 widget.h 文件,这是 Qt 项目中一个自定义窗口类的头文件。这个类名为 Widget,继承自 QWidget,表示你的主界面窗口。它包含了 UI 操作、文件操作以及可能的事件处理功能。


🧱 一、完整带注释版代码

#ifndef WIDGET_H
#define WIDGET_H

// 标准头文件
#include <QWidget>       // QWidget 是 Qt 中所有 UI 控件的基类
#include <QDebug>        // 提供调试输出功能(如 qDebug())
#include <QFile>         // 提供对文件的读写操作支持

// 告诉 qmake 使用哪些 Qt 模块(在 .pro 文件中配置)
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }  // 前向声明 Ui::Widget 类,由 widget.ui 自动生成
QT_END_NAMESPACE

// 主窗口类定义
class Widget : public QWidget
{
    Q_OBJECT  // 启用信号与槽机制的关键宏

public:
    QFile file;  // 成员变量:用于操作当前打开的文件

    // 构造函数,默认父控件为 nullptr
    explicit Widget(QWidget *parent = nullptr);

    // 析构函数
    ~Widget();

    // 放大字体函数
    void zoomIn();

    // 缩小字体函数
    void zoomOut();

    // 可选:事件过滤器函数原型(被注释掉了)
    // bool eventFilter(QObject *watched, QEvent *event);

private slots:
    // 按钮点击事件对应的槽函数

    // 打开文件按钮点击事件
    void on_btnFileOpen_clicked();

    // 保存文件按钮点击事件
    void on_btnFileSave_clicked();

    // 关闭文件按钮点击事件
    void on_btnFileClose_clicked();

    // 下拉框内容改变时触发
    void oncurrentIndexChanged(int index);

    // 光标位置变化时触发
    void oncursorPositionChanged();

private:
    // 指向通过 Qt Designer 创建的 UI 的指针
    Ui::Widget *ui;
};

#endif // WIDGET_H

📝 二、逐行解释 + 功能说明

✅ 1. 头文件保护宏

#ifndef WIDGET_H
#define WIDGET_H
...
#endif // WIDGET_H
  • 防止该头文件被多次包含;
  • 这是 C++ 编程中的标准做法;

✅ 2. 引入必要的 Qt 类

#include <QWidget>
#include <QDebug>
#include <QFile>
  • QWidget:Qt 界面开发的基础类;
  • QDebug:用于调试信息输出;
  • QFile:用于文件的读写操作;

✅ 3. 命名空间和 UI 类前向声明

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
  • 表示使用 Qt 的命名空间;
  • Ui::Widget 是由 .ui 文件自动生成的类,用于绑定 UI 组件;
  • 这里只是前向声明,完整的定义在 ui_widget.h 中(由 uic 工具生成);

✅ 4. 类定义:class Widget : public QWidget

class Widget : public QWidget
{
    Q_OBJECT
  • Q_OBJECT:启用 Qt 的元对象系统(Meta-Object System),使你能使用:
    • 信号/槽机制;
    • 属性系统;
    • 动态翻译等高级功能;

✅ 5. 公共成员函数

public:
    QFile file;
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void zoomIn();
    void zoomOut();
  • QFile file;:用于存储当前打开的文件对象;
  • Widget(QWidget *parent):构造函数;
  • ~Widget():析构函数;
  • zoomIn() / zoomOut():放大/缩小文本字体大小的函数;

✅ 6. 私有槽函数(Private Slots)

private slots:
    void on_btnFileOpen_clicked();
    void on_btnFileSave_clicked();
    void on_btnFileClose_clicked();
    void oncurrentIndexChanged(int index);
    void oncursorPositionChanged();

这些是自动连接的 私有槽函数,它们会响应来自 UI 的事件:

函数触发条件
on_btnFileOpen_clicked()用户点击“打开文件”按钮
on_btnFileSave_clicked()用户点击“保存文件”按钮
on_btnFileClose_clicked()用户点击“关闭文件”按钮
oncurrentIndexChanged(int index)下拉菜单选择项发生变化
oncursorPositionChanged()文本光标位置发生改变

⚠️ 注意:oncurrentIndexChangedoncursorPositionChanged 这两个函数名称不是自动匹配的,需要手动连接信号和槽。


✅ 7. 私有成员变量

private:
    Ui::Widget *ui;
  • ui 是指向 UI 对象的指针;
  • 通过它你可以访问 .ui 文件中设计的所有控件(如按钮、文本框等);
  • 例如:ui->textEdit->setText("Hello");

📌 三、功能总结

功能模块描述
自定义主窗口Widget 继承自 QWidget,作为程序的主界面
文件操作使用 QFile 实现文件打开、保存、关闭等功能
字体缩放提供 zoomIn() 和 zoomOut() 方法实现字体大小调整
事件响应通过私有槽函数响应按钮点击、下拉框变化、光标移动等
UI 管理使用 Qt Designer 设计界面,通过 ui 指针访问控件

🧩 四、可扩展建议

你可以在此基础上进一步增强这个窗口的功能:

扩展方向实现方式
Ctrl+滚轮缩放添加 eventFilter() 并监听滚轮事件
多文档支持使用 QMdiArea 实现多标签页编辑器
语法高亮使用 QSyntaxHighlighter 实现代码高亮
自动保存定期将内容写入临时文件
导出 PDF使用 QTextDocument::print() 或 QPdfWriter
查找替换功能添加查找框并实现搜索逻辑
拖拽文件打开重写 dragEnterEvent() 和 dropEvent()

✅ 五、总结

这是一个结构清晰、功能完整的 Qt 主窗口类头文件,适合用于构建富文本编辑器、日志查看器、简易 IDE 等应用程序。

如果你希望我帮你:

  • 写出 .cpp 文件的具体实现;
  • 教你如何添加拖拽打开文件功能;
  • 或者教你如何加入 Ctrl+滚轮 缩放功能; 欢迎继续提问 😊
#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

你提供的这段代码是 Qt 应用程序的 主函数,它负责启动应用程序并显示主窗口。这段代码非常典型,用于初始化 QApplication 对象、创建并显示主窗口 (Widget),然后进入应用程序的主事件循环。

代码逐行解释

#include "widget.h"
#include <QApplication>
  • #include "widget.h":包含自定义的 Widget 类声明头文件。Widget 是你的主窗口类,继承自 QWidget
  • #include <QApplication>:包含 Qt 的 QApplication 类定义,它是所有基于 Qt 的 GUI 应用程序的基础。
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
  • int main(int argc, char *argv[]):这是 C++ 程序的入口点。argc 和 argv 分别代表命令行参数的数量和值。
  • QApplication a(argc, argv);:创建一个 QApplication 对象,这是每个 Qt 应用程序必须有的对象。它管理应用程序范围内的资源,并处理常见的应用程序级操作(如事件处理)。
    Widget w;
    w.show();
  • Widget w;:创建 Widget 类的一个实例 w。这个实例就是你的应用程序主窗口。
  • w.show();:调用 show() 方法显示窗口。默认情况下,窗口是隐藏的,需要显式调用 show() 来显示它。
    return a.exec();
}
  • a.exec();:进入应用程序的主事件循环。这个调用会阻塞直到应用程序退出(例如用户关闭了主窗口)。exec() 返回后,你可以获取其返回值作为 main() 函数的返回值,通常用来指示应用程序的退出状态。

功能概述

这段代码的功能可以概括为:

  1. 初始化应用程序:通过创建 QApplication 对象来设置应用程序环境。
  2. 创建主窗口:实例化 Widget 类,这通常是你的主界面。
  3. 显示主窗口:调用 show() 方法将窗口显示出来。
  4. 运行事件循环:调用 exec() 方法进入 Qt 的事件处理循环,等待用户交互或其他事件发生,直到用户关闭应用程序。

示例场景

假设你已经定义了一个名为 Widget 的类,它可能包含了按钮、文本框等控件,并且设置了相应的槽函数以响应用户的交互(比如点击按钮保存文件或打开文件)。当你运行这个程序时:

  • 窗口将会显示在屏幕上。
  • 用户可以通过与界面上的控件互动(如点击按钮)触发特定的操作。
  • 当用户关闭主窗口时,exec() 返回,应用程序结束,控制权回到操作系统。

注意事项

  • 确保 .pro 文件配置正确:确保你的项目文件中正确地包含了所有的源文件、头文件以及资源文件。
  • UI 设计:如果你使用了 Qt Designer 设计 UI,则确保 .ui 文件被正确加载并在 Widget 类中使用。
  • 错误处理:虽然这段代码非常基础,但在实际开发中,你可能还需要添加一些错误处理机制,比如检查命令行参数、处理异常情况等。

如果你有更多关于如何扩展此功能的问题,或者有关于 Qt 编程的其他问题,请随时提问!

#include "mytextedit.h"

#include <QWheelEvent>
#include <QDebug>


MyTextEdit::MyTextEdit(QWidget *parent) : QTextEdit(parent)
{

}

void MyTextEdit::wheelEvent(QWheelEvent *e)
{
//    qDebug() << e->angleDelta().y();
    if(ctrlKeyPressed == 1){
    if(e->angleDelta().y() > 0){
        zoomIn();
    }else if(e->angleDelta().y() < 0){
        zoomOut();
    }
        e->accept();
    }else{
        QTextEdit ::wheelEvent(e);
    }
}

void MyTextEdit::keyPressEvent(QKeyEvent *e)
{
    if(e->key() == Qt::Key_Control){
//        qDebug() << "ControlPress";
        ctrlKeyPressed = 1;
    }
    QTextEdit ::keyPressEvent(e);
}

void MyTextEdit::keyReleaseEvent(QKeyEvent *e)
{
    if(e->key() == Qt::Key_Control){
//        qDebug() << "ControlRelease";
        ctrlKeyPressed = 0;
    }
    QTextEdit ::keyPressEvent(e);
}

你提供的代码实现了 MyTextEdit 类,这是一个自定义的文本编辑控件,继承自 QTextEdit。它重写了三个事件处理函数:wheelEvent()keyPressEvent()keyReleaseEvent(),以实现当用户按住 Ctrl 键并滚动鼠标滚轮时放大或缩小文本的功能。

代码解释

#include "mytextedit.h"

#include <QWheelEvent>
#include <QDebug>

MyTextEdit::MyTextEdit(QWidget *parent) : QTextEdit(parent)
{
    // 构造函数,初始化父类 QTextEdit
}
  • 构造函数:调用父类 QTextEdit 的构造函数进行初始化。这确保了 MyTextEdit 实例是一个有效的 QTextEdit 控件。
void MyTextEdit::wheelEvent(QWheelEvent *e)
{
    if(ctrlKeyPressed == 1){
        if(e->angleDelta().y() > 0){
            zoomIn();
        } else if(e->angleDelta().y() < 0){
            zoomOut();
        }
        e->accept();  // 标记事件已被处理
    } else {
        QTextEdit::wheelEvent(e);  // 调用基类方法处理其他滚轮事件
    }
}
  • wheelEvent():重写 QTextEdit 的 wheelEvent 方法。
    • 如果 ctrlKeyPressed 为 true(即用户按下了 Ctrl 键),根据滚轮滚动方向调用 zoomIn() 或 zoomOut() 方法。
    • 使用 e->accept() 来表明该事件已经被处理,不需要进一步传播。
    • 如果 Ctrl 键未按下,则调用基类的 wheelEvent 方法来执行默认的滚轮行为(如上下滚动文本)。
void MyTextEdit::keyPressEvent(QKeyEvent *e)
{
    if(e->key() == Qt::Key_Control){
//        qDebug() << "ControlPress";
        ctrlKeyPressed = 1;
    }
    QTextEdit::keyPressEvent(e);  // 调用基类方法处理其他按键事件
}
  • keyPressEvent():重写 QTextEdit 的 keyPressEvent 方法。
    • 如果检测到按下的键是 Ctrl 键,则将 ctrlKeyPressed 设置为 true
    • 调用基类的 keyPressEvent 方法来处理其他按键事件。
void MyTextEdit::keyReleaseEvent(QKeyEvent *e)
{
    if(e->key() == Qt::Key_Control){
//        qDebug() << "ControlRelease";
        ctrlKeyPressed = 0;
    }
    // 注意:这里应该是 keyReleaseEvent 而不是 keyPressEvent
    QTextEdit::keyReleaseEvent(e);  // 调用基类方法处理其他按键释放事件
}
  • keyReleaseEvent():重写 QTextEdit 的 keyReleaseEvent 方法。
    • 如果检测到释放的键是 Ctrl 键,则将 ctrlKeyPressed 设置为 false
    • 注意:这里的 QTextEdit::keyPressEvent(e); 应该改为 QTextEdit::keyReleaseEvent(e);,因为这是处理按键释放事件的函数。

错误修正

keyReleaseEvent() 函数中,有一处错误:

QTextEdit::keyPressEvent(e);

应更正为:

QTextEdit::keyReleaseEvent(e);

这是因为 keyReleaseEvent() 是用于处理按键释放事件的,而不是按键按下事件。

完整修正后的代码

#include "mytextedit.h"
#include <QWheelEvent>
#include <QDebug>

MyTextEdit::MyTextEdit(QWidget *parent) : QTextEdit(parent)
{
    // 初始化成员变量
    ctrlKeyPressed = false;
}

void MyTextEdit::wheelEvent(QWheelEvent *e)
{
    if (ctrlKeyPressed) {
        if (e->angleDelta().y() > 0) {
            zoomIn();
        } else if (e->angleDelta().y() < 0) {
            zoomOut();
        }
        e->accept();  // 标记事件已被处理
    } else {
        QTextEdit::wheelEvent(e);  // 默认处理滚轮事件
    }
}

void MyTextEdit::keyPressEvent(QKeyEvent *e)
{
    if (e->key() == Qt::Key_Control) {
        ctrlKeyPressed = true;
    }
    QTextEdit::keyPressEvent(e);  // 继续处理其他按键事件
}

void MyTextEdit::keyReleaseEvent(QKeyEvent *e)
{
    if (e->key() == Qt::Key_Control) {
        ctrlKeyPressed = false;
    }
    QTextEdit::keyReleaseEvent(e);  // 继续处理其他按键释放事件
}

功能总结

  • wheelEvent():当用户滚动鼠标滚轮时,如果同时按住了 Ctrl 键,则会触发文本缩放操作。
  • keyPressEvent():当用户按下键盘上的某个键时,如果该键是 Ctrl 键,则设置 ctrlKeyPressed 为 true
  • keyReleaseEvent():当用户释放键盘上的某个键时,如果该键是 Ctrl 键,则设置 ctrlKeyPressed 为 false

这样就实现了一个简单的功能:当用户按住 Ctrl 键并滚动鼠标滚轮时,可以放大或缩小文本编辑器中的字体大小。

#include "widget.h"
#include "ui_widget.h"
#include <QFile>
#include <QFileDialog>
#include <qfiledialog.h>
#include<QDebug>
#include <QMessageBox>
#include <QShortcut>
#include <QWheelEvent>

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
//    ui->textEdit->installEventFilter(this);
    QShortcut *shortcutOpen = new QShortcut(QKeySequence(tr("Ctrl+O", "File|Open")),this);
    QShortcut *shortcutSave = new QShortcut(QKeySequence(tr("Ctrl+S", "File|Save")),this);
    QShortcut *shortcutZoomIn = new QShortcut(QKeySequence(tr("Ctrl+Shift++", "File|Save")),this);
    QShortcut *shortcutZoomOut = new QShortcut(QKeySequence(tr("Ctrl+Shift+-", "File|Save")),this);

    connect(shortcutOpen, &QShortcut::activated, [=](){
        on_btnFileOpen_clicked();
    });

    connect(shortcutSave, &QShortcut::activated, [=](){
        on_btnFileSave_clicked();
    });

    connect(shortcutZoomIn, &QShortcut::activated, [=](){
        zoomIn();
    });
    connect(shortcutZoomOut, &QShortcut::activated, [=](){
        zoomOut();
    });

    //虽然上面一行代码进行widget和ui的窗口关联,但是如果发生窗口大小变化的时候,里面的布局不会随之变化
    //通过下面这行代码进行显示说明,让窗口变化时,布局及其子控件随之调整
    this->setLayout(ui->verticalLayout);
    ui->widgetButton->setLayout(ui->horizontalLayout);
    connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(oncurrentIndexChanged(int)));
    connect(ui->textEdit, SIGNAL(cursorPositionChanged()), this, SLOT(oncursorPositionChanged()));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::zoomIn()
{
    //获得TextEdit的当前字体信息
    QFont font = ui->textEdit->font();
    //获得当前字体大小
    int fontSize = font.pointSize();
    if(fontSize == -1) return;

    //改变大小,设置当前字体大小
    int newFontSize = fontSize + 1;
    font.setPointSize(newFontSize);
    ui->textEdit->setFont(font);
}

void Widget::zoomOut()
{
    //获得TextEdit的当前字体信息
    QFont font = ui->textEdit->font();
    //获得当前字体大小
    int fontSize = font.pointSize();
    if(fontSize == -1) return;

    //改变大小,设置当前字体大小
    int newFontSize = fontSize - 1;
    font.setPointSize(newFontSize);
    ui->textEdit->setFont(font);
}

//bool Widget::eventFilter(QObject *watched, QEvent *event)
//{

////    QKeyEvent *keyEvent = (QKeyEvent*) event;

////    if(keyEvent->key() == Qt::Key_Control){
////        qDebug() << "ctrl";
////    }

//    if(event->type() == QEvent::Wheel){
//        if(QGuiApplication::keyboardModifiers() == Qt::ControlModifier){
////            qDebug() << "ctrl + wheel";
//            QWheelEvent *wheelEvent = dynamic_cast<QWheelEvent*>(event);
//            if(wheelEvent->angleDelta().y() > 0){
//                zoomIn();
//            }else if(wheelEvent->angleDelta().y() < 0){
//                zoomOut();
//            }
//            return true;
//        }
//        return false;
//    }
//}


void Widget::on_btnFileOpen_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("open File"),
                                                    "E:/QT/", tr("Text(*.txt)"));
    ui->textEdit->clear();

    file.setFileName(fileName);
    if(!file.open(QIODevice::ReadWrite | QIODevice::Text)){
        qDebug() << "file open error";
    }
    this->setWindowTitle(fileName + "-课程作业");
    QTextStream in(&file);
    //    in.setCodec("UTF-8");
    //QString context = in.read(file.size());
    QString str = ui->comboBox->currentText();
    const char *c_str = str.toStdString().c_str();
    in.setCodec(c_str);
    while(!in.atEnd()){
        QString context = in.readLine();
        //        ui->textEdit->setText(context);
        ui->textEdit->append(context);
        //        qDebug() << "---------";
    }
    //    file.close();
}


void Widget::on_btnFileSave_clicked()
{
    if(!file.isOpen()){
        QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
                                                        "E:/QT/untitled.txt",
                                                        tr("Text (*.txt *.doc)"));
        file.setFileName(fileName);
        if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
            qDebug() << "file open error";
        }
        this->setWindowTitle(fileName + "-课程作业");

    }
    QTextStream out(&file);
    out.setCodec(ui->comboBox->currentText().toStdString().c_str());
    QString context = ui->textEdit->toPlainText();
    out << context;
    //    file.close();


}


void Widget::on_btnFileClose_clicked()
{
    QMessageBox msgBox;
    int ret = QMessageBox::warning(this, tr("课程作业退出提示"),
                                   tr("文档已被修改。\n"
                                      "是否要保存更改?"),
                                   QMessageBox::Save | QMessageBox::Discard
                                   | QMessageBox::Cancel,
                                   QMessageBox::Save);
    switch (ret) {
    case QMessageBox::Save:
        // Save was clicked
        on_btnFileSave_clicked();
        break;
    case QMessageBox::Discard:
        // Don't Save was clicked
        ui->textEdit->clear();
        if(file.isOpen()){
            file.close();
            this->setWindowTitle("课程作业");
        }
        break;
    case QMessageBox::Cancel:
        // Cancel was clicked
        break;
    default:
        // should never be reached
        break;
    }

    //    qDebug() << file.isOpen();
}

void Widget::oncurrentIndexChanged(int index) {

    ui->textEdit->clear();
    if(file.isOpen()){
        QTextStream in(&file);
        in.setCodec(ui->comboBox->currentText().toStdString().c_str());
        file.seek(0);
        while(!in.atEnd()){
            QString context = in.readLine();
            //        ui->textEdit->setText(context);
            ui->textEdit->append(context);
            //        qDebug() << "---------";
        }
        //    file.close();
    }


}

void Widget::oncursorPositionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();
    //qDebug() << cursor.blockNumber() + 1 << ", "<< cursor.columnNumber() + 1;
    QString blockNum = QString::number(cursor.blockNumber() + 1);
    QString columnNumber = QString::number(cursor.columnNumber() + 1);
    const QString labelMes = "列:" + blockNum + ", 行:" + columnNumber;
    ui->labelPosition->setText(labelMes);

    //    设置当前行高亮
    QList<QTextEdit::ExtraSelection> extraSelections;
    QTextEdit::ExtraSelection ext;

    //    1,知道当前行
    ext.cursor = ui->textEdit->textCursor();
    QBrush qBrush(Qt::yellow);

    //    2,颜色
    ext.format.setBackground(qBrush);
    //   配置段属性:整行显示,没有这句话不行
    ext.format.setProperty(QTextFormat::FullWidthSelection, true);

    //    3,设置
    //把ext加到ext的容器中
    extraSelections.append(ext);
    ui->textEdit->setExtraSelections(extraSelections);
}

你提供的这段代码是 widget.cpp 文件,这是 Qt 项目中主窗口类 Widget 的实现文件。它实现了你定义的主界面功能,包括:

  • 快捷键绑定
  • 文件打开/保存/关闭
  • 字体缩放(Ctrl + 滚轮 或 快捷键)
  • 编码切换
  • 光标位置显示与当前行高亮
  • 事件过滤器(被注释掉了)

🧱 一、构造函数:初始化界面和快捷键

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);
  • 使用 Qt Designer 设计的 .ui 文件初始化 UI;
  • 创建 UI 对象树并布局;

✅ 添加快捷键支持

QShortcut *shortcutOpen = new QShortcut(QKeySequence(tr("Ctrl+O", "File|Open")), this);
QShortcut *shortcutSave = new QShortcut(QKeySequence(tr("Ctrl+S", "File|Save")), this);
QShortcut *shortcutZoomIn = new QShortcut(QKeySequence(tr("Ctrl+Shift++", "File|Save")), this);
QShortcut *shortcutZoomOut = new QShortcut(QKeySequence(tr("Ctrl+Shift+-", "File|Save")), this);
  • 创建了四个快捷键对象:
    • Ctrl+O:打开文件
    • Ctrl+S:保存文件
    • Ctrl+Shift++:放大字体
    • Ctrl+Shift+-:缩小字体

⚠️ 注意:Qt 中 QKeySequence 对“加号”和“减号”的识别方式可能不一致,建议使用 QKeySequence::ZoomInQKeySequence::ZoomOut 更可靠。

✅ 绑定快捷键触发信号到槽函数

connect(shortcutOpen, &QShortcut::activated, [=](){
    on_btnFileOpen_clicked();
});

connect(shortcutSave, &QShortcut::activated, [=](){
    on_btnFileSave_clicked();
});

connect(shortcutZoomIn, &QShortcut::activated, [=](){
    zoomIn();
});
connect(shortcutZoomOut, &QShortcut::activated, [=](){
    zoomOut();
});
  • 当用户按下快捷键时,会调用对应的按钮点击或缩放函数。

✅ 设置布局(确保控件随窗口变化)

this->setLayout(ui->verticalLayout);
ui->widgetButton->setLayout(ui->horizontalLayout);
  • 显式设置主窗口的布局为 verticalLayout,让控件能随窗口大小自适应;
  • 同样设置了按钮区域的水平布局;

✅ 信号与槽连接

connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(oncurrentIndexChanged(int)));
connect(ui->textEdit, SIGNAL(cursorPositionChanged()), this, SLOT(oncursorPositionChanged()));
  • 下拉框改变 → 重新加载文件内容(按编码)
  • 光标位置改变 → 更新状态栏信息、高亮当前行

📦 二、缩放函数实现

🔍 放大字体

void Widget::zoomIn()
{
    QFont font = ui->textEdit->font();
    int fontSize = font.pointSize();
    if(fontSize == -1) return;

    int newFontSize = fontSize + 1;
    font.setPointSize(newFontSize);
    ui->textEdit->setFont(font);
}
  • 获取当前字体;
  • 如果字体大小无效则返回;
  • 增大字号后重新设置;

🔍 缩小字体

void Widget::zoomOut()
{
    QFont font = ui->textEdit->font();
    int fontSize = font.pointSize();
    if(fontSize == -1) return;

    int newFontSize = fontSize - 1;
    font.setPointSize(newFontSize);
    ui->textEdit->setFont(font);
}
  • 类似逻辑,但字号减少;

📁 三、文件操作功能实现

✅ 打开文件

void Widget::on_btnFileOpen_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("open File"),
                                                    "E:/QT/", tr("Text(*.txt)"));
    ui->textEdit->clear();

    file.setFileName(fileName);
    if(!file.open(QIODevice::ReadWrite | QIODevice::Text)){
        qDebug() << "file open error";
    }
    this->setWindowTitle(fileName + "-课程作业");

    QTextStream in(&file);
    in.setCodec(ui->comboBox->currentText().toStdString().c_str());
    while(!in.atEnd()){
        QString context = in.readLine();
        ui->textEdit->append(context);
    }
}
  • 弹出文件选择对话框;
  • 清空文本编辑区;
  • 设置文件名并尝试打开;
  • 读取文件内容并逐行显示在 textEdit 中;
  • 标题栏显示文件名;

✅ 保存文件

void Widget::on_btnFileSave_clicked()
{
    if(!file.isOpen()){
        QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
                                                        "E:/QT/untitled.txt",
                                                        tr("Text (*.txt *.doc)"));
        file.setFileName(fileName);
        if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){
            qDebug() << "file open error";
        }
        this->setWindowTitle(fileName + "-课程作业");
    }

    QTextStream out(&file);
    out.setCodec(ui->comboBox->currentText().toStdString().c_str());
    QString context = ui->textEdit->toPlainText();
    out << context;
}
  • 如果文件未打开,则弹出保存路径对话框;
  • 写入文本内容到文件;
  • 支持编码格式写入(如 UTF-8、GBK 等);

✅ 关闭文件(带提示)

void Widget::on_btnFileClose_clicked()
{
    QMessageBox msgBox;
    int ret = QMessageBox::warning(this, tr("课程作业退出提示"),
                                   tr("文档已被修改。\n是否要保存更改?"),
                                   QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
                                   QMessageBox::Save);

    switch (ret) {
    case QMessageBox::Save:
        on_btnFileSave_clicked();
        break;
    case QMessageBox::Discard:
        ui->textEdit->clear();
        if(file.isOpen()) {
            file.close();
            this->setWindowTitle("课程作业");
        }
        break;
    case QMessageBox::Cancel:
        break;
    }
}
  • 弹出确认消息框;
  • 用户可以选择保存、放弃更改或取消操作;
  • 若选择放弃,则清空文本并关闭文件;

🧰 四、下拉框编码切换响应

void Widget::oncurrentIndexChanged(int index)
{
    ui->textEdit->clear();
    if(file.isOpen()){
        QTextStream in(&file);
        in.setCodec(ui->comboBox->currentText().toStdString().c_str());
        file.seek(0); // 将文件指针移到开头
        while(!in.atEnd()){
            QString context = in.readLine();
            ui->textEdit->append(context);
        }
    }
}
  • 当编码格式发生变化时,重新以新编码读取文件内容;
  • 使用 seek(0) 保证从头开始读取;

👁‍🗨 五、光标位置变化处理(状态栏显示 + 行高亮)

void Widget::oncursorPositionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();
    QString blockNum = QString::number(cursor.blockNumber() + 1);
    QString columnNumber = QString::number(cursor.columnNumber() + 1);
    const QString labelMes = "列:" + blockNum + ", 行:" + columnNumber;
    ui->labelPosition->setText(labelMes);

    QList<QTextEdit::ExtraSelection> extraSelections;
    QTextEdit::ExtraSelection ext;

    ext.cursor = ui->textEdit->textCursor();
    QBrush qBrush(Qt::yellow);
    ext.format.setBackground(qBrush);
    ext.format.setProperty(QTextFormat::FullWidthSelection, true);

    extraSelections.append(ext);
    ui->textEdit->setExtraSelections(extraSelections);
}
  • 显示当前光标所在的行号和列号;
  • 高亮当前行(黄色背景);
  • 使用 ExtraSelection 实现行高亮效果;

🧼 六、优化建议与注意事项

✅ 修复潜在问题

  1. 文件未关闭:在 on_btnFileOpen_clicked()on_btnFileSave_clicked() 中打开文件后没有 close(),可能导致资源泄漏。

    if(file.isOpen()) file.close(); // 在打开前先关闭旧文件
  2. 重复打开文件:应避免多次打开同一个文件导致错误。

  3. 编码选择框为空的情况:应在界面上默认设置一个编码,如 UTF-8。

  4. 文件未保存就退出:可以添加 QSignalMapper 监听窗口关闭事件,弹出保存提示。

  5. 快捷键不够标准:推荐使用 Qt 自带的快捷键命名方式,例如:

    QKeySequence::Open
    QKeySequence::Save
    QKeySequence::ZoomIn
    QKeySequence::ZoomOut

📌 七、总结

功能模块描述
快捷键绑定Ctrl+O、Ctrl+S、Ctrl+Shift++/- 实现常用操作
文件操作支持打开、保存、关闭文件,并自动识别编码
字体缩放可通过快捷键或滚轮实现放大/缩小
编码切换支持多种编码格式查看与保存
状态栏显示实时显示光标位置
当前行高亮使用 ExtraSelection 实现视觉反馈

如果你希望我帮你:

  • 完善 Ctrl + 滚轮缩放功能(解除注释 eventFilter)
  • 添加撤销/重做功能
  • 添加查找替换功能
  • 支持多语言界面(国际化) 欢迎继续提问 😊
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>课程作业</string>
  </property>
  <property name="windowIcon">
   <iconset resource="res.qrc">
    <normaloff>:/icon/note.png</normaloff>:/icon/note.png</iconset>
  </property>
  <widget class="QWidget" name="layoutWidget">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>801</width>
     <height>601</height>
    </rect>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <property name="spacing">
     <number>0</number>
    </property>
    <item>
     <widget class="QWidget" name="widgetButtons" native="true">
      <property name="minimumSize">
       <size>
        <width>0</width>
        <height>60</height>
       </size>
      </property>
      <property name="styleSheet">
       <string notr="true">background-color: rgb(70, 70, 70);</string>
      </property>
      <widget class="QWidget" name="layoutWidget">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>1</y>
         <width>561</width>
         <height>61</height>
        </rect>
       </property>
       <layout class="QHBoxLayout" name="hlLayoutButtons">
        <item>
         <widget class="QPushButton" name="btnFileOpen">
          <property name="minimumSize">
           <size>
            <width>45</width>
            <height>45</height>
           </size>
          </property>
          <property name="styleSheet">
           <string notr="true"> QPushButton {border-image: url(:/icon/o1.png);}
 QPushButton:hover { border-image: url(:/icon/o2.png); }
 QPushButton:pressed { border-image: url(:/icon/o3.png); }

</string>
          </property>
          <property name="text">
           <string/>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QPushButton" name="btnFileSave">
          <property name="minimumSize">
           <size>
            <width>45</width>
            <height>48</height>
           </size>
          </property>
          <property name="styleSheet">
           <string notr="true"> QPushButton {border-image: url(:/icon/s1.png);}
 QPushButton:hover { border-image: url(:/icon/s2.png); }
 QPushButton:pressed { border-image: url(:/icon/s3.png); }</string>
          </property>
          <property name="text">
           <string/>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QPushButton" name="btnFileClose">
          <property name="minimumSize">
           <size>
            <width>45</width>
            <height>45</height>
           </size>
          </property>
          <property name="styleSheet">
           <string notr="true"> QPushButton {border-image: url(:/icon/c1.png);}
 QPushButton:hover { border-image: url(:/icon/c2.png); }
 QPushButton:pressed { border-image: url(:/icon/c3.png); }</string>
          </property>
          <property name="text">
           <string/>
          </property>
         </widget>
        </item>
        <item>
         <spacer name="horizontalSpacer">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
       </layout>
      </widget>
     </widget>
    </item>
    <item>
     <widget class="MyTextEdit" name="textEdit">
      <property name="minimumSize">
       <size>
        <width>45</width>
        <height>45</height>
       </size>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QWidget" name="widgetButton" native="true">
      <property name="minimumSize">
       <size>
        <width>0</width>
        <height>35</height>
       </size>
      </property>
      <property name="sizeIncrement">
       <size>
        <width>0</width>
        <height>0</height>
       </size>
      </property>
      <property name="styleSheet">
       <string notr="true">background-color: rgb(70, 70, 70);</string>
      </property>
      <widget class="QWidget" name="layoutWidget">
       <property name="geometry">
        <rect>
         <x>-1</x>
         <y>1</y>
         <width>791</width>
         <height>31</height>
        </rect>
       </property>
       <layout class="QHBoxLayout" name="horizontalLayout">
        <item>
         <spacer name="horizontalSpacer_2">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
        <item>
         <widget class="QLabel" name="labelPosition">
          <property name="text">
           <string/>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QComboBox" name="comboBox">
          <property name="minimumSize">
           <size>
            <width>130</width>
            <height>0</height>
           </size>
          </property>
          <item>
           <property name="text">
            <string>UTF-8</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>UTF-16</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>GBK</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>ANSI</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>GB2312</string>
           </property>
          </item>
         </widget>
        </item>
        <item>
         <spacer name="horizontalSpacer_3">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeType">
           <enum>QSizePolicy::Fixed</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
       </layout>
      </widget>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <customwidgets>
  <customwidget>
   <class>MyTextEdit</class>
   <extends>QTextEdit</extends>
   <header location="global">mytextedit.h</header>
  </customwidget>
 </customwidgets>
 <resources>
  <include location="res.qrc"/>
 </resources>
 <connections/>
</ui>

你提供的这段 XML 文件是 Qt 的 .ui 文件,它是由 Qt Designer 生成的 用户界面描述文件,用于定义 Widget 类中的界面布局、控件属性和结构。


🧾 概述

这个 .ui 文件定义了一个名为 Widget 的主窗口,包含以下主要组件:

组件功能
btnFileOpenbtnFileSavebtnFileClose文件操作按钮(打开、保存、关闭)
textEdit自定义文本编辑区域(使用了自定义类 MyTextEdit
comboBox编码格式选择框(支持 UTF-8、UTF-16、GBK、ANSI、GB2312 等)
labelPosition显示光标位置信息(如:行: x, 列: y)
快捷键功能Ctrl+O 打开,Ctrl+S 保存,Ctrl+Shift++/- 放大/缩小字体

🧱 结构解析

1. 基本窗口设置

<property name="geometry">
    <rect>
        <x>0</x>
        <y>0</y>
        <width>800</width>
        <height>600</height>
    </rect>
</property>
<property name="windowTitle">
    <string>课程作业</string>
</property>
<property name="windowIcon">
    <iconset resource="res.qrc">
        <normaloff>:/icon/note.png</normaloff>:/icon/note.png
    </iconset>
</property>
  • 设置窗口大小为 800x600;
  • 标题为 “课程作业”;
  • 使用资源文件 res.qrc 中的图标 note.png

2. 整体布局结构

使用了垂直布局 QVBoxLayout,从上到下依次排列:

  1. 工具栏(含三个按钮)
  2. 文本编辑区(使用自定义控件 MyTextEdit
  3. 底部状态栏(含编码选择框 + 光标位置标签)
🔘 工具栏部分
  • 包含三个按钮:
    • btnFileOpen
    • btnFileSave
    • btnFileClose
  • 使用了样式表实现按钮的图片切换效果(正常、悬停、按下状态不同图片);
  • 图片来自资源文件 res.qrc
  • 布局方式为 QHBoxLayout
🔘 文本编辑区
<widget class="MyTextEdit" name="textEdit">
  • 使用了你自定义的 MyTextEdit 控件;
  • 支持滚轮缩放、快捷键放大缩小等特性;
  • 在代码中通过 ui->textEdit 访问;
🔘 状态栏部分
  • 包含:
    • labelPosition:显示光标所在行列;
    • comboBox:选择文件编码;
  • 同样使用水平布局 QHBoxLayout

⚙️ 自定义控件声明

<customwidgets>
  <customwidget>
   <class>MyTextEdit</class>
   <extends>QTextEdit</extends>
   <header location="global">mytextedit.h</header>
  </customwidget>
</customwidgets>
  • 声明了 MyTextEdit 是一个自定义控件;
  • 继承自 QTextEdit
  • 头文件路径为 mytextedit.h
  • Qt Creator 会据此识别该控件并允许你在设计器中使用;

🎨 资源引用

<resources>
  <include location="res.qrc"/>
</resources>
  • 引用了资源文件 res.qrc,里面应包含所有用到的图标资源;
  • 示例内容如下(.qrc 文件示例):
<RCC>
    <qresource prefix="/">
        <file>icon/o1.png</file>
        <file>icon/o2.png</file>
        <file>icon/o3.png</file>
        ...
        <file>icon/note.png</file>
    </qresource>
</RCC>

💡 优化建议与注意事项

✅ 修复潜在问题

  1. 按钮点击反馈不明显?

    • 可以在样式表中增加一些过渡动画或背景色变化;
    • 或者使用 QIcon::fromTheme() 实现系统图标风格适配;
  2. 资源路径是否正确?

    • 确保项目目录下存在 res.qrc 文件,并且图标路径正确;
    • 如果运行时图标未显示,请检查 .pro 文件中是否添加了:
       qmake 

      深色版本

      RESOURCES += res.qrc
  3. 布局拉伸问题?

    • 当前工具栏和底部状态栏高度固定,可考虑使用 QSizePolicy::Minimum 或 Expanding 来让其更自然地适应窗口大小变化;
  4. 编码选择框默认值?

    • 可以在构造函数中手动设置默认选中项:
      ui->comboBox->setCurrentIndex(0); // 默认 UTF-8
  5. 窗口大小不能调整?

    • 如果你希望窗口可以自由缩放,请确保没有设置固定大小:
      setFixedSize(800, 600); // 如果有这句,就删除

🧩 总结

部分内容
主窗口QWidget,标题“课程作业”,图标 note.png
布局QVBoxLayout + QHBoxLayout 组合
控件按钮、文本编辑器、编码下拉框、光标位置标签
自定义控件MyTextEdit(继承 QTextEdit)
资源管理使用 res.qrc 存放图标资源
快捷键在代码中绑定(Ctrl+O/S/+/-)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小范好好学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值