目录

Qt入门笔记

Qt入门笔记


一、前言

这个是用于学习QT入门的一个笔记。使制作一个QT小项目——记事本,所需要掌握的东西。逐渐熟悉每个类的基本用法,暴干2W多字,以后会继续更新!

二、创建Qt项目

2.1、使用向导创建

打开Qt Creator界面选择菜单栏[文件]新建工程 https://i-blog.csdnimg.cn/direct/2c9ad9b5f29b4e71bd2c2394d45ad953.png

弹出New Project对话框,选择Qt Widgets Application

https://i-blog.csdnimg.cn/direct/2ada068d2b194e4e8d80dd9b501bfcae.png 点击Choose https://i-blog.csdnimg.cn/direct/6996509aca10450a93448d14e66be342.png

下一步默认即可 https://i-blog.csdnimg.cn/direct/49367bdd5be54acbbd951c60dd1e5e4f.png

选择编译套件 https://i-blog.csdnimg.cn/direct/908545936ee64189b55fee2de11929a7.png 向导会默认添加一个继承自QMainWindow的类,可以在此修改类的名字和基类。默认的基类有QMainWindow、QWidget以及QDialog三个,我们可以选择QWidget(类似于空窗口),这里我们可以先创建一个不带UI的界面,继续下一步。后面的默认即可

2.2、最简单的Qt应用程序

https://i-blog.csdnimg.cn/direct/5a3928c24f2e4d02ad72d45c50f26148.png

2.2.1、main函数

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();//相当于绘制函数,没有它窗口都看不见
    return a.exec();//用来启动应用程序的事件循环的。当你调用这个函数
                      时,它会开始处理和分发事件,如用户的点击、键盘输入等
}
  • MainWindow

    :这是一个包含完整菜单栏、工具栏和状态栏的主窗口应用程序框架。它适合于更复 杂的应用程序,需要这些额外的用户界面元素来提供丰富的功能和交互

  • Widget

    :这通常是一个简单的窗口,没有内置的菜单栏、工具栏或状态栏。它适合于更简单或专用 的应用程序,不需要复杂的用户界面组件。

  • QApplication a(argc, argv) ;

    这行代码的作用是创建一个

    QApplication

    类的

    实例。这是几乎每个

    Qt

    应用程序必须做的第一步,因为它负责管理应用程序的许多核心功能。

2.2.2、widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget //MainWindow公有继承QMainWindow,QMainWindow继承Q_OBJECT
{
    Q_OBJECT//一个宏,继承Q_OBJECT或者集成它的子类需要加上

public:
    Widget(QWidget *parent = nullptr);//构造函数
    ~Widget();//析构函数

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

2.2.3、widget.cpp文件

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)//初始化列表
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}
  • *Widget::Widget(QWidget parent) : QWidget(parent),ui(new Ui::Widget):

    代码

    QWidget(parent)

    是初始化列表,用于调用基类

    QWidget

    的构造函数,并将

    parent

    传递给 它。 ui(new Ui::Widget)

    是初始化类内部的

    ui

    成员变量,这是通过

    new

    关键字动态分配的。 Ui::Widget 是由

    Qt Designer

    工具生成的,用于处理用户界面。这种方式允许将用户界面的设计与后端 逻辑代码分离,有助于提高代码的可维护性和可读性。

2.3、Qt按键Botton

2.3.1、创建一个Botton

在Qt中创建一个按键是非常容易得事,只需要随便拖拖拉拉就可以了 https://i-blog.csdnimg.cn/direct/e6bfebf98dab4fef9ecc53f68641118f.png

我们可以修改它的按键颜色以及不同状态下(按下、点击……)的属性,比如颜色 https://i-blog.csdnimg.cn/direct/37c808b8e45745d6bdc11e90949d1682.png https://i-blog.csdnimg.cn/direct/85b3e4d5fc2f49dcbc216b98d2d52cfc.png

这里修改为黑色做个示例: https://i-blog.csdnimg.cn/direct/5a721290a5aa4512b2915169c4e766cf.png https://i-blog.csdnimg.cn/direct/f72caf59d31840eabab4c11050652d83.png 这个就是修改后的样子

我们还可以修改按键不同状态下的颜色以及他的“外表”,我们就需要用到一点语法: https://i-blog.csdnimg.cn/direct/c80fd68eccfb41feaf1b8358de36b6bd.png

这里我们就是用照片来美化按键的UI

https://i-blog.csdnimg.cn/direct/9d97758539b14f1ea50a485cd454a68a.png

先把照片放在一个文件夹里面,然后copy去工程文档里面,然后回到编辑,右键选择添加文件:

https://i-blog.csdnimg.cn/direct/660f8100948844e79f79684062ea7aca.png

然后选择Qt里面的Resource File,一路默认会出现一下界面: https://i-blog.csdnimg.cn/direct/8e1db9f45323471fb88f70d8f4c0a32e.png 然后依次点击: https://i-blog.csdnimg.cn/direct/4b3fb17f44ce499780bf91f7544aebe0.png

然后把照片全部添加进去:

https://i-blog.csdnimg.cn/direct/0ba05e96c5464d329860ce4b0f8daac7.png

这里点击添加资源,选择对应要使用的照片即可,配合使用的语法: https://i-blog.csdnimg.cn/direct/200ce9c8def1417cb4482095de571610.png

QPushButton{border-image: url(:/icon/s1.png);}//默认状态为s1照片

QPushButton:hover{border-image: url(:/icon/s2.png);}//悬停状态为s2照片

QPushButton:pressed{border-image: url(:/icon/s3.png);}//按下状态为s3照片

2.3.2、信号与槽

简单来说信号就是触发槽,槽是一个执行的动作,信号就是触发槽的信号。

  • 信号

    (Signals)

    :是由对象在特定事件发生时发出的消息。例如,

    QPushButton

    有一个

    clicked()

    信号,当用户点击按钮时发出。

  • (Slots)

    :是用来响应信号的方法。一个槽可以是任何函数,当其关联的信号被发出时,该槽函数 将被调用。

简单使用一下信号与槽:我们需要在类Widget中添加一下信号和槽的成员:

class Widget : public QWidget
{
    Q_OBJECT

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

//类成员信号定义
signals:
    void mysignal();//无参类型信号
    void mysignalparams(int value);//有参类型信号

//类成员槽定义
private slots:
    void myslot();//无参类型槽
    void myslotparams(int value);//有参类型槽

private:
    Ui::Widget *ui;
};

然后在.cpp文件中定义槽的函数:

//槽函数定义
void Widget::myslot()
{
    std::cout << "myslot" << std::endl;
}
//槽函数定义
void Widget::myslotparams(int value)
{
    std::cout << "myslotparams" << std::endl;
    std::cout << value << std::endl;
}
然后将信号和槽“连接起来(connect)”:
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(this,SIGNAL(mysignal()),this,SLOT(myslot()));//将信号和槽联系起来
    connect(this,SIGNAL(mysignalparams(int)),this,SLOT(myslotparams(int)));//将信号和槽联系起来

    //代码触发信号
    emit mysignal();
    emit mysignalparams(99);
}

运行结果: https://i-blog.csdnimg.cn/direct/9fe710e0c1034e2baaa07af9ae2d7d49.png

2.3.3、按键使用信号与槽的方法

方法一共有4种:

  1. Designer 中点击:

  2. 使用 QObject::connect(是否使用函数指针)

  3. 使用

    C++11 Lambda表达式

第一种:右键点击按键,选择转到槽: https://i-blog.csdnimg.cn/direct/77e92110fcdd4208b3f9b8e385473c36.png

https://i-blog.csdnimg.cn/direct/098d6be019fd44dfa27d7dc668fb636c.png

然后就会自动跳转到.cpp文件中:我们定义好槽的函数内容即可

// 第一种方式按键响应函数
void MainWindow::on_pushButton_clicked()
{
    std::cout << "第一种方法按下响应" << std::endl;
}

第二种: 使用 QObject::connect(是否使用函数指针)

我们需要在.h头文件中声明槽,第一种系统会自动帮我们声明 https://i-blog.csdnimg.cn/direct/4da1184564694d45a854c8450765b85e.png

然后我们也是去.cpp文件中定义内容并且使用connect函数“连接” 信号与槽 https://i-blog.csdnimg.cn/direct/a6ba332b0f7945b2887a19e3d91b48e9.png

**第四种: 使用

C++11 Lambda表达式**

优点:不需要在头文件中声明槽函数

//第三方式:lambda表达式:QObject::connect(sender, &Sender::signal, [=]() { /* lambda body */ });
    QObject::connect(ui->pushButton_3, &QPushButton::clicked,[=]()
    {
        std::cout << "第三种方法按下响应" << std::endl;
    });
    //不需要在h头文件中声明槽——响应函数

运行结果:依次点击按键,依次执行对应的槽函数,依次打印: https://i-blog.csdnimg.cn/direct/5b9d34d6353f465cb55592c0351b6417.png

2.4、文件Read与Write-QFile类

QFile

Qt

框架中用于文件处理的一个类。它提供了读取和写入文件的功能,支持文本和二进制文 件。

QFile

继承自

QIODevice

,因此它可以像其他

IO

设备一样使用。

主要功能

文件读写

QFile

支持打开文件进行读取或写入操作

文件信息

:可以检索有关文件的信息,如大小、修改日期等。

文件操作

:提供了对文件进行重命名、移动、删除等操作的能力。

错误处理

QFile

在操作文件时提供了错误处理机制,可以通过相应的函数检查和获取错误信息

  • open()

    :打开一个文件。需要指定模式(如只读、只写、读写等)。

  • close()

    :关闭文件

  • read()

    write()

    :用于读取和写入数据。

  • exists()

    :检查文件是否存在。

  • remove()

    :删除文件。

  • copy()

    :复制文件。

