C++ QT入门2——记事本功能实现与优化(事件处理+基本控件)

C++ QT入门2------记事本功能优化(事件处理+基本控件)

本次设计是基于 C++ QT入门1------记事本基础功能实现 的扩展与优化,因此需先参考上文进行基本功能的实现。

一、记事本功能优化

编码乱码问题

程序设计默认为UTF-8的编码,打开其他编码格式会出现文字乱码的情况,如打开ANSI编码文件则会出现中文乱码的情况,因此需要程序根据文件类型自定义编码格式。

QComboBox下拉控件

1. 在ui文件为Combo Box添加索引项:

2. 绑定信号与槽

每次对combo Box下拉控件的选项进行选择确实时会发出 currentIndexChanged (当前索引改变)信号,因此在构造函数内通connnect 将该信号与特定的槽函数进行绑定

cpp 复制代码
//绑定信号与槽
connect(ui->comboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(on_currentIndexChanged(int)));

记得在对应的.h文件进行声明槽函数

cpp 复制代码
private slots:
    void on_currentIndexChanged(int);

3. 槽函数的实现

通过自带的参数 indexcurrentText 方法获取点击的索引下标与内容

cpp 复制代码
void MainWindow::on_currentIndexChanged(int index)
{
    qDebug() << "index: " << index;
    qDebug() << "coding: " << ui->comboBox->currentText();
}

实际效果如图下所示:

QString、string、char * 间的数据转化

cpp 复制代码
string str;
QString qstr;
char * cstr;

//从QString 到 std::string
str = qstr.toStdString();
 
//从std::string 到QString
qstr = QString::fromStdString(str);

//从std::string 到 cstr;
cstr = str.c_str();

编码问题解决整合

通过以上Combo Box方式可以在保存的时候自定义编码方式,在读取文件的时候设置对应的编码方式

进行加载即可避免乱码问题。
定义成员变量-编码方式:

cpp 复制代码
public:
	QString code_mode;

绑定信号与槽:

cpp 复制代码
connect(ui->comboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(on_currentIndexChanged(int)));

槽函数的实现

方式1 :可以只改变成员变量code_mode,并修改打开与关闭的编码模式,但这种方式代码简单,但只适合下次重新打开生效

cpp 复制代码
void Widget::on_currentIndexChanged(int index)
{
    //1. 设置系统的编码方式 但只对下次打开文件起作用
    //记得需要修改打开关闭槽函数的编码方式为code_mode 
    code_mode = ui->comboBox->currentText();
    qDebug() << "index: " << index;
    qDebug() << "coding: " << ui->comboBox->currentText();
}

方式2:但实际应用中应该选择编码方式后应立即重新加载文件,这种方式更符合实际,实现步骤大致为:

  1. 获取新的编码方式
  2. 重新读取文本数据
  3. 将新的数据显示在文本编辑器中
cpp 复制代码
void Widget::on_currentIndexChanged(int index)
{
    //1. 设置系统的编码方式 但只对下次打开文件起作用
    //记得需要修改打开关闭槽函数的编码方式为code_mode 
    code_mode = ui->comboBox->currentText();
    qDebug() << "index: " << index;
    qDebug() << "coding: " << ui->comboBox->currentText();

    //2. 在不新打开新文件的情况下,选择编码方式,自动重新设置文件编码方式
    //重新读取文件数据流
    ui->textEdit->clear();
    if(file.isOpen())
    {
        //此时文件是打开的情况,文件光标在文件尾部,若要重新读取文件 需要重置光标
        file.seek(0);

        QTextStream in(&file);
        //以新的编码格式重新读取数据
        in.setCodec((const char*) code_mode.toStdString().c_str());

        while(!in.atEnd())
        {
            QString line = in.readLine();
            /***************3. 将txt文件内容输出至文本编辑器********************/
            ui->textEdit->append(line);
        }
    }
}

注意: 这种情况下当文件被打开按键打开并遍历一遍时,光标处于文件尾巴,因此需要手动将光标移至文件头部再进行对文件的读取

光标行列值显示

QTextEdit中的光标改变会产生某个信号,可以进行信号与槽的连接。将光标改变信号和窗口槽函数连接,在槽函数中显示光标的行列位置。
光标变化信号:

cpp 复制代码
void cursorPositionChanged()

获取光标位置:

cpp 复制代码
QTextCursor QTextEdit::textCursor() const

