这是我学习 C++ 后,尝试使用 Qt 开发桌面应用的练习项目。在入门阶段参考了 B 站「社长_嵌入式」的 Qt 教程视频,收获很多。
本文是我在编码过程中对知识点、功能实现与问题解决的总结,目的是为了 ​​记录学习过程,方便以后回顾​​。
项目代码是我边学边写的,​​可能包含一些 BUG 或不够完善的地方​​,如果您在调试时发现问题,可以尝试自行修改,也欢迎提出建议,共同进步!
github链接:https://github.com/houshiyuan3-eng/MyQtProject

天气预报小案例总结

在这里插入图片描述

1 控制label组件的边框:

​ border-radius

2 QT在网络上获取Json数据的步骤:

  • QNetworkAccessManager *manger = new QNetworkAccessManager (this)//网络接口管理者

  • QNetWorkRequest req(QUrl(Qstring(网址)))

  • connect(manger,&QNetworkAccessManager::finished,this,&Widget::readHttpReply);//监听函数

  • 判断是否接受成功 (QNetworkReply *reply)

    int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

    if(reply->error() == QNetworkReply::NoError&&code==200)
    表示success;

    QByteArray data = reply->readAll();//接收数据

  • 接受数据后转换为需要的数据:

QJsonDocument jsonObj = QJsonDocument::fromJson(dataJson);//获取数据

返回的内容有多重类型,根据类型判断接受的格式,要注意如何遍历:

​ 例如:QJsonArray QJsonObject

​ 循环遍历时候数据的类型用QJsonValue 表示

3 添加简单的弹窗事件简易版:

QMenu *menuQuit =new QMenu(this);
QAction *action =new QAction(QIcon(":/tuichu.png"),tr("退出"),this);
menuQuit->addAction(action);
connect(menuQuit,&QMenu::triggered,this,[=]{
    this->close();
});

4 窗口不显示上边的调节部分:

​ setWindowFlag(Qt::FramelessWindowHint)

5 固定窗口的大小:

​ setFixedSize(a,b);

6 自定义鼠标点击事件:

void mousePressEvent(QMouseEvent *event);
void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton){
        qDebug()<<"left button";
        offend = event->globalPos()-this->pos();
      	//event->globalPos()相当于整个桌面坐标,this->pos()相对于窗口的坐标
    }
    if(event->button()==Qt::RightButton){
        menuQuit->exec(QCursor::pos());
    }
}

7 鼠标移动事件:使鼠标可以拖动窗口

void mouseMoveEvent(QMouseEvent *event) override;
void Widget::mouseMoveEvent(QMouseEvent *event)
{
    this->move(event->globalPos()-offend);
}

8 显示某个组件的坐标

ui->label.x();//显示X的坐标 
ui->label.width();//组件宽度

9 事件过滤器

    bool eventFilter(QObject *watcher,QEvent *event);//都文件中重写时间过滤器函数
    ui->widget_hightemp->installEventFilter(this);
    ui->widget_lowtemp->installEventFilter(this);//给对应组件添加监听事件
    bool Widget::eventFilter(QObject *watcher, QEvent *event)
        {
            if (watcher == ui->widget_hightemp && event->type() == QEvent::Paint) {
                drawHighTempLine();
                return true;
            }

            if (watcher == ui->widget_lowtemp && event->type() == QEvent::Paint) {
                drawLowTempLine();
                return true;
            }

            return QWidget::eventFilter(watcher, event); // 其他情况交回父类处理
        }

车辆仪表盘案例总结

在这里插入图片描述

1paintEvent 触发时机

触发情况 是否自动触发 说明
窗口首次显示(show() 后) ✅ 自动 首次绘制界面
窗口从被遮挡变为可见(如最小化恢复) ✅ 自动 重新绘制暴露的部分
调用 update() ✅ 异步自动 请求重绘,推荐使用
调用 repaint() ✅ 同步立即 立即重绘,少用为妙
窗口大小改变(resize) ⚠️ 可能自动 通常伴随 resizeEvent,可能触发 paintEvent
手动指定区域更新(如 update(QRect)) ✅ 异步自动 只更新指定区域
系统或 Qt 认为需要重绘某个区域 ✅ 自动 比如部分失效等

2 在某位置插入图片