openopen_mode;
返回值:失败返回0,成功返回1

open_mode:
QIODevice::NotOpen
QIODevice::ReadOnly//只读
QIODevice::WriteOnly//只写
QIODevice::ReadWrite//可读可写
QIODevice::Append
QIODevice::Truncate
QIODevice::Text//文本,\n默认修改为\r\n更好阅读
QIODevice::Unbuffered
QIODevice::NewOnly
QIODevice::ExistingOnly

这里的函数和Linux系统编程的函数大差不差,可以稍微参考一下:

2.4.1、文件操作——Read文件

//点击按键读取函数
void Widget::on_pushButton_clicked()
{
    //1.打开文件
    //QFile file("D:/Qt/test.txt");//需要打开的文件的位置
    QFile file;
    file.setFileName("D:/Qt/test.txt");

    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))//打开失败
    {
        qDebug() << "open File error";
    }
    else
    {
        qDebug() << "open File success";
    }

    //2.读取文件
    char buf[100] = {'\0'};
    qint64 Read_count = 0;

    Read_count = file.read(buf, 100);
    if(Read_count != 0)// 读取成功返回读取到的字节数
    {
       std::cout << "Read :" << Read_count << std::endl;
    }
    else
    {
        std::cout << "Read error" << std::endl;
    }
    //3.输出文件内容
    qDebug() << buf;//输出文件内容
    //4.关闭文件
    file.close();
}

2.4.2、文件操作——Write文件

//点击按键写入函数
void Widget::on_pushButton_2_clicked()
{
    //1.打开文件
    //QFile file("D:/Qt/test.txt");
    QFile file;
    file.setFileName("D:/Qt/test.txt");

    file.open(QIODevice::WriteOnly | QIODevice::Text);//文件不存在会自动创建,文件存在会更换带掉其内容
    //2.写入文件
    file.write("Hello BOBEN!");//返回写入的数据的个数
    //3.关闭文件
    file.close();
}

Read和Write文件运行结果: https://i-blog.csdnimg.cn/direct/984a979fc6d0453d8663b9c933fb746f.png

2.4.3、 QTextStream读写文件

QTextStream 的主要特性成一个表格。请看下表: https://i-blog.csdnimg.cn/direct/428aae8c5c0f43d1a2b14cdf1890955e.png

1、 QTextStream方式读文件
//QTextStream方式读取文件槽
void Widget::on_pushButton_clicked()
{
    QFile file;
    file.setFileName("D:/Qt/test.txt");//需要打开的文件的存放位置
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))//只读文本模式打开失败
    {
        qDebug() << "file open error";
    }
    QTextStream in(&file);//绑定文件
    in.setCodec("UTF-8");//设置字符
    // QString context = in.read(file.size());//一次性全部读取内容
    while(!in.atEnd())//分行读取  in.atEnd()——确认是否到文件底部,到了返回1,没有到返回0
    {
        QString context = in.readLine();//读取一行内容
        qDebug() << context;//打印一行内容
        qDebug() << "----";//打印一行内容
    }
    file.close();//关闭文件
}
2、 QTextStream方式写文件
//QTextStream方式写入文件槽
void Widget::on_pushButton_2_clicked()
{
    QFile file;
    file.setFileName("D:/Qt/test.txt");//文件路径,不存在自动创建
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))文件不存在会自动创建,文件存在会更换带掉其内容
    {
        qDebug() << "file open error";
    }
    QTextStream out(&file);
    out.setCodec("UTF-8");
    out << "nihao Boben";
    file.close();
}

2.4.4、光标操作seek

这里的光标和我们电脑的光标实质上是一样的,可以理解为光标在哪里,文本就从那里开始操作(读 | 写):

这里创造两个按键,并且都有自己的信号(点击)与槽,一个按键打开文件后读取函数(一行一行读取),读取完后不关闭文件,注意读取完后光标就处于文本的最后的地方了,如前面所说: 可以理解为光标在哪里,文本就从那里开始操作(读 | 写) ,另一个按键则不需要打开文件了,可以直接读取内容,但是这个时候 光标就处于文本的最后的地方,所以按键2根本读取不到内容,运行结果在后面!

.h文件
class Widget : public QWidget
{
    Q_OBJECT

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

    QFile file;//将文本的QFile类作为成员使用

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    void on_pushButton_3_clicked();

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



.c文件
//QTextStream方式读取文件槽
void Widget::on_pushButton_clicked()
{
    //QFile file;
    file.setFileName("D:/Qt/test.txt");//需要打开的文件的存放位置
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))//只读文本模式打开失败
    {
        qDebug() << "file open error";
    }
    QTextStream in(&file);//绑定文件
    in.setCodec("UTF-8");//设置字符
    // QString context = in.read(file.size());//一次性全部读取内容
    while(!in.atEnd())//分行读取  in.atEnd()——确认是否到文件底部,到了返回1,没有到返回0
    {
        QString context = in.readLine();//读取一行内容
        qDebug() << context;//打印一行内容
        qDebug() << "----";//打印一行内容
    }
    //file.close();//关闭文件
}

void Widget::on_pushButton_3_clicked()
{

    //file.setFileName("D:/Qt/test.txt");//需要打开的文件的存放位置
    //if(!file.open(QIODevice::ReadOnly | QIODevice::Text))//只读文本模式打开失败
    //{
    //    qDebug() << "file open error";
    //}
    QTextStream in(&file);//绑定文件
    in.setCodec("UTF-8");//设置字符
    // QString context = in.read(file.size());//一次性全部读取内容
    while(!in.atEnd())//分行读取  in.atEnd()——确认是否到文件底部,到了返回1,没有到返回0
    {
        QString context = in.readLine();//读取一行内容
        qDebug() << context;//打印一行内容
        qDebug() << "----";//打印一行内容
    }
    file.close();//关闭文件
}

运行结果: https://i-blog.csdnimg.cn/direct/7ff99e7dda624c9a8f88cbee51dc418d.png

这个时候就需要使用光标移动函数了:

seekpace;  pace:光标位置

所以我们只需要在按键2读取前加上一句代码可以让它可以读取到内容:

void Widget::on_pushButton_3_clicked()
{

    //file.setFileName("D:/Qt/test.txt");//需要打开的文件的存放位置
    //if(!file.open(QIODevice::ReadOnly | QIODevice::Text))//只读文本模式打开失败
    //{
    //    qDebug() << "file open error";
    //}
    QTextStream in(&file);//绑定文件
    in.setCodec("UTF-8");//设置字符
    // QString context = in.read(file.size());//一次性全部读取内容
    
    file.seek(0);

    while(!in.atEnd())//分行读取  in.atEnd()——确认是否到文件底部,到了返回1,没有到返回0
    {
        QString context = in.readLine();//读取一行内容
        qDebug() << context;//打印一行内容
        qDebug() << "----";//打印一行内容
    }
    file.close();//关闭文件
}

运行结果: https://i-blog.csdnimg.cn/direct/81423eb3de0d41b4a8f332605d2b3c59.png

2.5、 文件选择对话框 QFileDialog类

文件选择对话框就是和我们的电脑点开文件夹出现的窗口一样,类似于: https://i-blog.csdnimg.cn/direct/cdaded9625ca4242bd6a4f5e93ff02e9.png

2.5.1、显示单(多)个对话框

qfileDialog.setFileMode(File_mode);

https://i-blog.csdnimg.cn/direct/c8e476ef469444d3bab7cb12ca6e932e.png

示例:

//浏览文件夹槽函数
void Widget::on_pushButton_clicked()
{
    QFileDialog qfileDialog;// 创建一个 QFileDialog 实例
    qfileDialog.setFileMode(QFileDialog::ExistingFile);// 设置对话框为打开文件模式ExistingFile(s),复数为可以打开多个文件
    qfileDialog.setNameFilter("*.txt");// 设置文件过滤器
    //其他使用过滤器:dialog.setNameFilter("Text files (*.txt);;Images (*.png *.jpg);;All files(*)");
    qfileDialog.exec();// 显示对话框
    QStringList qstrings = qfileDialog.selectedFiles();//返回选中的文件的位置
    for(QString str : qstrings)//链表遍历打印
    {
        qDebug() << str;//打印选中的文件位置
    }
}

运行结果: https://i-blog.csdnimg.cn/direct/84a009c66f74412492a507ff3bb27f1b.png

2.5.2、另存(创建)文件

//另存文件槽函数
void Widget::on_pushButton_2_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this,tr("Save File"),"D:/QT/man.txt");

    QFile file;
    file.setFileName(fileName);//文件路径,不存在自动创建
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))//打开文件
    {
       qDebug() << "file open error";
    }
    QTextStream out(&file);
    out.setCodec("UTF-8");
    out << "666666666";
    file.close();
}

运行结果: https://i-blog.csdnimg.cn/direct/d54489a0b1c8403eadb9b5cea05fe151.png 就会得到一个新的.txt文件: https://i-blog.csdnimg.cn/direct/69093824446c4bd695c587d4cdff8348.png

2.5.3、显示单个对话框的另一种方式

QString fileName = QFileDialog::getOpenFileName(this,tr("Open File"),"D:/QT/",tr("Text(*.txt)"));

2.6、文本text- textEdit类

制作一个文本输入框一样很简单,也只需要和按键一样一拖即可实现: https://i-blog.csdnimg.cn/direct/bac11cd8a5d14c5e816ceb3abb9c1c06.png

上面我们打开文件读取文件内容是将内容打印出来,这里我们可以打印出来在文本上:                  那我们就先要学习几个 textEdit 类里面简单的函数 :

ui->textEdit->clear();//清除textEdit的内容
ui->textEdit->setText(context);//在文本上显示出来(替换形式)
ui->textEdit->append(context);//在文本上显示出来(追加形式)
context属于QString类型

然后我们就可以使用这几个函数和前面所学的实现,点击按键,跳出一个文件选择框,选择好文件后,将文件的内容显示在文本框中:

//打开文件按键的槽函数
void Widget::on_pushButton_clicked()
{
    //返回选中文件的文件路径
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"D:/Qt/",tr("Text (*.txt)"));
    QFile file;//定义一个QFile类定义一个文件

    //ui->textEdit->clear();//清除textEdit的内容
    file.setFileName(fileName);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))//打开文件
    {
        qDebug() << "file open error";//打开文件失败打印信息
    }
    QTextStream in(&file);//使用QTextStream读取文件内容
    in.setCodec("UTF-8");//用UTF-8字符格式读取
    while(!in.atEnd())
    {
        QString context = in.readLine();
        // qDebug() << qPrintable(context);
        ui->textEdit->setText(context);
        //ui->textEdit->append(context);//在文本上显示出来
    }
}

2.6.1、 textEdit的信号

我们到UI界面右击文本,点击跳到槽,可以看看它有什么信号: https://i-blog.csdnimg.cn/direct/f5570639e85643aa9943a1efcb6f0e92.png

这里使用上面这个箭头的作为演示,实现打印当前第几行第几列的功能:

//文本当前位置坐标发生变化信息所触发的槽
void Widget::on_textEdit_cursorPositionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();//获取当前新的坐标
    //qDebug() << cursor.blockNumber()+1 <<","<< cursor.columnNumber() + 1;
    QString blockNum = QString::number(cursor.blockNumber()+1);//提取坐标中的列坐标
    QString columnNum = QString::number(cursor.columnNumber()+1);//提取坐标中的行坐标

    qDebug() << blockNum << columnNum;//打印信息
}

2.6.2、 QList

Qt

框架中,

QList

是一个容器类,它在内部实现上类似于一个数组,但也提供了一些链表的特性。

QList

的设计旨在提供一个在多数情况下既高效又方便的通用列表容器。用于存储元素列表。它提供了 丰富的功能,包括添加、移除、访问元素等。

QList

的内部工作原理:

  1. 数组式存储

    QList

    在大多数情况下使用连续内存存储其元素,类似于数组。这意味着它提供了快 速的索引访问(通过下标操作符 []

    ),以及相对高效的迭代性能。

  2. 动态调整大小

    :与静态数组不同,

    QList

    可以动态增长和缩减,自动管理内存分配。

  3. 链表特性

    :虽然

    QList

    主要基于数组,但它也提供了一些链表的操作,比如在列表的开始或结束 处添加和移除元素。这些操作通常比在数组中间插入或删除元素更高效。

  4. 复制时共享内存

    QList

    使用一种称为

    隐式共享

    implicit sharing

    )或

    写时复制

    copy-onwrite)的技术。这意味着当你复制一个

    QList

    时,它不会立即复制所有元素,而是共享相同的数 据,直到你尝试修改其中一个列表,此时才进行实际的复制。这使得复制 QList

    变得非常高效。

基本用法:

包含头文件

:首先,你需要包含

QList

的头文件。

#include <QList>

创建

QList

实例

:创建一个

QList

对象,并指定存储的元素类型。

QList<int> list;

添加元素

:使用

append

push_back

方法添加元素。

list.append(1);
list.append(2);
list.append(3);

访问元素

:可以使用下标操作符或

at()

方法访问元素。

int firstElement = list[0];
int secondElement = list.at(1);

遍历列表

:使用迭代器或范围基的

for

循环遍历列表。

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

移除元素

:使用

removeAt

removeOne

clear

方法移除元素。

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

2.6.3、 ExtraSelection(文本字体颜色属性)

QTextEdit::ExtraSelection

是一个在

QTextEdit

中用来表示额外的文本选择和高亮的结构。

如何工作:

  • ExtraSelection

    结构体

    QTextEdit::ExtraSelection

    是一个结构体,包含了两个主要成员:

    QTextCursor

    QTextCharFormat

    QTextCursor

    表示在文本中的一个位置或者区间,而

    QTextCharFormat

    用于定义这个区间的格式,比如背景颜色、字体等。

  • 设置

    ExtraSelection

    :你可以创建一个或多个

    ExtraSelection

    对象,为它们设置相应的光标位 置和格式,然后通过 QTextEdit

    setExtraSelections

    方法将这些对象应用到文本编辑器中。 这样,你可以对文本的特定部分应用特定的格式,而不影响其他文本。

  • 高亮当前行

    :要高亮显示当前行,你需要在

    cursorPositionChanged()

    信号的槽函数中创建一个 ExtraSelection 对象。使用当前的

    QTextCursor

    对象(通过

    textCursor()

    方法获取)来确

    定当前行的位置,并设置背景颜色为你选择的高亮颜色。