获取光标行列值:

cpp 复制代码
int columnNumber() const
int blockNumber() const

绑定信号与槽:

cpp 复制代码
//文本框绑定光标变化信号和槽函数
connect(ui->textEdit,SIGNAL(cursorPositionChanged()),this,SLOT(on_cursorPositionChanged()));

槽函数实现:

cpp 复制代码
void Widget::on_cursorPositionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();
    //qDebug() << cursor.blockNumber()   + 1 << "," <<cursor.columnNumber() + 1 << endl;
    //将行列数字转为 QString 类型
    QString lineNum = QString::number(cursor.blockNumber() + 1);
    QString colNum =  QString::number(cursor.columnNumber() + 1);
	//行列信息显示于标签
    const QString msg = "line:" + lineNum + " col:" + colNum;
    ui->label1->setText(msg);
}

注意: 只有UTF-8的编码格式工程允许在QLabel中显示中文。本工程编码格式为GBK,QLabel无法正常显示中文,后续工程将使用UTF-8编码。

记事本打开窗口标题

在文件未打开、打开、保存、修改后记事本的窗口标题提示应根据实际情况修改,因此需根据不同情况设置窗口的标题
未打开 / 关闭 槽函数

cpp 复制代码
this->setWindowTitle("my notebook");

打开 / 保存 槽函数:

cpp 复制代码
//设置记事本标题
QString qstr = QString::fromStdString(fileName.toStdString().substr(33,-1));
this->setWindowTitle( qstr + "-my noteBook");

关闭按钮优化---弹窗提示

通过利用帮助手册中QMessageBox的Detailed Description中的案例代码进行修改整合,实现关闭按钮的弹窗检测。

cpp 复制代码
//关闭文件按钮
void Widget::on_pushButton2_clicked()
{
    int ret = QMessageBox::warning(this, tr("My Application"),
                                   tr("The document has been modified.\n"
                                      "Do you want to save your changes?"),
                                   QMessageBox::Save | QMessageBox::Discard
                                       | QMessageBox::Cancel,
                                   QMessageBox::Save);

    switch (ret)
    {
        //保存,调用保存功能
        case QMessageBox::Save:
            //调用保存按钮槽函数
            qDebug() << "Save" << endl;
            on_pushButton3_clicked();
            if(file.isOpen())
                file.close();
            ui->textEdit->clear();
            this->setWindowTitle("my notebook");
            break;

        //丢弃 不保存 清理数据
        case QMessageBox::Discard:
             qDebug() << "Discard" << endl;
             ui->textEdit->clear();
             if(file.isOpen()){
                 file.close();
                 this->setWindowTitle("my notebook");
             }
        	break;
            
        //误触
        case QMessageBox::Cancel:
            qDebug() << "Cancel" << endl;
            break;
        default:
            // should never be reached
        	break;
    }
}

快捷键设计

在Qt中实现快捷键功能通常涉及到类的使用。下面是一个简答的代码示例,展示如何在Qt应用程序中为特定功能设置快捷键:

cpp 复制代码
//创建一个快捷键(Ctrl+n)开关连到窗口
QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+n"),this);
//当快捷键按下,显示一个消息框
QObject::connect(shortcut, &QShortcut::activated,[&](){
    QMessageBox::information(this, "short activated", "ctrl+N was pressed");
});

在这个示例中,当用户按下 Ctrl+ N时,程序将弹出一个消息框。这是通过创建一个 QShortcut 对象,并将其快捷键序列设量为 "Ctrl+N" 来实现的。然后将 activated 信号连接到一个 Lambda 函数,该函数在快捷键被激活时执行。这种方法非常适用于为特定操作提供快速访问路径。

为记事本打开和保存文件设置快捷键:

cpp 复制代码
//按钮打开快捷键
QShortcut *shortcutOpen = new QShortcut(QKeySequence(tr("Ctrl+o", "File|Open")),this);
connect(shortcutOpen, &QShortcut::activated,[=](){
    on_pushButton1_clicked();
});

//设置保存快捷键
QShortcut *shortcutSave = new QShortcut(QKeySequence(tr("Ctrl+s", "File|Save")),this);
connect(shortcutSave, &QShortcut::activated,[=](){
    on_pushButton3_clicked();
});

字体大小缩放快捷键实现:

cpp 复制代码
//创建一个快捷键(Ctrl+Shift+=)放大缩小字体
QShortcut *fontSizeIn  = new QShortcut(QKeySequence(tr("Ctrl+Shift+=", "File|Save")),this);
QShortcut *fontSizeOut = new QShortcut(QKeySequence(tr("Ctrl+Shift+-", "File|Save")),this);

//字体放大
connect(fontSizeIn,&QShortcut::activated,[=](){
    qDebug() << "Ctrl+Shift+=" << endl;
    //获得TextEdit的当前信息
    QFont font = ui->textEdit->font();
    //获得当前字体大小
    int fontSize = font.pointSize();
    qDebug() << "size= " << fontSize << endl;

    if(fontSize == -1)  return;

    //改变字体大小
    font.setPointSize(++fontSize);
    ui->textEdit->setFont(font);
});

//字体缩小
connect(fontSizeOut,&QShortcut::activated,[=](){
    //获得TextEdit的当前信息
    QFont font = ui->textEdit->font();
    //保存当前字体大小
    int fontSize = font.pointSize();
    if(fontSize == -1)  return;

    //改变字体大小
    font.setPointSize(--fontSize);
    ui->textEdit->setFont(font);
});

二、☆ QT事件处理

事件处理过程

众所周知Q 是一个素于C++的能架,主要用来开发带窗口的应用程序,我们使用的基于窗口的应用程序都是基于事件,其目的主要是用来实现回调。所以在Qt框架内部为我们提供了一系列的事件处理机制,当窗口事件产生之后,事件会经过:事件派发 -> 事件过滤 -> 事件分发 -> 事件处理 几个阶段。Qt窗口中对于产生的一系列事件都有默认的处理动作,如果我们有特殊需求就需要在合适的阶段重写事件的处理 动作,比如信号与槽就是一种

事件 (event)是由系统或者Qt本身在不同的场景下发出的。当用户按下 / 移动鼠标,敲下键盘,或者是窗口关闭 / 大小发生变化 / 隐藏或显示都会发出一个相应的事件。 一些事件在对用户操作做出响应时发出,如鼠标 / 键盘事件等;另一些事件则是由系统自动发出,如计时器事件。

每一个Qt应用程序都对应一个唯一的 QApplication 应用程产对象,然后调用这个对象的 exec() 函数。这样Qt框架内部的事件检测就开始了(程序将进入事件循环来监听应用程序的事件)。

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

我件在Qt中产生之后的分发过理是这样的:

1.当事件产生之后,Qt使用应用程序对象调用notify() 函数将事件发送到指定的窗口:

cpp 复制代码
[override virtual] bool QApplication::notify(QObject *receiver, QEvent *e);

2.事件在发送过程中可以通过事件过滤器进行过滤,默认不对任何产生的事件进行过滤。

cpp 复制代码
//需要先给窗口安装过滤器,该事件才会触发
[virtual] bool QObject::eventFilter(QObject *watched, QEvent *event);

3.当事件发送到指定窗口之后,窗口的事件分发器会对收到的事件进行分类:

cpp 复制代码
[override virtual protected] bool QObject::event(QEvent *event);

4.事件分发器会将分类之后的事件(鼠标事件、键盘事件、绘图事件...)分发给对应的事件处理函数进行处理,每个事件处理器函数都有默认的处理动作 (我们也可以重写这些事件处理器函数) ,比如:鼠标事件:

cpp 复制代码
//鼠标按下
[virtual protected] void QWidget::mousePressEvent(QMouseEven *event);
//鼠标释放
[virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event);
//鼠标移动
[virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event);

重写事件案例

初步重写鼠标进入、离开、滚轮滑动以及关闭窗口的常用事件,并给出相关重写过程与实例程序:

