往widget.cpp中加入这行代码可以使得在窗口发生大小变化时,布局及其子控件随之调整
this->setLayout(ui->verticalLayout);
🎈基本概念:
提出疑问,界面上已经有按键了,怎么操作才能让用户按下按键后有操作上的反应呢?
在 Qt 中,信号和槽机制是一种非常强大的事件通信机制。这是一个重要的概念,特别是对于初学者来说,理解它对于编写 Qt 程序至关重要。
概要
-
信号 (Signals):是由对象在特定事件发生时发出的消息。例如,QPushButton 有一个 clicked() 信号,当用户点击按钮时发出。
-
槽 (Slots):是用来响应信号的方法。一个槽可以是任何函数,当其关联的信号被发出时,该槽函数 将被调用。
-
连接信号和槽:使用 QObject::connect() 方法将信号连接到槽。当信号发出时,关联的槽函数 会自动执行。
🎈按键QPushButton设置信号与槽
在 Qt 中,有几种不同的方式来设置按键信号与槽的连接,主要包括: Qt的信号和槽机制是其事件处理系统的核心。这种机制允许对象之间的通信,而不需要它们知道对方的 具体实现。以下是Qt信号和槽的几种常见连接方式的简要概述,我将它们整理成表格形式以便于理解:
连接方式 | 描述 | 示例 |
---|---|---|
使用 QObject::connect | 最常用的方式,直接通过 QObject::connect函数连接信号和槽。 | QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot())); |
使用C++11 Lambda表达式 | 利用C++11引入的Lambda表达式进行信号与槽的连接。这种方式可以直接 在连接点使用匿名函数,使代码更加简洁。 | QObject::connect(sender, &Sender::signal, [=]() { /* lambda body */ }); |
使用函数指针 | Qt 5中引入,允许使用函数指针直接连接信号和槽,这种方式类型安全,且可以利用IDE的代码补全和错误检 查。 | QObject::connect(sender, &Sender::signal, receiver, &Receiver::slot); |
自动连接(使用UI 文件) | 在使用Qt Designer时,可以通过命名约定自动连接信号和槽。当UI文件加载时,以 on__命名的槽会自动连接到相应的信号。 | 在Qt Designer中命名按钮为 pushButton,然后在代码中定义 on_pushButton_clicked()。 |
这些方式各有优劣,选择哪种方式取决于具体的应用场景、代码风格以及个人偏好。例如,直接使用 QObject::connect是最通用的方式,而使用Lambda表达式可以在同一位置编写信号处理逻辑,提高 代码的可读性。使用函数指针的方式则在编译时提供更好的类型检查。自动连接通常在使用Qt Designer 设计UI时比较方便。
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//在构造函数中进行信号与槽的绑定
//第二种方式:QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
QObject::connect(ui->btnCon, SIGNAL(clicked()), this, SLOT(on_btnCon_clickedMyself()));
//第三种方式:lambda表达式:QObject::connect(sender, &Sender::signal, [=]() { /* lambda body */ });
QObject::connect(ui->btnLambda, &QPushButton::clicked,[=](){
std::cout << "btnLambdaClicked" << std::endl;
});
//第四种方式:QObject::connect(sender, &Sender::signal, receiver, &Receiver::slot);
QObject::connect(ui->btnFortch,&QPushButton::clicked,this,&Widget::on_fortch_clicked);
}
Widget::~Widget()
{
delete ui;
}
//第一种方式:通过uiDesigner
void Widget::on_btnui_clicked()
{
std::cout<<"UIbutclicked"<<std::endl;
}
void Widget::on_btnCon_clickedMyself()
{
std::cout<<"btnConClicked"<<std::endl;
}
void Widget::on_fortch_clicked()
{
std::cout<<"btnFortchClicked"<<std::endl;
}
🎈自定义信号与槽:
在Qt中,自定义信号与槽是实现对象间通信的一种机制。信号和槽是Qt对象通信的核心特性,使得一个对象能够在发生某种事件时通知其他对象。自定义信号与槽的实现步骤如下:
1. 定义信号:
在Qt中,信号是由 signals 关键字声明的类成员函数。它们不需要实现,只需声明。
例如:
class MyClass : public QObject {
Q_OBJECT
public:
MyClass();
signals:
void mySignal(int value);
};
在上面的例子中, MyClass 有一个名为 mySignal的信号,它带有一个整型参数。
2.定义槽:
槽可以是任何普通的成员函数,但通常在类定义中用 slots 关键字标识。槽可以有返回类型, 也可以接受参数,但它们的参数类型需要与发出信号的参数类型匹配。
例如:
class MyClass :public QObject {
Q_OBJECT
public slots:
void mySlot(int value);
};
在这个例子中,我们定义了一个名为 mySlot 的槽,它接收一个整型参数。
3.连接信号与槽:
使用 QObject::connect 函数将信号与槽连接起来。当信号被发射时,连接到这个信号 的槽将被调用。
MyClass *myObject = new MyClass();
connect(myObject, SIGNAL(mySignal(int)), myObject, SLOT(mySlot(int)));
这行代码连接了 myObject 的 mySignal 信号到同一个对象的mySlot槽
4.发射信号:
使用emit 关键字发射信号。当信号被发射时,所有连接到这个信号的槽都会被调用。
emit mySignal(123);
这将触发所有连接到 mySignal 的槽。
自定义信号和槽是Qt编程中非常强大的特性,它们使得组件之间的通信变得灵活而松耦合。通过信和槽,可以方便地实现各种复杂的事件驱动逻辑。
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<iostream>
#include<QDebug>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
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;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
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(100);
}
Widget::~Widget()
{
delete ui;
}
void Widget::myslot()
{
qDebug()<<"myslot";
}
void Widget::myslotparams(int value)
{
qDebug()<<"myslotparms's value:"<<value;
}
最终输出结果:
QDebug()
QDebug 是 Qt 框架中用于输出调试信息的一个类。它提供了一种方便的方式来输出文本到标准输出(通常是控制台),这对于调试 Qt 应用程序非常有用。QDebug 类可以与 Qt 的信号和槽机制一起使用,使得在响应各种事件时能够输出有用的调试信息。使用 QDebug 的一个典型方式是通过 qDebug() 函数,它返回一个QDebug 对象。然后,可以使用流操作符 << 来输出各种数据类型。例如:
qDebug() << "This is a debug message";
int value = 10;
qDebug() << "The value is" << value;
当执行这些代码时,它们会在应用程序的控制台输出相应的文本。这对于检查程序的运行状态、变量的值或者跟踪程序的执行流程非常有帮助。
还可以使用qDebug() 来输出自定义类型,只要为这些类型提供了适当的输出操作符重载。此外,Qt 还提供了qInfo() , qWarning() , qCritical() 和 qFatal() 函数,用于输出不同级别的信息,分别用 于普通信息、警告、关键错误和致命错误。这有助于对日志信息进行级别划分,从而更好地控制输出内容。
🎈文件操作类 QFile:
QFile 是 Qt 框架中用于文件处理的一个类。它提供了读取和写入文件的功能,支持文本和二进制文件。 QFile 继承自 QIODevice ,因此它可以像其他IO设备一样使用。
主要功能 :
1. 文件读写: QFile 支持打开文件进行读取或写入操作
2. 文件信息:可以检索有关文件的信息,如大小、修改日期等。
3. 文件操作:提供了对文件进行重命名、移动、删除等操作的能力。
4. 错误处理: QFile 在操作文件时提供了错误处理机制,可以通过相应的函数检查和获取错误信息。
常用方法 :
-
open() :打开一个文件。需要指定模式(如只读、只写、读写等)。
-
close() :关闭文件。
-
read() 和 write() :用于读取和写入数据。
-
exists() :检查文件是否存在。
-
remove() :删除文件。
-
copy() :复制文件。
以下是使用 QFile 的一个简单例子:
#include "widget.h"
#include "ui_widget.h"
#include <QFile>
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnread_clicked()
{
//1.打开文件
//QFile file("D:/code/Qt/Qfile/test.txt");
QFile file;
file.setFileName("D:\\code\\Qt\\Qfile\\test.txt");
file.open(QIODevice::ReadOnly | QIODevice::Text);
//2.读取文件
char context[100]={'\0'};
// char *context=new char(size);
file.read(context,100);
//3.输出文件
qDebug()<<context;
//4.关闭文件
file.close();
}
void Widget::on_pushButton_2_clicked()
{
//1.打开文件
QFile file;
file.setFileName("D:\\code\\Qt\\Qfile\\test2.txt");
file.open(QIODevice::WriteOnly | QIODevice::Text);
//2.写入文件
file.write("Program QFile is writing something to this file!我是小鱼");
qDebug()<<"已经写入文件";
//3.关闭文件
file.close();
}
运行出来:
我们分别点击读取文件和写入文件按钮
控制台输出以下结果
然后我们打开test2.txt观察一下
成功读写入文件啦~
🎈QTextStream
QTextStream 的主要特性成一个表格。请看下表:
特性类别 | 说明 |
字符编码 | 支持 Unicode,可以处理如 UTF-8、UTF-16 等不同编码。通过setCodec() 方法设置特定编码。 |
读写文本 | 用于读写文件、字符串或任何继承自QIODevice 的对象。 |
格式化 | 提供文本格式化功能,如数字精度、基数(十进制、十六进制等)调整。 |
流操作符 | 支持使用<<和>>操作符,类似于C++中的iostream |
换行处理 | 自动处理不同操作系统间的换行符差异(如 Unix 的 \n 和 Windows 的 \r\n )。 |
错误处理 | 能够检测和报告在读写过程中出现的错误。 |
缓冲机制 | 提供缓冲机制,提高读写效率。 |
字符串操作 | 可以方便地处理和解析字符串数据。 |
QTextStream 是一个功能强大的类,用于处理文本数据,特别是在需要考虑字符编码和文本格式化的情况下。通过这些特性,它提供了一种灵活而强大的方式来读写和操作文本。
以下是一个更详细的示例,展示了如何使用 QTextStream 来读写文件:
void Widget::on_btnstreread_clicked()
{
//1.打开文件
QFile file;
file.setFileName("D:\\code\\Qt\\Qfile\\test.txt");
file.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream in(&file);
//in.seTCodec("UTF-8");//这是QT5的使用方法,注意区分
in.setEncoding(QStringConverter::Utf8);//QT6我们用setEncoding来设置编码格式
// QString context=in.read(file.size());
while(!in.atEnd()){ //多行文件读取,适合大文件读取
QString context=in.readLine();
qDebug()<<context;
}
qDebug()<<"已经成功读取文件!!!";
file.close();
}
void Widget::on_btnstrewirte_clicked()
{
//打开文件
QFile file;
file.setFileName("D:\\code\\Qt\\Qfile\\test2.txt");
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out.setEncoding(QStringConverter::Utf8);//设置编码格式
out << "I'm writing the text file!!! ";
file.close();
qDebug()<<"写入文件成功!";
}
结果运行如下啦:
🎈文件选择对话框 QFileDialog
QFileDialog开发流程
使用 QFileDialog 的基本步骤通常如下:
实例化:首先,创建一个 QFileDialog 对象的实例。
QFileDialog dialog;
设置模式:根据需要设置对话框的模式,如打开文件、保存文件等。
dialog.setFileMode(QFileDialog::AnyFile);
设置过滤器:如果需要,可以设置文件类型过滤器,以限制用户可以选择的文件类型。
dialog.setNameFilter(tr("Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML
files (*.xml)"));
显示对话框:通过调用 exec() 方法显示对话框,并在用户作出选择后执行相应的操作。
if (dialog.exec()) {
QStringList files = dialog.selectedFiles();
// 对用户选定的文件进行操作
}
通过 selectedFiles 方法获取用户选择的文件路径列表,然后对这些文件进行相应的处理。 这是使用 QFileDialog 的基本模式。Qt 也允许使用静态方法直接创建和显示对话框,例如 QFileDialog::getOpenFileName() ,这些方法更简单,但提供的自定义选项较少。
用QFileDialog打开文件并读写案例:
void Widget::on_btnQfileDialog_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), "D:/code/", tr("Text (*.txt)"));
qDebug()<<fileName ;
QFile file;
file.setFileName(fileName);
file.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream in(&file);
//in.seTCodec("UTF-8");//这是QT5的使用方法,注意区分
in.setEncoding(QStringConverter::Utf8);//QT6我们用setEncoding来设置编码格式
// QString context=in.read(file.size());
while(!in.atEnd()){ //多行文件读取,适合大文件读取
QString context=in.readLine();
qDebug()<<context;
}
qDebug()<<"已经成功读取文件!!!";
file.close();
}
用QFileDialog创建文件并保存案例:
void Widget::on_btnsave_clicked()
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "D:/code/untitled.txt", tr("Text (*.txt *.doc)"));
qDebug()<<fileName;
QFile file;
file.setFileName(fileName);
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out.setEncoding(QStringConverter::Utf8);//设置编码格式
out << "QDialog write Data to Txt file ";
file.close();
qDebug()<<"保存文件成功!";
}
运行结果如下: