项目地址:
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 开发的核心模块,提供QWidget
、QPushButton
、QLabel
等控件;- 在 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() | 文本光标位置发生改变 |
⚠️ 注意:
oncurrentIndexChanged
和oncursorPositionChanged
这两个函数名称不是自动匹配的,需要手动连接信号和槽。
✅ 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()
函数的返回值,通常用来指示应用程序的退出状态。
功能概述
这段代码的功能可以概括为:
- 初始化应用程序:通过创建
QApplication
对象来设置应用程序环境。 - 创建主窗口:实例化
Widget
类,这通常是你的主界面。 - 显示主窗口:调用
show()
方法将窗口显示出来。 - 运行事件循环:调用
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::ZoomIn
和QKeySequence::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
实现行高亮效果;
🧼 六、优化建议与注意事项
✅ 修复潜在问题
-
文件未关闭:在
on_btnFileOpen_clicked()
和on_btnFileSave_clicked()
中打开文件后没有close()
,可能导致资源泄漏。if(file.isOpen()) file.close(); // 在打开前先关闭旧文件
-
重复打开文件:应避免多次打开同一个文件导致错误。
-
编码选择框为空的情况:应在界面上默认设置一个编码,如 UTF-8。
-
文件未保存就退出:可以添加
QSignalMapper
监听窗口关闭事件,弹出保存提示。 -
快捷键不够标准:推荐使用 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
的主窗口,包含以下主要组件:
组件 | 功能 |
---|---|
btnFileOpen , btnFileSave , btnFileClose | 文件操作按钮(打开、保存、关闭) |
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
,从上到下依次排列:
- 工具栏(含三个按钮)
- 文本编辑区(使用自定义控件
MyTextEdit
) - 底部状态栏(含编码选择框 + 光标位置标签)
🔘 工具栏部分
- 包含三个按钮:
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>
💡 优化建议与注意事项
✅ 修复潜在问题
-
按钮点击反馈不明显?
- 可以在样式表中增加一些过渡动画或背景色变化;
- 或者使用
QIcon::fromTheme()
实现系统图标风格适配;
-
资源路径是否正确?
- 确保项目目录下存在
res.qrc
文件,并且图标路径正确; - 如果运行时图标未显示,请检查
.pro
文件中是否添加了:深色版本
RESOURCES += res.qrc
- 确保项目目录下存在
-
布局拉伸问题?
- 当前工具栏和底部状态栏高度固定,可考虑使用
QSizePolicy::Minimum
或Expanding
来让其更自然地适应窗口大小变化;
- 当前工具栏和底部状态栏高度固定,可考虑使用
-
编码选择框默认值?
- 可以在构造函数中手动设置默认选中项:
ui->comboBox->setCurrentIndex(0); // 默认 UTF-8
- 可以在构造函数中手动设置默认选中项:
-
窗口大小不能调整?
- 如果你希望窗口可以自由缩放,请确保没有设置固定大小:
setFixedSize(800, 600); // 如果有这句,就删除
- 如果你希望窗口可以自由缩放,请确保没有设置固定大小:
🧩 总结
部分 | 内容 |
---|---|
主窗口 | QWidget ,标题“课程作业”,图标 note.png |
布局 | QVBoxLayout + QHBoxLayout 组合 |
控件 | 按钮、文本编辑器、编码下拉框、光标位置标签 |
自定义控件 | MyTextEdit (继承 QTextEdit) |
资源管理 | 使用 res.qrc 存放图标资源 |
快捷键 | 在代码中绑定(Ctrl+O/S/+/-) |