cpp 复制代码
//头文件声明事件重写函数
void enterEvent(QEvent *event) override;
void leaveEvent(QEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
void closeEvent(QCloseEvent *event) override;
cpp 复制代码
/**************重写事件函数c文件实现***************/
//鼠标进入事件
void Widget::enterEvent(QEvent *event)
{
    qDebug() << "mouse enter" << endl;
}
//鼠标离开事件
void Widget::leaveEvent(QEvent *event)
{
    qDebug() << "mouse leave" << endl;
}
//滚轮事件
void Widget::wheelEvent(QWheelEvent *event)
{
    qDebug() << event->angleDelta();
}
//窗口关闭事件
void Widget::closeEvent(QCloseEvent *event)
{
	//创建QMessageBox弹窗
    int ret = QMessageBox::warning(this, tr("My notebook"),
                                   tr("close the windows\n"
                                      "Do you want toclose the windows?"),
                                   QMessageBox::Yes | QMessageBox::No);
    switch (ret)
    {
	    case QMessageBox::Yes:
	        event->accept();	//接受事件
	        break;
	    case QMessageBox::No:
	        event->ignore();	//忽略事件
	        break;
	    default:
	        // should never be reached
	        break;
    }
}

事件自定义按钮

之前通用UI界面已完成按钮的三态设置,按钮的跳转等等,为巩固事件处理,本次通过事件处理来完成的按钮的三态、美化与响应过程:

cpp 复制代码
#include "evnetbutton.h"

#include <QPainter>

evnetButton::evnetButton(QWidget *parent) : QWidget(parent)
{
    pic.load(":/icon/file.jpg");//加载图片
    //setFixedSize(pic.size());   //图片和按钮大小匹配 按钮适应图片大小
    update();                   //update才能调paintEvent事件
}
void evnetButton::enterEvent(QEvent *event)
{
    pic.load(":/icon/QQ.jpg");//加载图片
    update();
}
void evnetButton::mousePressEvent(QMouseEvent *event)
{
    pic.load(":/icon/QQ.jpg");//加载图片
    update();
}
void evnetButton::leaveEvent(QEvent *event)
{
    pic.load(":/icon/file.jpg");//加载图片
    update();
}
void evnetButton::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.drawPixmap(rect(),pic);
}

注意: 需要将UI文件内的QWidget 提升为evnetButton类(自定义类)。

为自定义按钮添加信号与槽:

在按钮按下的状态事件下,发送一个自定义信号:

cpp 复制代码
void evnetButton::mousePressEvent(QMouseEvent *event)
{
    pic.load(":/icon/QQ.jpg");//加载图片
    update();
    emit clicked();
}

主widget界面程序绑定自定义信号与槽,响应按键的按下处理:

cpp 复制代码
/*********自定义按钮事件的槽函数**********/
connect(ui->eventBtn,&evnetButton::clicked,[=]()
{
   	qDebug() << "eventButton clicked!";
});

鼠标滚轮实现字体大小缩放

1. 自定义控件MyTextEdit ,并使得继承于QTextEdit

cpp 复制代码
class MyTextEdit : public QTextEdit
{
public:
    MyTextEdit(QWidget *parent);
};
cpp 复制代码
//构造函数 带父对象
MyTextEdit::MyTextEdit(QWidget *parent):QTextEdit(parent)
{
}

2. 捕获按钮按下,松开以及滚轮滑动事件

cpp 复制代码
protected:
    void wheelEvent(QWheelEvent *e) override;
    void keyPressEvent(QKeyEvent *e) override;
    void keyReleaseEvent(QKeyEvent *e) override;
private:
    bool ctrlPressed = 0;
cpp 复制代码
//鼠标滚轮事件
void MyTextEdit::wheelEvent(QWheelEvent *e)
{
    qDebug() << e->angleDelta().y();
    //按下ctrl + 滚轮实现字体缩放
    if(ctrlPressed == 1)
    {
        if( e->angleDelta().y() > 0)
            zoomIn();   //放大
        else
            zoomOut();  //缩小
        e->accept();
    }
    else                //鼠标正常下滑
    {
        QTextEdit::wheelEvent(e);
    }
}

//按键按下事件
void MyTextEdit::keyPressEvent(QKeyEvent *e)
{
    if(e->key() == Qt::Key_Control)
    {
        ctrlPressed = 1;            //ctrl按下标志
        //qDebug() << "ctrl pressed!";
    }
    QTextEdit::keyPressEvent(e);    //由Press正常执行
}

//按键松开事件
void MyTextEdit::keyReleaseEvent(QKeyEvent *e)
{
    if(e->key() == Qt::Key_Control){
        ctrlPressed = 0;
        //qDebug() << "ctrl Release!";
    }
    QTextEdit::keyReleaseEvent(e);  //由Release正常执行
}

事件过滤器

我们通过继承QTextEdit来重写事件实现Ctrl加滚轮的检测,还有一种处理方式,叫做事件过滤器

