C++——Qt信号与槽

往widget.cpp中加入这行代码可以使得在窗口发生大小变化时,布局及其子控件随之调整  

this->setLayout(ui->verticalLayout);

🎈基本概念:

提出疑问,界面上已经有按键了,怎么操作才能让用户按下按键后有操作上的反应呢?

在 Qt 中,信号和槽机制是一种非常强大的事件通信机制。这是一个重要的概念,特别是对于初学者来说,理解它对于编写 Qt 程序至关重要。

概要

  1. 信号 (Signals):是由对象在特定事件发生时发出的消息。例如,QPushButton 有一个 clicked() 信号,当用户点击按钮时发出。

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

  3. 连接信号和槽:使用 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()<<"保存文件成功!";

}

运行结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值