QPainter painter(this);
painter.drawPixmap(rect,QPixmap(":/icon/CarLogo.png"));

3 渐变色设置步骤

	QRadialGradient RGradient(0,0,radical-30);//调用不同渐变色方法,设置不同的形状
	RGradient.setColorAt(1,QColor(255,0,0,200));//设置颜色变化比例
    // RGradient.setColorAt(0.98,QColor(255,0,0,120));
    RGradient.setColorAt(0.9,QColor(255,0,0,100));
    RGradient.setColorAt(0.8,QColor(0,0,0,100));
    RGradient.setColorAt(0.0,QColor(0,0,0,0));
    painter.setBrush(RGradient);
    painter.setPen(Qt::NoPen);
    painter.drawPie(QRect(-radical+12,-radical+12,radical*2-30,radical*2-30),-150*16,-60*(240*1.0/60)*16);//在指定部分画

4 绘制自定义形状

    painter.setBrush(QBrush(Qt::white));
    static const QPointF points[4] = {
        QPointF(0,1),
        QPointF(150.0,0),
        QPointF(150.0,1),
        QPointF(0,10)
    };
    // painter.drawLine(50,0,radical-50,0);
    painter.drawPolygon(points,4);

5 字体设置

    QFont font("华文宋体",30);
    font.setBold(true);
    painter.setFont(font);

Qt网络通信助手总结

在这里插入图片描述

1 实现的功能

该程序实现了一个 基于 TCP 协议的简易聊天/通信系统,支持:

服务端功能:

  • 监听指定的 IP 和端口
  • 接收多个客户端的连接
  • 显示客户端的连接、断开信息
  • 接收来自客户端的数据并显示
  • 向单个客户端或所有客户端发送消息
  • 管理客户端连接(如断开、端口选择等)

客户端功能:

  • 连接到指定的服务器 IP 和端口
  • 发送消息到服务器
  • 接收并显示来自服务器的消息
  • 处理连接状态(成功、失败、超时等)
  • 断开连接

2 使用的 Qt 模块与核心类

Qt 模块 核心类 / 功能 用途说明
Core QObject, QWidget, qDebug, QString, etc. 基础对象、字符串处理、调试输出等
Gui QWidget, QTextEdit, QLineEdit, QPushButton, etc. 用户界面组件
Network QTcpServer, QTcpSocket, QHostAddress, QAbstractSocket, QNetworkInterface TCP 通信相关类
Widgets QWidget, QVBoxLayout, QMessageBox, etc. 图形界面控件与布局

3 网络通信相关类与功能

3.1QTcpServer —— TCP 服务端

主要功能:监听指定的 IP 和端口,接受客户端连接,管理多个客户端连接

关键函数与信号:​

  • server->listen(QHostAddress, quint16 port):开始监听
  • server->hasPendingConnections():是否有等待接受的连接
  • server->nextPendingConnection():接受一个新连接,返回 QTcpSocket*
  • 信号:newConnection():当有新客户端连接时触发

代码示例:

server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()), this, SLOT(on_newClient_Connnect()));
...
if(!server->listen(QHostAddress(ip), port)) { ... }
3.2 QTcpSocket —— TCP 客户端通信套接字

主要功能:用于与服务端建立的连接,进行数据的发送

可以使服务端与单个客户端连接的套接字,也可以是客户端用来连接服务器的套接字

关键函数:

  • connectToHost(ip, port):连接到指定的服务器
  • write(data):发送数据(字节数组)
  • readAll():读取所有接收到的数据
  • close():关闭连接

重要信号:

  • readyRead():当有数据可读时触发
  • connected():连接成功时触发
  • disconnected()/ stateChanged():连接状态变化
  • errorOccurred(QAbstractSocket::SocketError):发生错误时触发

代码示例:

client = new QTcpSocket(this);
connect(client, SIGNAL(readyRead()), this, SLOT(mRead_Data_From_Server()));
connect(client, SIGNAL(connected()), this, SLOT(onConnect()));
connect(client, SIGNAL(errorOccurred(...)), this, SLOT(onError(...)));
3.3 QHostAddress & QAbstractSocket
  • QHostAddress:表示 IP 地址,支持 IPv4 / IPv6
  • QAbstractSocket:QTcpSocket 的父类,提供通用的套接字状态和操作

获取本机地址:

//遍历本机所有网络接口地址,筛选出 IPv4 地址供用户选择
QList<QHostAddress> address = QNetworkInterface::allAddresses();
for(QHostAddress tmp : address){
    if(tmp.protocol() == QAbstractSocket::IPv4Protocol){
        ui->comboBox_serverIPAddress->addItem(tmp.toString());
    }
}

4 信号与槽机制(Qt 的核心机制!)

Qt 使用 信号与槽(Signals & Slots) 机制进行对象间的通信,替代传统回调,更加安全和灵活。

信号与槽的基本用法:

connect(sender, SIGNAL(signalName(params...)), receiver, SLOT(slotName(params...)));

或者(推荐使用新式语法,更类型安全):

connect(sender, &SenderClass::signalName, receiver, &ReceiverClass::slotName);

本案例中的信号与槽连接举例:

信号来源 信号 槽函数 作用
QTcpServer newConnection() on_newClient_Connnect() 有新客户端连入
QTcpSocket readyRead() on_readyRead_handler() / mRead_Data_From_Server() 收到数据
QTcpSocket stateChanged() mstateChanged() 套接字状态改变
QTcpSocket errorOccurred() onError() 出现网络错误
QTimer timeout() onTimeOut() 连接超时处理
自定义(或 ComboBox) on_Combox_click Combox_refush() 刷新端口列表(自定义信号)

5 UI 界面与控件交互

5.1 常见控件
  • QTextEdit:用于显示聊天内容 / 日志
  • QLineEdit:输入 IP、端口、消息内容
  • QPushButton:触发连接、发送、停止等操作
  • QComboBox:选择 IP、端口、发送对象等
5.2 布局管理
  • 使用了 QVBoxLayout(垂直布局),通过代码设置:
this->setLayout(ui->verticalLayout);
  • 一般更推荐在 Qt Designer 中直接拖放布局,而不是代码动态设置,除非有特殊需求
5.3 将组件上升至函数
//头文件:
class myCombox : public QComboBox
{
    Q_OBJECT
public:
    myCombox(QWidget *parent);
protected:
    void mousePressEvent(QMouseEvent *e) override;
signals:
    void on_Combox_click();
};
//源文件:
#include "mycombox.h"

#include <QMouseEvent>

myCombox::myCombox(QWidget *parent):QComboBox(parent){

}

void myCombox::mousePressEvent(QMouseEvent *e)
{
    if(e->button()==Qt::LeftButton){
        emit on_Combox_click();
    }
    QComboBox::mousePressEvent(e);
}
//主函数:
connect(ui->comboBox_ChoosePort,&myCombox::on_Combox_click,this,&Widget::Combox_refush);
//调用函数:
void Widget::Combox_refush()
{
    ui->comboBox_ChoosePort->clear();
    qDebug()<<"combox refush";
    QList<QTcpSocket *> tcpclients = server->findChildren<QTcpSocket *>();
  //试图查找当前 server 对象下所有的 QTcpSocket 子对象
    if(tcpclients.size()!=0){
        for(QTcpSocket *tmp :tcpclients){
            ui->comboBox_ChoosePort->addItem(QString::number(tmp->peerPort()));
        }
        ui->comboBox_ChoosePort->addItem("ALL");
    }

}

6 其他零散知识

6.1 字节流处理(数据的发送与接收)
  • 使用 QByteArray作为数据载体
  • write()发送数据
  • readAll()读取数据
  • 注意编码问题,尤其是中文。推荐使用 toUtf8()而非 toStdString().c_str()
6.2 光标显示

通过 QTextCursor控制文本滚动与光标位置,提升用户体验:

ui->textEdit_serverContent->moveCursor(QTextCursor::End);
ui->textEdit_serverContent->ensureCursorVisible();
6.3 消息框提示(QMessageBox)
//用于提示错误,警告等
QMessageBox msgbox;
msgbox.setWindowTitle("监听失败");
msgbox.setText("端口号被占用!");
msgbox.exec();
6.4定时器(QTimer)——用于连接超时

客户端连接时,启动一个 单次定时器 检测是否连接成功,防止一直卡死:

timer = new QTimer(this);
timer->setSingleShot(true);
timer->setInterval(2000);
connect(timer, SIGNAL(timeout()), this, SLOT(onTimeOut()));
timer->start();

7 总结