这里先使得文本当前行高光作为例子:

//文本当前位置坐标发生变化信息所触发的槽
void Widget::on_textEdit_cursorPositionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();//获取当前新的坐标
    //qDebug() << cursor.blockNumber()+1 <<","<< cursor.columnNumber() + 1;
    QString blockNum = QString::number(cursor.blockNumber()+1);//提取坐标中的列坐标
    QString columnNum = QString::number(cursor.columnNumber()+1);//提取坐标中的行坐标

    qDebug() << blockNum << columnNum;//打印信息

    //设置当前高亮
    QList<QTextEdit::ExtraSelection>  extraSelection;//制作一个QTextEdit::ExtraSelection类型的容器
    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、设置
    extraSelection.append(ext);//将结构体假如到容器里面去
    ui->textEdit->setExtraSelections(extraSelection);//设置

}

不仅有背景颜色的更改,还有更多其他的属性可以更改: https://i-blog.csdnimg.cn/direct/f82e4e2ab9cb47d9b6ba799b890d0fa7.png

这里使用改变字体大小来作为一个示例:

//快捷键槽函数
void Widget::test()
{
    qDebug() << "test";
    //获取当前字体的信息
    QFont font = ui->textEdit->font();
    //获取字体大小
    int fontsize = font.pointSize();
    if(fontsize == -1)  return;

    //改变字体大小
    int newsize = fontsize +1;
    font.setPointSize(newsize);

    //设置字体大小
    ui->textEdit->setFont(font);
}

运行结果,触发槽后字体逐渐变大:

https://i-blog.csdnimg.cn/direct/1b303d9be354431fa0688206832a03ac.png https://i-blog.csdnimg.cn/direct/8a2f09529ed744cca7fe7a5761641d36.png

2.7、 QComboBox选择条框

QComboBox

Qt

框架中用于创建下拉列表的一个控件。

它允许用户从一组选项中选择一个选项,并可以配置为可编辑,使用户能够在其中输入文本。

QComboBox

提供了一系列方法来添加、删除和修改列表中的项,支持通过索引或文本检索项,并可以通过信号和槽机制来响应用户的选择变化。该 控件广泛应用于需要从多个选项中进行选择的用户界面场景,例如表单和设置界面。 https://i-blog.csdnimg.cn/direct/cb20f1984e8e4134958178d662b0ac09.png

那么一个选择条框是什么样的呢? https://i-blog.csdnimg.cn/direct/0ca2c35b7b2649c297d6cad53d9069ee.png

当然,它的生成一样相当简单,也是一拖即可: https://i-blog.csdnimg.cn/direct/7912fc5bbc514a71a7ee92e63f05b1c0.png

这个和按键一样,一样适用于和信号与槽配合使用,不同的是按键是按下的状态改变作为信号,这个是选择框选择的东西作为信号。我们搜索手册可以看看他的信号种类: https://i-blog.csdnimg.cn/direct/adfc64c063224022b1db4115fd24cd33.png

接下来还是老样子,连接信号与槽,声明和定义槽:

.c文件
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //这里使用选中框变化的信号currentIndexChanged(int index) index选中内容的索引(从0开始)
    connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(oncurrentIndexChanged(int)));//连接信号与槽
}

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

//槽函数执行动作
void Widget::oncurrentIndexChanged(int index)
{
    qDebug() << index;
    qDebug() << ui->comboBox->currentText();//这里需要展现的内容都可以去手册查,看看自己需要什么,这里是打印选中的文本

   //ui->comboBox->currentText();这里返回的是Qstring类型
   //想要转换成const char*类型需要ui->comboBox->currentText().toStdString().c_str;
}



.h文件
class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void oncurrentIndexChanged(int index);//声明槽函数

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

运行结果: https://i-blog.csdnimg.cn/direct/71e4e7b3a07e4dbeb9c1d8e0ac4da7fe.png

2.8、消息对话框 QMessageBox

QMessageBox

Qt

框架中用于显示消息框的一个类,它常用于向用户显示信息、询问问题或者报告错 误。以下是 QMessageBox

的一些主要用途:

  • 显示信息

    :向用户显示一些信息性的消息。

  • 询问用户决策

    :询问用户一个问题,并根据其回答做出相应的操作。

  • 报告错误

    :向用户报告程序运行中的错误。

消息对话框到底是啥样的呢? https://i-blog.csdnimg.cn/direct/f49cf700133c4ee5acdecebf91d935c0.png

那我们怎么才能创建生成一个对话框呢?我们可以打开手册查看这个类的成员用法: https://i-blog.csdnimg.cn/direct/708f6f534e8d4a48a4f71b4e6743ba1d.png

这里还是使用一个按键来触发制作一个对话框:

//弹出对话框的按键的槽
void Widget::on_pushButton_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);//按键的名字

    switch (ret) //哪个按键按下了
    {
       case QMessageBox::Save:
           // Save was clicked
                qDebug() << "Save";
           break;
       case QMessageBox::Discard:
           // Don't Save was clicked
                qDebug() << "Discard";
           break;
       case QMessageBox::Cancel:
           // Cancel was clicked
                qDebug() << "Cancel";
           break;
       default:
           // should never be reached
           break;
     }
}

运行结果: https://i-blog.csdnimg.cn/direct/d1e83f4a2e374de481a48b150f51bdf7.png

2.9、快捷键添加- QShortcut

Qt

中实现快捷键功能通常涉及到

QShortcut

类的使用。下面是一个简单的代码示例,展示了如何在 Qt 应用程序中为特定功能设置快捷键:

这里使一个使用 Lambda表达式

的一个实例:

// 创建一个快捷键 (Ctrl + N) 并关联到窗口
QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+N"), &window);
// 当快捷键被按下时,显示一个消息框
QObject::connect(shortcut, &QShortcut::activated, [&]() 
{
    QMessageBox::information(&window, "Shortcut Activated", "Ctrl+N waspressed");
});

我们可以看看QKeySequence函数里面的成员可以是什么,手册里面实在太多了,我们只看一部分好了:发现快捷键还可以操作文件,下面我们来写一个例子: https://i-blog.csdnimg.cn/direct/88b8247b387c497e8a0b575a34d8af3d.png

这里我们也写一个简单的例子,快捷键触发槽函数打印信息:

.c文件
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+N"), this);//创建一个快捷键

    connect(shortcut,SIGNAL(activated()),this,SLOT(test()));//绑定信号与槽
}

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


//快捷键槽函数
void Widget::test()
{
    qDebug() << "test";
}



.h文件
class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void test();//槽函数声明


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

运行结果: https://i-blog.csdnimg.cn/direct/88473459bb2745af8b2e0d1f8142281e.png

对于要对文件进行操作的话,我们需要在参数方面进行修改:

QShortcut *shortcut = new QShortcut(QKeySequence(tr("Ctrl+S",“File|Open)), this);//创建一个快捷键



然后还是进行绑定信号与槽,后面在槽函数内对文件进行操作即可

2.10、QT事件

事件处理过程:

众所周知

Qt

是一个基于

C++

的框架,主要用来开发带窗口的应用程序(不带窗口的也行,但不是主流)。 我们使用的基于窗口的应用程序都是基于事件,其目的主要是用来实现回调(因为只有这样程序的效率 才是最高的)。所以在Qt

框架内部为我们提供了一些列的事件处理机制,当窗口事件产生之后,事件会 经过:

事件派发 -> 事件过滤->事件分发->事件处理

几个阶段。 Qt窗口中对于产生的一系列事件都有默认 的处理动作,如果我们有特殊需求就需要在合适的阶段重写事件的处理动作

比如信号与槽就是一种

事件(

event

)是由系统或者

Qt

本身在不同的场景下发出的。当用户按下

/

移动鼠标、敲下键盘,或者是 窗口关闭/

大小发生变化

/

隐藏或显示都会发出一个相应的事件。一些事件在对用户操作做出响应时发出, 如鼠标/

键盘事件等;另一些事件则是由系统自动发出,如计时器事件。

每一个

Qt

应用程序都对应一个唯一的

QApplication

应用程序对象,然后调用这个对象的

exec()

数,这样

Qt

框架内部的事件检测就开始了(

程序将进入事件循环来监听应用程序的事件

)。

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow* w = new MainWindow;
    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 QWidget::event(QEvent *event);
  4. 事件分发器会将分类之后的事件(鼠标事件、键盘事件、绘图事件。。。)分发给对应的事件处理 器函数进行处理,每个事件处理器函数都有默认的处理动作(我们也可以重写这些事件处理器函 数),比如:鼠标事件:

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

    我们可以去看看支持重写的事件有多少,我们可以去手册查看 QWidget 类的Protected Functions:(这里没有完全展现出来)

    https://i-blog.csdnimg.cn/direct/6103b0c5df324a3d91a29b2004d18aa0.png

这里我们挑几个出来重写一下test一下:

.h文件

class Widget : public QWidget
{
    Q_OBJECT

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

public://声明事件处理函数
    void enterEvent(QEvent *event) override;//进入运行框函数重写
    void leaveEvent(QEvent *event) override;//离开运行框函数重写
    void wheelEvent(QWheelEvent *event) override;//进入运行框滚动滑轮函数重写
    void closeEvent(QCloseEvent *event) override;//关闭运行框函数重写
    void resizeEvent(QResizeEvent *event) override;//放大缩小运行框函数重写

private:
    Ui::Widget *ui;
};




.c文件