在Qt的事件处理过程中,引入事件过滤器 (Event Filter) 可以让你在事件达到目标对象之前进行拦截和处理。这是一种强大的机制,允许你在不同对象间共享事件处理逻辑或在父对象中集中处理待定事件,下面是加入事件过滤器的步聚:

  • 1.定义事件过滤器: 事件过滤器通常是重写了 QObject::eventFilter() 方法的对象。这个方法会在事件传递给目标对象之前被调用。

  • 2. 安装事件过滤器: 使用 QObject::installEventFilter() 方法安装事件过滤器。这个方法告诉Qt在将事件发送给特定对象之前先通过过滤器对象。例如,如果想在父面口中过滤子窗口的事件,需要在父窗口的对象上调用installEventFilter(),并将子窗口作为参数传进。

  • 3.事件过波路逻辑:eventFilter() 方法内部,可以编写自定义逻辑来决定如何处理或忽略事件。如果此方法返回 true,则表示事件已被处理,不应该继续传递;如果返回 false,则事件将正常传递给目标对象。

  • 4.事件分发: 当事件发生时,Qt首先将事件发送到安装了事件过滤器的对象。在这一步,eventFilter() 方法被调用。

  • 5.决定是否传进事件: 根据 eventFilter() 方法的返回值,Qt决定是否继续向目标对象传递事件。如果过滤器返回 true,事件处理到此结束;如果返回 false,事件继续传递到原始目标对象。

  • 6.目标对象处理事件: 如果事件过滤器允许事件继续传递,目标对象将没有事件过滤器存在时那样处理事件。

事件过滤器待别适用于以下情况:

  • 想在不修改子类代码的情况下改变事件的行为。
  • 当多个对象需要共享相同的事件处理逻辑。
  • 当需要在更高的层级上监控或修改应用程序的事件流。

通过使用事件过洗器,Qt应用程序可以获得更大的灵活性和更细粒度的事件处理控制。

滚轮字体的实现:
为文本编辑器安装事件过滤器:

cpp 复制代码
// 构造函数内 给textEdit安装事件过滤器,为滚轮字体做准备
ui->textEdit->installEventFilter(this); 

事件过滤器处理函数:

cpp 复制代码
//事件过滤器
bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    // 滚轮滑动
    if(event->type() == QEvent::Wheel)
    {
        if(QGuiApplication::keyboardModifiers() == Qt::ControlModifier)
        {
            qDebug() << "control + Wheel";
            QWheelEvent *wheelEvent = (QWheelEvent *)event;
            //判断滚轮方向
            if(wheelEvent->angleDelta().y() > 0)
            {
                zoomIn();
                qDebug() << "zoomIn";
            }
            else if(wheelEvent->angleDelta().y() < 0)
            {
                qDebug() << "zoomOut";
                zoomOut();
            }
        }
    }
}

三、当前行高亮的实现

C++模板回顾

  • 在C++中,模板 (Template) 是一种通用的编程工具,允许程序员编写泛型代码 ,使得类或函数能够适用于多种不同的数据类型 而不需要重复编写相似的代码
  • C++ 提供了两种主要类型的模板:类模板和函数模板

类模板:

类模板允许定义通用的类,其中某些类型可以作为参数。这样的类可以处理不同类型的数据,而不需要为每个数据类型编亏单独的类。

Ps:若对模板有一定的了解的可跳过这个

cpp 复制代码
//类模板定义
template <typename T>	//定义一种模板
class PrintData
{
private:
     T data;

public:
    void show_data(){
        cout << "data= " << data << endl;
    }
    void set_data(T data){
        this->data = data;
    }
};

int main()
{
	//实例化模板对象p3, 数据类型为string
    PrintData<string> p3;
    p3.set_data("hello");
    p3.show_data();

    return 0;
}

函数模板:

函数模板允许编写通用的函数,可以处理多种不同类型的数据。

cpp 复制代码
//定义一个函数模板
template <typename T>
T add(T a, T b)
{
    return a + b;
}

int main()
{
	//测试函数模板
    int ret1 = add(10,20);
    cout << "ret1= " << ret1 << endl;

    double ret2 = add(1.5,2.2);
    cout << "ret2= " << ret2 << endl;

    return 0;
}

QList容器介绍及使用

在Qt 框架中,QList 是一个容器类,它在内部实现上类似于一个数组,但也提供了一些链表的特性。 QList 的设计旨在提供一个在多数情况下既高效又方便的通用列表容器。用于存储元素列表,它提供了丰高的功能,包括添加、 移除、访问元素等。