知识点分类 具体内容
Qt 基础 QWidget、信号槽、构造/析构、UI 加载(setupUi)、布局管理
网络编程 QTcpServer、QTcpSocket、TCP 通信流程、IP 地址处理、端口监听
信号与槽 事件驱动编程、新旧信号槽语法、自定义信号处理
套接字通信 readyRead、connected、disconnected、errorOccurred、stateChanged
UI 交互 按钮、输入框、下拉框、文本框、按钮状态控制
数据收发 QByteArray、write()、readAll()、字符串编码(toUtf8)
日志与提示 QTextEdit、QTextCursor、QMessageBox
定时器 QTimer、超时处理、单次定时
网络工具类 QHostAddress、QNetworkInterface、QAbstractSocket
多客户端管理 nextPendingConnection、findChildren、动态管理套接字列表
代码结构与设计 功能分离、状态管理、模块化思想(可优化点)

基于 Qt 的串口调试助手

在这里插入图片描述

1 核心功能模块

模块 功能描述
1. 串口通信 打开/关闭串口,设置波特率、数据位、校验位、停止位、流控,实现串口数据的收发
2. 数据发送 支持手动发送、自动定时发送、循环批量发送;支持 HEX / 文本格式发送
3. 数据接收 实时接收串口数据并显示,支持 HEX 显示切换,统计收发字节数
4. 数据记录与保存 保存接收/发送历史到文件,支持导出文本内容
5. 快捷按钮控制 通过多个按钮(pushButton_1 ~ pushButton_9)快速填充发送框内容并发送
6. 界面交互优化 包括面板隐藏/展开、时间显示、状态提示、自动滚动、输入框与复选框联动等
7. 参数配置持久化 支持从文件加载/保存输入框和复选框的状态(如一键配置导入导出)
8. 动态控件管理 通过 findChild 动态查找和绑定多个按钮、输入框、复选框,实现可扩展 UI

2 串口通信相关(QSerialPort 核心知识点)

2.1 QSerialPort 类

用于控制电脑上的串口硬件,进行数据的收发

需要设置的参数包括:

  • 端口名称(COM1, /dev/ttyUSB0…)
  • 波特率(BaudRate)
  • 数据位(DataBits)
  • 校验位(Parity)
  • 停止位(StopBits)
  • 流控(FlowControl)
2.2 关键函数
函数 作用
setPortName() 设置串口号
setBaudRate() 设置波特率,如 9600、115200
setDataBits() 数据位,如 8
setParity() 校验位,如 NoParity、EvenParity
setStopBits() 停止位,如 OneStop
setFlowControl() 流控,如 NoFlowControl
open(QIODevice::ReadWrite) 打开串口
close() 关闭串口
write() 发送数据
readAll() 读取所有可用数据
isOpen() 判断是否已打开
2.3信号
信号 说明
readyRead() 当串口有数据到达时触发,用于接收数据

3 UI 界面与控件交互设计

3.1 控件类型
  • 按钮类:QPushButton(发送、清空、保存、打开串口、快捷按钮等)
  • 输入框类:QLineEdit(发送内容、定时发送间隔等)
  • 复选框类:QCheckBox(HEX 发送、自动换行、定时发送开关等)
  • 文本显示区:QTextEdit(历史记录、发送记录)
  • 下拉框类:QComboBox(串口列表、波特率、校验位等)
  • 分组框:QGroupBox(用于组织界面模块,如历史面板、文本面板)
  • 标签类:QLabel(时间显示、状态提示等)
3.2 动态控件查找与绑定

使用了 findChild<T>()动态查找控件,并为多个类似的按钮/输入框/复选框进行了 “批量绑定”

for(int i=1;i<=9;i++){
    QString btnname = QString("pushButton_%1").arg(i);
    QPushButton *btn = findChild<QPushButton *>(btnname);
    ...
    connect(btn, SIGNAL(clicked()), this, SLOT(on_command_btn_clicked()));
}

4 文件操作

  • 保存通信记录 到 txt 文件:on_pushButton_SaveRecord_clicked()
  • 保存输入框/复选框配置on_pushButtonSave_clicked()
  • 加载配置on_pushButtonLoad_clicked()

使用到的类:

  • QFileDialog:弹出文件选择对话框
  • QFile:操作文件(打开、读写、关闭)
  • QTextStream:以文本形式读写文件内容

