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

news2024/11/27 18:40:35

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

  • 一、记事本功能优化
    • 编码乱码问题
      • QComboBox下拉控件
      • QString、string、char * 间的数据转化
      • 编码问题解决整合
    • 光标行列值显示
    • 记事本打开窗口标题
    • 关闭按钮优化—弹窗提示
    • 快捷键设计
  • 二、☆ QT事件处理
    • 事件处理过程
    • 重写事件案例
    • 事件自定义按钮
    • 鼠标滚轮实现字体大小缩放
    • 事件过滤器
  • 三、当前行高亮的实现
    • C++模板回顾
    • QList容器介绍及使用
    • 当前行高亮设置
    • ExtraSelection简介
  • 四、记事本项目总结

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

一、记事本功能优化

编码乱码问题

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

QComboBox下拉控件

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

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

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

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

private slots:
    void on_currentIndexChanged(int);

3. 槽函数的实现
  通过自带的参数 indexcurrentText 方法获取点击的索引下标与内容

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

实际效果如图下所示:

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

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方式可以在保存的时候自定义编码方式,在读取文件的时候设置对应的编码方式
进行加载即可避免乱码问题。
定义成员变量-编码方式:

public:
	QString code_mode;

绑定信号与槽:

connect(ui->comboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(on_currentIndexChanged(int)));

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

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. 将新的数据显示在文本编辑器中
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中的光标改变会产生某个信号,可以进行信号与槽的连接。将光标改变信号和窗口槽函数连接,在槽函数中显示光标的行列位置。
光标变化信号:

void cursorPositionChanged()

获取光标位置:

QTextCursor QTextEdit::textCursor() const

获取光标行列值:

int columnNumber() const
int blockNumber() const

绑定信号与槽:

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

槽函数实现:

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编码。

记事本打开窗口标题

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

this->setWindowTitle("my notebook");

打开 / 保存 槽函数:

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

关闭按钮优化—弹窗提示

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

//关闭文件按钮
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应用程序中为特定功能设置快捷键:

//创建一个快捷键(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 函数,该函数在快捷键被激活时执行。这种方法非常适用于为特定操作提供快速访问路径。

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

//按钮打开快捷键
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();
});

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

//创建一个快捷键(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框架内部的事件检测就开始了(程序将进入事件循环来监听应用程序的事件)。

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

我件在Qt中产生之后的分发过理是这样的:
1.当事件产生之后,Qt使用应用程序对象调用notify() 函数将事件发送到指定的窗口:

[override virtual] bool QApplication::notify(QObject *receiver, QEvent *e);

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

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

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

[override virtual protected] bool QObject::event(QEvent *event);

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

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

重写事件案例

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

//头文件声明事件重写函数
void enterEvent(QEvent *event) override;
void leaveEvent(QEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
void closeEvent(QCloseEvent *event) override;
/**************重写事件函数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界面已完成按钮的三态设置,按钮的跳转等等,为巩固事件处理,本次通过事件处理来完成的按钮的三态、美化与响应过程:

#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类(自定义类)。

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

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

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

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

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

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

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

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

protected:
    void wheelEvent(QWheelEvent *e) override;
    void keyPressEvent(QKeyEvent *e) override;
    void keyReleaseEvent(QKeyEvent *e) override;
private:
    bool ctrlPressed = 0;
//鼠标滚轮事件
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应用程序可以获得更大的灵活性和更细粒度的事件处理控制。

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

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

事件过滤器处理函数:

//事件过滤器
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:若对模板有一定的了解的可跳过这个

//类模板定义
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;
}

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

//定义一个函数模板
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 的头文件。

#include <QList>

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

QList<int> list;

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

list.append(10);
list.append(20);
list.append(30);

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

int element1 = list[0];
int element2 = list.at(1);

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

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

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

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

当前行高亮设置

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

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来设置特定文本的格式:

#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程序开发流程-涉及从设计到部署的整个开发流程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1425732.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Common Mistakes in German

Comman Mistakes in German 1, Haus oder Hause2, ja nein oder doch(1) Positive Fragen(2) Negative Fragen 1, Haus oder Hause 2, ja nein oder doch (1) Positive Fragen (2) Negative Fragen kein / nicht P3

docker集成 nacos/nacos-server (包括踩的坑)

tips 这边需要的数据库我已经安装好了&#xff0c;所以数据库的安装这边已经省略了 拉取镜像&#xff08;这边使用nacos1.4.1作为例子&#xff09; docker pull nacos/nacos-server:1.4.1创建映射的文件夹 (conf存放配置文件&#xff0c;logs存放日志文件) mkdir -p /data/n…

202415读书笔记|《鲸鱼安慰了大海》——我不知道你爱不爱我 湖水想被青山拥在怀里

202415读书笔记|《鲸鱼安慰了大海》——我不知道你爱不爱我 湖水想被青山拥在怀里 辑一 我们一起站在山坡上开花辑二 野花唱歌给自己听辑三 星空给我留了位置后记 《鲸鱼安慰了大海》作者燕七&#xff0c;是在一个关注的友友那里知道的这本书&#xff0c;决定读下去&#xff0c…

IDEA如何进行远程Debug调试

背景&#xff1a; 使用docker进行CVE漏洞复现的时候&#xff0c;由于只能黑盒进行复现&#xff0c;并不能知道为什么会产生这个漏洞&#xff0c;以及漏洞的POC为什么要这么写&#xff0c;之前我都是通过本地debug来进行源码分析&#xff0c;后来搜了一下&#xff0c;发现可以进…

林浩然的“微分剑法”大显神威

林浩然的“微分剑法”大显神威 Lin Haoran’s Mighty “Differential Sword Technique” 在数学王国的一隅&#xff0c;有一位名叫林浩然的智者&#xff0c;他以其独特的“微分剑法”名震江湖。这门源自微积分的绝世武学&#xff0c;让他成功解决了瞬时速度难题和曲线切线问题&…

解决:ModuleNotFoundError: No module named ‘torchvision’

解决&#xff1a;ModuleNotFoundError: No module named ‘torchvision’ 文章目录 解决&#xff1a;ModuleNotFoundError: No module named torchvision背景报错问题报错翻译报错位置代码报错原因解决方法方法一&#xff0c;直接安装方法二&#xff0c;手动下载安装方法三&…

一文详解docker swarm

文章目录 1、简介1.1、涉及到哪些概念&#xff1f;1.2、需要注意什么&#xff1f; 2、集群管理2.1、创建集群2.2、将节点加入集群2.3、查看集群状态。2.4、将节点从集群中移除2.5、更新集群2.6、锁定/解锁集群 3、节点管理4、服务部署4.1、准备4.2、服务管理4.2.1、常用命令4.2…

OSPF排错

目录 实验拓扑图 实验要求 实验排错 故障一 故障现象 故障分析 故障解决 故障二 故障现象 故障分析 故障解决 故障三 故障现象 故障分析 故障解决 故障四 故障现象 故障分析 故障解决 故障五 故障现象 故障分析 故障解决 故障六 故障现象 故障分析 …

为 Spring Boot 项目配置 Logback 日志

关于 Logback 日志系统是一个线上项目必备的素质之一&#xff0c;代表性的日志框架 Log4j、SLF4J、Logback 这哥仨竟然是亲兄弟&#xff0c;他们有一个亲爹&#xff0c;那就是巨佬 Ceki Gulcu。 由于 Spring Boot 的默认日志框架选用的 Logback&#xff0c;再加上 Log4j2 之前…

[网络安全 渗透实验 01]基于MSF框架渗透攻击Win7主机系统的设计与实现

基于MSF框架渗透攻击Win7主机系统的设计与实现 文章目录 基于MSF框架渗透攻击Win7主机系统的设计与实现[Warning] 写在前面1. 实验要求2. 实验环境搭建2.1 攻击机&#xff08;Linux kali&#xff09;的下载与安装2.2 靶机&#xff08;Windows 7 Enterprise with Service Pack 1…

AI赋能—EasyCVR视频融合平台为春节人员流动保驾护航

春节期间&#xff0c;如景区、商场、车站等公共场所的人流量激增&#xff0c;人员密集度大。在此情况下&#xff0c;监控客流量可以及时发现人群聚集、过度拥挤等安全隐患&#xff0c;防止发生安全事故。通过实时监测和分析客流量数据&#xff0c;可以及时发现安全隐患和拥堵问…

MySQL 可重复读隔离级别,完全解决幻读了吗?

文章目录 前言一、什么是幻读&#xff1f;二、快照读是如何避免幻读的&#xff1f;三、当前读是如何避免幻读的&#xff1f;四、幻读被完全解决了吗&#xff1f;场景1场景2 总结 前言 MySQL InnoDB 引擎的默认隔离级别虽然是「可重复读」&#xff0c;但是它很大程度上避免幻读…

【Qt学习笔记】(二)信号和槽

信号和槽 1 信号和槽概述2 信号和槽的使用3 可视化生成槽函数4 自定义信号和槽5 带参数的信号和槽6 信号与槽的连接方式7 信号与槽的断开8 使用 Lambda 表达式来定义槽函数 1 信号和槽概述 在Qt中&#xff0c;用户和控件的每次交互过程称为一个事件。比如"用户点击按钮&q…

动网格-网格重构之弹性光顺局部重构法(四)

弹性光顺法的基本特点 弹性光顺法中&#xff0c;网格线类似于弹簧&#xff0c;两端节点(node)作弹性移动 弹性光顺法有如下特点。 (1)节点的数量和节点之间的连接关系均不变&#xff0c;即节点之间的连接属性不变。 (2)单独使用时&#xff0c;仅限于变形非常小的情况&#xff…

Ubuntu-22.04上使用硬解码播放视频

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、准备工作1.显卡驱动2.其它必须软件3.查看显卡支持哪些编码格式 二、SMplayer三、VLC总结 前言 现在Ubuntu做的越来越好了&#xff0c;很多人拿它来当主力机…

深度解读NVMe计算存储协议-1

随着云计算、企业级应用以及物联网领域的飞速发展&#xff0c;当前的数据处理需求正以前所未有的规模增长&#xff0c;以满足存储行业不断变化的需求。这种增长导致网络带宽压力增大&#xff0c;并对主机计算资源&#xff08;如内存和CPU&#xff09;造成极大负担&#xff0c;进…

【Tomcat与网络10】Tomcat I/O和线程池的并发调优

前面我们看了提高Tomcat启动速度的措施&#xff0c;这里我们看一下如何提高Tomcat的性能。 Tomcat 的调优涉及 I/O 模型和线程池调优、JVM 内存调优以及网络优化等&#xff0c;今天我们来聊聊 I/O 模型和线程池调优&#xff0c;由于 Web 应用程序跑在 Tomcat 的工作线程中&…

月入过万比打工强,在家就能做steam搬砖项目真的假的

每天都有粉丝私下跟我聊天&#xff0c;讨论Steam搬砖项目到底是不是真的&#xff0c;到底能不能做。你想让我详细说说。那么今天就和大家详细聊聊这个月入过万元的项目。 简单来说&#xff0c;Steam搬砖项目就是在国外蒸汽上采购游戏道具&#xff0c;在国内网易buff平台上销售…

外包干了10个月,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

面对近期行情大起大落的伦敦银需要关注什么?

近期经常有听到投资者抱怨说&#xff0c;伦敦银价格没有明显趋势&#xff0c;很难做。确实&#xff0c;我们从日线图看&#xff0c;金价处于一个比较宽幅的横盘区间当中&#xff0c;近期的行情也是大涨大跌。投资者认为&#xff0c;面对大起大落的行情无从下手。下面我们就来讨…