QList 的内部工作原理:

  • 1.数组式存储: QList 在大多数情况下使用连续内存存储其他元素,类似于数組。这意味着它提供了快速的索引访问(通过下标操作符 [ ] ),以及相应高效的迭代性能
  • 2.动态调整大小 :与静态数组不同,QList 可以动态增长和缩减,自动管理内存分配。
  • 3. 链表特性: 虽然 QList 主要基于数组,但它也提供了一些链表的操作,比如在列表的开始或结束处添加和移除元素。这些操作通常比在数组中间插入或删除元素更高效。
  • 4. 复制时共享内存: QList 使用一种称为"隐式共享",或"写时复制"的技术。这意味者当你复制一个QList时,它不会立即复制所有元奈,而是共享相同的数据,直到你尝试修改其中一个列表,此时才进行实际的复制。这使得复制 QList 变得非常高效。

使用场景:

  • 当你需要快速的随机访问(如通过索引访问元素)时,QList 是一个不错的选择。
  • 如果你的主要操作是在列表的两端添加或移除元素,QList 也表现得很好。

基本用法:
包含头文件: 首先,需要包含 QList 的头文件。

cpp 复制代码
#include <QList>

**创建QList实例:**创建一个QList对象,并指定存储的元素类型

cpp 复制代码
QList<int> list;

添加元素: 使用 appendpush_back() 方法添加元素

cpp 复制代码
list.append(10);
list.append(20);
list.append(30);

访问元素: 可以使用下标操作符或 at() 方法访问元素

cpp 复制代码
int element1 = list[0];
int element2 = list.at(1);

遍历列表: 使用迭代器或范围的 for 循环遍历列表

cpp 复制代码
for(int i = 0; i < list.size(); i++)
{
	qDebug() << list[i];
}
	
//使用范围的for循环遍历
for(int item : list)
{
	qDebug() << item ;
}

移除元素: 使用removeAt、removeOne或clear方法移除

cpp 复制代码
list.removeAt(1);		//移除索引为1的元素
list.removeOne(100);	//移除一个值为100的元素
list.clear();			//清空整个列表

当前行高亮设置

在之前的光标位置改变的槽函数中进行补充设置当前行高亮代码,这些先给出实现高亮的代码,后面再对ExtraSelection做简要介绍。

cpp 复制代码
void Widget::on_cursorPositionChanged()
{
	/**********光标行列值显示************/
    QTextCursor cursor = ui->textEdit->textCursor();
    qDebug() << cursor.blockNumber()   + 1 << "," <<cursor.columnNumber() + 1 << endl;
    //将行列数字转为 QString 类型
    QString lineNum = QString::number(cursor.blockNumber() + 1);
    QString colNum =  QString::number(cursor.columnNumber() + 1);
    const QString msg = "line:" + lineNum + " col:" + colNum;
    ui->label1->setText(msg);

	/*************设置当前行高亮*************/
    //QList及变量定义
    QList<QTextEdit::ExtraSelection> extraSelections;   //QTextEdit::ExtraSelection 类型的列表集合
    QTextEdit::ExtraSelection ext1;

     //1. 获取当前行
    ext1.cursor = ui->textEdit->textCursor();

    //2. 设置颜色
    QBrush qBrush(Qt::yellow);
    ext1.format.setBackground(qBrush);
    //配置段落属性:整行显示,没有这行不行
    ext1.format.setProperty(QTextFormat::FullWidthSelection,true);

    //3. 设置
    //将ext1对象加入QList容器列表
    extraSelections.append(ext1);
    ui->textEdit->setExtraSelections(extraSelections);
}

ExtraSelection简介

QTextEdit::ExtraSelection 是一个在 QTextEdit 中用来表示额外文本选的和高亮的结构。
如何工作:

  • 1. ExtraSelection结构体QTextEdit::ExtraSelection 是一个结构体,包含了两个主要成员:QTextCursorQTextCharFormat。QTextCursor 表示在文本中的一个位置或区间,而 QTextCharFormat 用于定义这个区间的格式,比如背景颜色、字体等。
  • 2.设置 Extraselection: 通过创建一个或多个 ExtraSelection 对象,为它们设置相应的光标位置和格式,然后通过QTextEdit的 setExtraSelections方法将这些对象应用到文本编辑器中。这样,就可以对文本的特定部分应用特定的格式,而不影响其他文本。
  • 3.高亮当前行: 要高亮显示当前行,需要在cursorPositionChanged() 信号的槽的函数中创建一个 ExtraSelection 对象。使用当前 QTextCursor 对象(通过 textCursor() 方法获取)来确定当前行的位置,并设置背景颜色为选择的一种高亮颜色。

QTextCharFormat 类是Qt框架中的一部分,用于描述文本字符的格式。这个类提供了 丰富的接口来设置和获取文本字符的各种属性等。QTextCharFormat 通常用于丰富文本处理,可以在像 QTextEdit 和 QTextDocument 这样的类中使用。

QTextCharFormat 常用功能和方法:

1. 设置和获取字体样式:

  • 通过 setFont() 方法设置字体
  • 通过 font() 方法获取当前字体

2. 设置字体属性:

  • setFontWeight():设置字体粗细
  • setFontItalic():设置字体是否倾斜
  • setFontUnderline():设置是否有下划线

3. 设置文本颜色和背景颜色:

  • setBackground():设置文本的背景色
  • setForeground():设置文本字体的颜色

4. 其他文本属性:

  • setToolTip():设置文本的工具提示
  • setAnchor():设置文本是否为超链接
  • setAnchorHref():设置超链接的目标URL

实例代码:

下面是一个简单的示例,展示如何在QTextEdit 中使用QTextCharFormat来设置特定文本的格式:

cpp 复制代码
#include <QApplication>
#include <QTextEdit>
#include <QTextCharFormat>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTextEdit editor;

    //创建一个QTextCharFormat对象
    QTextCharFormat format;
    format.setFontWeight(QFont::Bold);
    format.setForeground(Qt::blue);
    format.setBackground(Qt::yellow);

    //将格式应用到编辑器中的特定文本
    QTextCursor cursor = editor.textCursor();
    cursor.movePosition(QTextCursor::Start);
    cursor.insertText("hello world!",format);

    editor.show();
    return a.exec();
}

四、记事本项目总结

类别 功能 描述
UI设计师基本控件操作 QWidget 基础的用户单元、用于构建复杂的用户界面
QPushButton 用于创建按钮
QHBoxLayout 水平布局管理器,用于水平排列控件
QVBoxLayout 竖直布局管理器,用于竖直排列控件
QTextEdit 多行文本编辑器控件
QStyleSheet 使用样式表来控制控件的外观
文件操作类 QFile 用于读取和写入文件
文件选择对话框类 QFileDialog 提供一个对话框,允许用户选择文件或目录
QT的信号与槽 - 用于对象之间的通信机制
消息对话框 QMessageBox 用于显示信息、警告、错误等对话框
快捷键捕获和处理 - 用户捕获和键盘快捷键
Ctrl按键信号捕获和处理 - 专门处理Ctrl按键的信号
鼠标滚轮信号捕获和处理 - 专门捕获和处理鼠标滚轮动作
事件处理 event 用于处理不同的事件
文本字符编码检测 - 用于检测和处理文本的字符编码
字体放大缩小 - 用于调整字体大小
QT程序开发流程 - 涉及从设计到部署的整个开发流程
相关推荐
Beau_Will6 分钟前
数据结构-树状数组专题(1)
数据结构·c++·算法
hunandede39 分钟前
av_image_get_buffer_size 和 av_image_fill_arrays
c++
怀澈1222 小时前
高性能服务器模型之Reactor(单线程版本)
linux·服务器·网络·c++
chnming19872 小时前
STL关联式容器之set
开发语言·c++
威桑3 小时前
MinGW 与 MSVC 的区别与联系及相关特性分析
c++·mingw·msvc
熬夜学编程的小王3 小时前
【C++篇】深度解析 C++ List 容器:底层设计与实现揭秘
开发语言·数据结构·c++·stl·list
yigan_Eins3 小时前
【数论】莫比乌斯函数及其反演
c++·经验分享·算法
Mr.133 小时前
什么是 C++ 中的初始化列表?它的作用是什么?初始化列表和在构造函数体内赋值有什么区别?
开发语言·c++
阿史大杯茶3 小时前
AtCoder Beginner Contest 381(ABCDEF 题)视频讲解
数据结构·c++·算法
C++忠实粉丝3 小时前
计算机网络socket编程(3)_UDP网络编程实现简单聊天室
linux·网络·c++·网络协议·计算机网络·udp