5 时间显示相关功能

windowtimer = new QTimer(this);
connect(windowtimer, &QTimer::timeout, [=]{
    // 时间显示
    QDateTime currenttime = QDateTime::currentDateTime();
    QDate date = currenttime.date();
    int year = date.year();
    int month = date.month();
    int day = date.day();
    QTime time = currenttime.time();
    int hour = time.hour();
    int minute = time.minute();
    int second = time.second();
    mytime = QString("%1-%2-%3 %4:%5:%6")
                .arg(year, 2, 10, QChar('0'))
                .arg(month, 2, 10, QChar('0'))
                .arg(day, 2, 10, QChar('0'))
                .arg(hour, 2, 10, QChar('0'))
                .arg(minute, 2, 10, QChar('0'))
                .arg(second, 2, 10, QChar('0'));
    ui->label_times->setText(mytime);
});
windowtimer->start(1000);  // 每隔 1000 毫秒(即 1 秒)触发一次 timeout()
5.1 QDateTime / QDate / QTime —— Qt 提供的时间日期类

Qt 提供了一整套非常方便的时间日期处理类

作用
QDateTime 包含日期和时间,可通过 currentDateTime()获取当前系统时间
QDate 只包含日期部分(年、月、日)
QTime 只包含时间部分(时、分、秒)
QDateTime currenttime = QDateTime::currentDateTime();  // 获取当前日期时间
QDate date = currenttime.date();                       // 提取日期部分
QTime time = currenttime.time();                       // 提取时间部分
  • 年:date.year()
  • 月:date.month()
  • 日:date.day()
  • 时:time.hour()
  • 分:time.minute()
  • 秒:time.second()
5.2 QString::arg() —— 格式化字符串(重点!)

使用了 QString::arg()方法,对数字进行 格式化拼接,确保每一位数字都是 两位数,不足的前面补零

mytime = QString("%1-%2-%3 %4:%5:%6")
            .arg(year, 2, 10, QChar('0'))   // 年,占2位,不足补0
            .arg(month, 2, 10, QChar('0'))  // 月
            .arg(day, 2, 10, QChar('0'))    // 日
            .arg(hour, 2, 10, QChar('0'))   // 时
            .arg(minute, 2, 10, QChar('0')) // 分
            .arg(second, 2, 10, QChar('0')); // 秒

参数解释:

QString::arg(value, 最小宽度, 进制, 填充字符)

基于 Qt 的轻量级记事本(Notepad)项目的核心代码

在这里插入图片描述

功能包括:

  • 打开 / 保存 / 关闭文本文件
  • 使用快捷键(Ctrl+O、Ctrl+S、Ctrl+Shift+/-)进行快捷操作
  • 自定义文本编辑区(继承自 QTextEdit,支持 Ctrl+滚轮缩放字体)
  • 显示当前光标所在 行号和列号
  • 关闭窗口时的 确认对话框
  • 文档修改提示与保存提醒
  • 使用 Qt 的信号槽、事件处理、快捷键机制等核心功能

1 功能简介

功能模块 功能描述
1. 文件操作 打开文本文件(支持 .txt)、保存文件、关闭文件并提示保存
2. 编辑区增强 自定义 QTextEdit,支持通过 Ctrl + 鼠标滚轮缩放字体大小
3. 快捷键支持 支持常用的快捷键操作,如:• Ctrl+O:打开文件• Ctrl+S:保存文件• Ctrl+Shift+=:增大字体• Ctrl+Shift±:减小字体
4. 光标位置提示 实时显示当前光标所在的 行号和列号(如:行: 3, 列: 15)
5. 用户交互与安全 关闭窗口时弹出确认对话框,保存前提示,防止误操作丢失内容
6. 界面与布局管理 使用 Qt Designer 布局,并动态设置窗口标题、布局响应等

2 信号与槽机制(核心交互逻辑)

2.1 快捷键触发操作
QShortcut *shortcutopen = new QShortcut(QKeySequence(tr("Ctrl+O")), this);
connect(shortcutopen, &QShortcut::activated, [=]{
    on_btn_open_clicked();
});
  • 使用 QShortcut绑定快捷键(如 Ctrl+O、Ctrl+S)
  • 当用户按下快捷键时,触发对应的槽函数(比如打开文件、保存文件)
