2021-12-29更新 Qt5 的新版和旧版信号-槽的写法 特别注意说明。
Qt5的旧语法(使用SIGNAL宏和SLOT宏):
connect(sender, SIGNAL(valueChanged(QString, QString)),
receiver, SLOT(updateValue(QString)));
Qt5的新语法(使用函数指针):
//Qt5 不带参数的信号和槽 的新写法
connect(sender, &Sender::valueChanged,
receiver, &Receiver::updateValue);
带有参数的信号和槽:
//Qt5 中带有参数的信号和槽的新写法
//前面声明的信号,信号必须返回void,且无需实现
signals:
void my_signal(int,QString);
//前面声明的槽,槽必须返回 void,需要实现
slots:
void print_signal(int, QString);
//后面使用时,要转成 指向类成员函数的指针 后再使用
void (Widget::*signal_with_para)(int,QString) = &Widget::my_signal; //带参数信号
void (Widget::*slot_with_para)(int,QString) = &Widget::print_signal; //带参数槽
connect(btn2, signal_with_para, this, slot_with_para); //处理带参数的信号
Qt官方对新语法格式的说明:
注意:官方强调的槽函数类型为 PointerToMemberFunction ,意为 指向 类成员函数的指针,可以是指向任意的类成员函数的指针。所以,&后面需要跟上 类修饰符 ::。
下面的引文可在 Qt Creator 中选中 connect 函数,然后按F1 键就能在对应的帮助文档中看到。
[static] QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)
This function overloads connect().
Creates a connection of the given type from the signal in the sender object to the method in the receiver object. Returns a handle to the connection that can be used to disconnect it later.
The signal must be a function declared as a signal in the header. The slot function can be any member function that can be connected to the signal. A slot can be connected to a given signal if the signal has at least as many arguments as the slot, and there is an implicit conversion between the types of the corresponding arguments in the signal and the slot.
Example:
QLabel *label = new QLabel;QLineEdit *lineEdit = new QLineEdit;QObject::connect(lineEdit, &QLineEdit::textChanged,label, &QLabel::setText);This example ensures that the label always displays the current line edit text.
A signal can be connected to many slots and signals. Many signals can be connected to one slot.
If a signal is connected to several slots, the slots are activated in the same order as the order the connection was made, when the signal is emitted
The function returns an handle to a connection if it successfully connects the signal to the slot. The Connection handle will be invalid if it cannot create the connection, for example, if QObject is unable to verify the existence of signal (if it was not declared as a signal) You can check if the QMetaObject::Connection is valid by casting it to a bool.
By default, a signal is emitted for every connection you make; two signals are emitted for duplicate connections. You can break all of these connections with a single disconnect() call. If you pass the Qt::UniqueConnection type, the connection will only be made if it is not a duplicate. If there is already a duplicate (exact same signal to the exact same slot on the same objects), the connection will fail and connect will return an invalid QMetaObject::Connection.
The optional type parameter describes the type of connection to establish. In particular, it determines whether a particular signal is delivered to a slot immediately or queued for delivery at a later time. If the signal is queued, the parameters must be of types that are known to Qt's meta-object system, because Qt needs to copy the arguments to store them in an event behind the scenes. If you try to use a queued connection and get the error message
QObject::connect: Cannot queue arguments of type 'MyType'(Make sure 'MyType' is registered using qRegisterMetaType().)make sure to declare the argument type with Q_DECLARE_METATYPE
Overloaded functions can be resolved with help of qOverload.
Note: This function is thread-safe.
See also Differences between String-Based and Functor-Based Connections.
Qt5 新写法的优势及好处见此文:
以下为 原文:
自参。
实现每科目成绩变化后,总成绩自动更新。
即多个QLineEdit 发射 textChanged() 信号,单个槽 (自拟的函数 calc() )接收,实现多对一的连接。
1. Qt原生控件
Qt原生控件,自带有足够的信号。在UI界面中,右击控件,选择“转到槽”,会提示先选择“信号”,我们选择合适的信号即可。
1.1 头文件mainwindow.h
头文件中添加 槽函数声明。注意槽函数参数最好与信号函数的参数保持一致。
//因后面用到 日期和时间,这里需加上对应的头文件
#include <QDate>
#include <QTime>
#include <QDateTime>
...
private slots:
void calc(const QString &mystr);
1.2 类文件 mainwindow.cpp
1.2.1 构造函数 添加 信号与槽的关联 connect
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->lineEdit, SIGNAL(textChanged(QString)), this, SLOT(calc(QString)));
connect(ui->lineEdit_2, SIGNAL(textChanged(QString)), this, SLOT(calc(QString)));
connect(ui->lineEdit_3, SIGNAL(textChanged(QString)), this, SLOT(calc(QString)));
}
注意:
A. 信号函数要用 SIGNAL() 包裹,槽函数要用 SLOT() 包裹。
B. 信号函数可以带有参数,但不用注明返回值类型。
C. 信号函数和槽函数的参数都不用注明参数名称,只需要参数类型。
D. 信号函数和槽函数的参数个数、类型一致。
E. 信号函数可以是 Qt组件的 已定义好的 函数,也可以是自己定义的函数。
1.2.2 槽函数的实现代码
/*
记得在 mainwindow.h 中添加 日期和时间头文件引用
#include <QDate>
#include <QTime>
#include <QDateTime>
*/
void MainWindow::calc(const QString & mystr)
{
// mystr接收信号传出的参数
this->log.append("输入:"+mystr);
this->log.append("\t");
//sum
int chinese = ui->lineEdit->text().toInt();
int math = ui->lineEdit_2->text().toInt();
int english = ui->lineEdit_3->text().toInt();
int sum = chinese + math + english;
this->log.append("总分:"+QString::number(sum));
this->log.append("\t");
if(sum >= 60*3){
ui->labelR->hide();
ui->labelG->show();
this->log.append("总分及格:是");
this->log.append("\t");
}else{
ui->labelG->hide();
ui->labelR->show();
this->log.append("总分及格:否");
this->log.append("\t");
}
this->log.append("时间:"+QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
this->log.append("\n");
ui->textEdit->setText(this->log);
}
1.3 代码下载
Qt5多信号单槽例子.zip-桌面系统文档类资源-CSDN下载
可参考意义不大。编译环境:Qt 5.9.3, Qt Creator 4.4.1, Windows 10 x64。
2. 自定义信号
如果我们需要从某个弹出的窗口中得到数据,这时候 弹出窗口怎么向主窗口发送数据呢。
我们的主界面只有 三门成绩,这时候需要做个 弹出的对话框,弹出的对话框会列出所有学生及其学号、班级等信息,由用户单击选择。再将选中的学生信息 传递给 主窗口。
这时候,就出现了 2个 类: mainWindow 和 dialog。两者不能互相引用和改变对方的控件和数据。这时候他们俩之间的数据传递,就可以使用 自定义的信号。
比如,下面就是实现 对话框中学生被选中,并确定后,将学生的数据发送主窗口。
2.1 头文件dialog.h
对话框类可使用 Qt Creator采用图形化界面创建。
头文件中要声明这个信号。信号的声明与函数声明比较类似。
//因后面用到 日期和时间,这里需加上对应的头文件
#include <QDate>
#include <QTime>
#include <QDateTime>
#include <QFile>
#include <QDialog>
#include <QListWidget>
#include <QListWidgetItem>
#include <QTextStream>
#include <QDebug>
...
signals:
void sendData(QString);
private slots:
void calc(const QString &mystr);
2.2 类文件dialog.cpp
在某个函数中,发射信号。注意,比普通的函数调用,多了个 前缀 emit。
// Qt
void Dialog::on_buttonBox_accepted()
{
//此处省略选择学生的操作
//假设已经选中并得到学生姓名为 李四
QString stuName = "李四"
//发射信号
emit sendData(stuName);
}
2.3 主窗口类头文件 mainwindow.h
声明对话框对象。声明接收信号的槽。槽的声明和 函数声明比较相似。
// Qt5
#include <QMainWindow>
#include <QMessageBox>
#include <QFile>
#include <QDialog>
#include <QListWidget>
#include <QListWidgetItem>
#include "dialog.h" //记得引用对话框头文件
//...
private:
Ui::Pressure *ui;
QDialog *dlg;
private slots:
void receiveData(QString data)
2.4 主窗口类文件 mainwindow.cpp
在类初始化的时候,创建对话框对象,并建立信号与槽的关联。
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//信号槽方式下父子窗体传值的测试
MainWindow::dlg = new Dialog;
//关联信号和槽函数
connect(dlg,SIGNAL(sendData(QString)),this,SLOT(receiveData(QString)));
// dlg->setModal(true); 不论是模态或者非模态都可以正常传值
//dlg->show();
}