//进入运行框处理函数
void Widget::enterEvent(QEvent *event)
{
    qDebug() << "mouse enter";
}
//离开运行框处理函数
void Widget::leaveEvent(QEvent *event)
{
    qDebug() << "mouse leave";
}
//进入运行框滚轮滑动处理函数
void Widget::wheelEvent(QWheelEvent *event)
{
    qDebug() << event->angleDelta();

}
//关闭运行框处理函数
void Widget::closeEvent(QCloseEvent *event)
{
    int ret = QMessageBox::warning(this, tr("My Application"),
                                    tr("close the window\n"
                                       "Do you want to close the window?"),
                                    QMessageBox::Ok | QMessageBox::No
                                    );
    switch(ret){
    case QMessageBox::Ok:
        event->accept();
        break;
    case QMessageBox::No:
        event->ignore();
        break;
    }

}
//放大缩小运行框处理函数
void Widget::resizeEvent(QResizeEvent *event)
{
    qDebug() << "oldSize:" << event->oldSize()
             << "newSize:" << event->size();
}

运行结果: https://i-blog.csdnimg.cn/direct/b5692ed98b0e4aa1a1a063d4c049f0af.png

2.10.1、利用事件制作自定义按键

我们在文件中新建一个类: https://i-blog.csdnimg.cn/direct/a5bd6ece4fd646a5951fe5c933ee7b35.png

我这里起名为Mybotton继承于Widget(注意第一个字母要大写)

.h文件

#ifndef MYBOTTON_H
#define MYBOTTON_H

#include <QWidget>

class Mybotton : public QWidget
{
    Q_OBJECT
public:
    explicit Mybotton(QWidget *parent = nullptr);

protected:
    void leaveEvent(QEvent *event) override;//离开widget窗口
    void enterEvent(QEvent *event) override;//进入widget窗口

signals:

};

#endif // MYBOTTON_H



.c文件

#include "mybotton.h"

#include <QDebug>

Mybotton::Mybotton(QWidget *parent) : QWidget(parent)
{

}

void Mybotton::leaveEvent(QEvent *event)
{
    qDebug() << "lll";
}

void Mybotton::enterEvent(QEvent *event)
{
    qDebug() << "kkk";
}

然后因为我们是继承于Widget类,所以我们生成一个Widget: https://i-blog.csdnimg.cn/direct/62a2e46539ce4f3685734f42f47ab116.png

然后右键点击矩形,点击提升为我们刚才创建的类: https://i-blog.csdnimg.cn/direct/68908d04c6544cf595413b0b10607f5d.png 运行结果: https://i-blog.csdnimg.cn/direct/1d51613365464adead7685ede8776d95.png

2.10.2、自定义按键信号与槽

这里可以回忆一下前面自定义信号与槽的使用:

mybotton.h

class Mybotton : public QWidget
{
    Q_OBJECT
public:
    explicit Mybotton(QWidget *parent = nullptr);

protected:
    void leaveEvent(QEvent *event) override;//离开widget窗口
    void enterEvent(QEvent *event) override;//进入widget窗口

signals:
    void clicked();//声明信号


};



widget.cpp:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    connect(ui->mybtn,&Mybotton::leaved,[=](){
        qDebug() << "myButton is leaved !";
    });

    connect(ui->mybtn,&Mybotton::entered,[=](){
        qDebug() << "myButton is entered !";
    });
}


mybotton.cpp:

void Mybotton::leaveEvent(QEvent *event)
{
    qDebug() << "lll";
    emit leaved();//触发信号
}

void Mybotton::enterEvent(QEvent *event)
{
    qDebug() << "kkk";
    emit entered();
}

运行结果: https://i-blog.csdnimg.cn/direct/c941da2ea8394835a2aed765dc1bcdf0.png

2.10.3、事件实现控制字体大小

首先我们要实现Ctrl+鼠标控制字体大小,我们需要重写鼠标滑动事件和键盘输入事件执行动作,两者合起来就可以实现了!

我们新建一个类,基于QTextEdit类

https://i-blog.csdnimg.cn/direct/469d6974dac4440e9523af982e0975da.png

新建一个文本并且提升为MyTextEdit: https://i-blog.csdnimg.cn/direct/6e4a17f740bd4c9e8092fbd9032188d5.png 代码:

mytextedit.h

#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;//Ctrl是否被按下标志位

};

#endif // MYTEXTEDIT_H



mytextedit.c

#include "mytextedit.h"

#include <QWheelEvent>
#include <QDebug>

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

}

void MyTextEdit::wheelEvent(QWheelEvent *e)
{
    qDebug() << "wheelEvent";
    if(ctrlKeyPressed == 1){
        if(e->angleDelta().y() > 0){
            //放大字体
            qDebug() << "fangda";
        }else if(e->angleDelta().y() < 0){
            //缩小字体
            qDebug() << "suoxiao";
        }
        e->accept();//事件处理完成
    }else{
        QTextEdit::wheelEvent(e);//没有按下Ctrl默认怎么处理就怎么处理
    }
}

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

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

运行结果: https://i-blog.csdnimg.cn/direct/f522e8c5dc324f3d8334ea3a3ee37454.png