2.2 文本编辑区增强功能(MyTextEdit 类)

创建了一个自定义控件类:

class MyTextEdit : public QTextEdit

它继承自 QTextEdit,并 重写了 3 个事件处理函数,用于增强编辑区的功能:

① wheelEvent() —— Ctrl + 滚轮缩放字体

void MyTextEdit::wheelEvent(QWheelEvent *e)
{
    if(onkeypressed){  // 只有按下 Ctrl 时才响应滚轮
        if(e->angleDelta().y() > 0) zoomIn();   // 放大字体
        else zoomOut();                       // 缩小字体
        e->accept();
    } else {
        QTextEdit::wheelEvent(e); // 默认行为
    }
}

功能:

  • 当用户按住 Ctrl 键 + 滚轮向上/向下,字体就会放大或缩小
  • 利用了 zoomIn()zoomOut()这两个 QTextEdit 内置的便捷函数

限制:

  • 只有检测到 Key_Control被按下时(通过 keyPressEvent / keyReleaseEvent 管理),滚轮事件才会触发缩放

keyPressEvent() / keyReleaseEvent() —— 检测 Ctrl 键状态

void MyTextEdit::keyPressEvent(QKeyEvent *e)
{
    if(e->key() == Qt::Key_Control)
        onkeypressed = 1;  // Ctrl 按下
    QTextEdit::keyPressEvent(e);
}

void MyTextEdit::keyReleaseEvent(QKeyEvent *e)
{
    if(e->key() == Qt::Key_Control)
        onkeypressed = 0;  // Ctrl 释放
    QTextEdit::keyReleaseEvent(e);
}
  • 通过记录一个布尔变量 onkeypressed,标识当前是否按下了 Ctrl 键
  • 这个状态被用于控制 滚轮是否触发缩放

3 文件操作

3.1 打开并读取文件内容
void Widget::on_btn_open_clicked()
{
    QString filename= QFileDialog::getOpenFileName(this,tr("Open File"),"D:/QTtest/QT_notebook/notebook",tr("Text(*.txt)"));
    ui->textEdit->clear();

    file.setFileName(filename);
    this->setWindowTitle(filename+"-侯世源的记事本");
    if(!file.open(QIODevice::ReadWrite| QIODevice::Text)){
        qDebug()<<"open file error";
    }

    QTextStream in(&file);
    while(!in.atEnd()){
        QString context =in.readLine();
        ui->textEdit->append(context);
    }
    // file.close();
}
3.2 保存文件
void Widget::on_btn_save_clicked()
{
    if(!file.isOpen()){
        QString filename = QFileDialog::getSaveFileName(this,tr("Open File"),"D:/QTtest/QT_notebook/notebook/untitled.txt",tr("Text(*.txt)"));
        file.setFileName(filename);
        if(!file.open(QIODevice::WriteOnly)|QIODevice::Text){
            qDebug()<<"file open error";
        }
    }
    QTextStream out(&file);
    QString context= ui->textEdit->toPlainText();
    QMessageBox messagebox;
    messagebox.setInformativeText("文件保存成功!");
    messagebox.setStandardButtons(QMessageBox::Ok);
    int ret = messagebox.exec();
    // file.close();
}
3.3 关闭文件逻辑

(1) 关闭按钮逻辑(on_btn_close_clicked)

  • 弹出一个 QMessageBox 询问是否保存、丢弃或取消
  • 支持三种选项,交互非常专业,是记事本类软件的标配

(2)关闭文件事件

void Widget::on_btn_close_clicked()
{
    // qDebug()<<"click";

    QMessageBox msgBox;
    msgBox.setText("The document has been modified.");
    msgBox.setInformativeText("Do you want to save your changes?");
    msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
    msgBox.setDefaultButton(QMessageBox::Save);
    int ret = msgBox.exec();
    switch (ret) {
    case QMessageBox::Save:
        on_btn_save_clicked();
        break;
    case QMessageBox::Discard:
        ui->textEdit->clear();
        if(file.isOpen()){
            file.close();
            ui->textEdit->clear();
            this->setWindowTitle("侯世源的记事本");
        }
        break;
    case QMessageBox::Cancel:
        // Cancel was clicked
        break;
    default:
        // should never be reached
        break;
    }
}

(3) 窗口关闭事件(closeEvent)

void Widget::closeEvent(QCloseEvent *event)
{
    int ret = QMessageBox::warning(this,tr("侯世源的记事本"),tr("Do you want close the window?\n close the window"),QMessageBox::Ok|QMessageBox::No);
    switch (ret) {
    case QMessageBox::Ok:
        event->accept();
        break;
    case QMessageBox::No:
        event->ignore();
    default:
        break;
    }

}

4 光标位置实时显示(行号 / 列号),高亮显示

4.1 显示行号

实现函数:oncursorPositionChanged()

QTextCursor tcur = ui->textEdit->textCursor();
int blockNumber = tcur.blockNumber();  // 当前行号(从0开始)
int columnNumber = tcur.columnNumber(); // 当前列号(从0开始)
ui->labelposition->setText("行: " + QString::number(blockNumber) + " , 列: " + QString::number(columnNumber));
  • 该函数与 textEditcursorPositionChanged()信号连接
  • 每当光标移动时,实时更新一个标签控件(比如叫 labelposition),显示当前光标位于 第几行、第几列
4.2高亮显示选中行
QList<QTextEdit::ExtraSelection> extraSelection;
QTextEdit::ExtraSelection ext;
ext.cursor = ui->textEdit->textCursor();
QBrush qbrush(Qt::lightGray);
ext.format.setBackground(qbrush);
ext.format.setProperty(QTextFormat::FullWidthSelection, true);
extraSelection.append(ext);
ui->textEdit->setExtraSelections(extraSelection);

QTextEdit::ExtraSelection 是什么:

Qt 定义的一个 结构体(或类),用来描述一个“额外的选中区域样式”,包括:

  • 哪一部分文本/区域要高亮(通过 cursor 指定)
  • 这个区域的文本格式(比如背景色、字体颜色等)
  • 是否整行高亮等属性

声明(简化)大致如下:

struct ExtraSelection {
    QTextCursor cursor;           // 高亮区域对应的文本光标位置
    QTextCharFormat format;       // 该区域的文本格式(比如背景色)
};

②代码逐行解析:

(1) 创建一个 ExtraSelection 列表

QList<QTextEdit::ExtraSelection> extraSelection;
  • 这是一个列表,可以存放 多个高亮区域(比如同时高亮多行)
  • 但在这里只高亮 当前光标所在的一行,所以只添加了一个

(2) 创建一个 ExtraSelection 对象

QTextEdit::ExtraSelection ext;

(3) 设置要高亮的区域 —— 当前光标所在行

ext.cursor = ui->textEdit->textCursor();
  • textCursor()返回当前 QTextEdit 中光标的位置
  • 它代表 当前光标所在的行、列
  • 默认情况下,ExtraSelection 会高亮光标所在位置的“字符区域”
  • 但配合下面的属性,我们可以让它高亮 整行

(4) 设置高亮的背景颜色

QBrush qbrush(Qt::lightGray);
ext.format.setBackground(qbrush);
  • QBrush是 Qt 的画刷,用于定义填充颜色
  • Qt::lightGray是浅灰色 —— 你也可以换成别的颜色,比如:Qt::yellow``QColor(200, 200, 255)自定义 RGB / RGBA 值
  • ext.format.setBackground(qbrush)表示:将这个区域的背景色设置为浅灰色,实现高亮效果

(5) 设置为“整行高亮”

ext.format.setProperty(QTextFormat::FullWidthSelection, true);

关键!这是实现“整行高亮”的核心属性。

  • QTextFormat::FullWidthSelection是一个枚举值,表示:让选中的区域自动拉伸至整行宽度,即使光标没有选中到行尾
  • 如果不设置这个属性:高亮区域可能只覆盖光标附近的几个字符
  • 设置后:高亮会自动填充 从行首到行尾的整个水平范围,视觉上就是“整行高亮”

(6) 把这个高亮区域加入列表

extraSelection.append(ext);
  • 我们把配置好的高亮对象 ext,放入列表 extraSelection

(7) 应用高亮到文本编辑器

ui->textEdit->setExtraSelections(extraSelection);
  • 这是真正“生效”的一步!
  • 调用 setExtraSelections()后,Qt 会在下一帧渲染时,把列表中的高亮区域绘制出来
  • 不会影响用户真实选中的文本,只是视觉上的额外提示
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