看的书是Qt5.9,但书上却用的Qt4中的通用用法:SIGNAL和SLOT宏,
不过,书后面却又给了一种传递信号和槽函数地址的用法(Qt5的用法),但是这本书的作者在这块却说的不好,如下图:
首先要知道,信号也是一个函数,它也可以像一般的函数一样进行重载。
1.没有对信号进行重载时,可以直接这样用,因为就这一个信号函数,不存在二义性的问题,即编译器不用纠结传入的到底是哪个函数的地址。
2. 但是当我们对信号进行重载时,就不能直接这样了,因为此时会有一个二义性的问题,即编译器会纠结传入的到底是哪个函数的地址。那这个时候怎么办呢?
就拿书上我画黄线的这个例如来说吧,Qt把QSpinBox的valueChanged这个信号重载了一次,也就是现在有两个同名的函数了,那我们可以定义两个函数指针啊,分别指向这两个函数,那么想连接哪个信号,就向connect中传入哪个信号对应的函数指针。这样就没有二义性的问题了,因为编译器知道了你传入的是哪个函数
。
void (QSpinBox::*p1_valueChanged) (int) = &QSpinBox::valueChanged;
void (QSpinBox::*p2_valueChanged) (const QString &) = &QSpinBox::valueChanged;
和我们平时定义函数指针不同的地方在于:在这里定义一个指向类的成员函数的指针时,需要在前面指定一下这个函数指针它属于哪个类。
那么,就可以这样把信号与槽连接起来了:
connect(spinNum, p1_valueChanged, this, &widget::onValueChanged);
或者
connect(spinNum, p2_valueChanged, this, &widget::onValueChanged);
另外,这个槽函数也可以像信号一样重载,然后再分别定义对应的函数指针,再向connect中传递对应的函数指针。反正都同理啦。
所以当重载信号时,并非像这书上说的那样,不能用那种方法了,还是向connect中传信号函数地址,只是你要传一个指定好了的信号函数的地址,不然就会有二义性,程序会出错!
还有就是,我用那个SIGNAL和SLOT来整,信号与槽老是连接不上,也不报个错。。。
我只是觉得书上这一块没说好,自己也顺带写篇推文记一下,没有说这书不好的意思
,主要还是做一个学习笔记。
那么下面通过一个例子来试试,这里我重载的是一个自定义的信号。
例子
(在QtCreater上编写的)
内容:做两个窗口,两个窗口上个一个按钮,点击哪个窗口上的按钮,就隐藏哪个窗口,然后显示另一个窗口。
思路:让一个窗口成为主窗口,在主窗口的类中实例化另一个窗口(子窗口)。在主窗口中点击按钮隐藏子窗口,这好办。但在子窗口中点击按钮隐藏主窗口,还是得折腾一下。可以在子窗口中点击按钮时,往外面发射一个信号,在主窗口的类中把这个信号与一个槽函数连接一下就行了。所以这就需要自定义一个信号了。
上面讲的内容都在代码中加粗了,并以更大号的字体标出来了!
头文件
1. 声明主窗口类的头文件:widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include "subwindow.h"
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private:
//私有成员变量
QPushButton* btn;
SubWindow subW;
//私有成员函数
void setupUI(); //初始化主窗口函数
void showSubWindow(); //
void btn1_sub(); //
void btn2_sub(int i, QString s); //
};
#endif // WIDGET_H
2. 声明子窗口类的头文件:subwindow.h
#ifndef SUBWINDOW_H
#define SUBWINDOW_H
#include
#include
class SubWindow : public QWidget
{
Q_OBJECT
public:
explicit SubWindow(QWidget *parent = nullptr);
private:
//私有成员变量
QPushButton *btn1;
QPushButton *btn2;
//私有成员函数
void setupUI(); //初始化子窗口函数
void btn1_clicked(); //点击按钮1后要执行的那个槽函数(在槽函数中发射第一个重载信号)
void btn2_clicked(); //点击按钮1后要执行的那个槽函数(在槽函数中发射第一个重载信号)
signals:
//自定义信号,必须使用signals声明。这里重载了一个
void sig_showMainWindow();
void sig_showMainWindow(int, QString);
public slots:
//槽函数也就是一个函数,所以直接在成员函数那写就行,这里可以不写
};
#endif // SUBWINDOW_H
源文件
1. 定义主窗口类的头文件:widget.cpp
#include "widget.h"
#include
//默认构造函数
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
Widget::setupUI(); //在构造函数中调用初始化主窗口的函数
}
Widget::~Widget()
{
}
//定义初始化主窗口的函数
void Widget::setupUI()
{
//设置主窗口相关的参数
this->resize(400, 600);
this->move(500, 200);
this->setWindowTitle("Main Window");
//在主窗口中创建一个按钮,设置相关参数,连接信号与槽
btn = new QPushButton("隐藏主窗口,显示子窗口", this);
btn->resize(300, 50);
btn->move(50, 250);
connect(btn, &QPushButton::clicked, this, &Widget::showSubWindow);
//分别定义那两个指向自定义信号函数的指针
void (SubWindow::*p1_sig_hideMainWindow) () = &SubWindow::sig_showMainWindow;
void (SubWindow::*p2_sig_hideMainWindow) (int, QString) = &SubWindow::sig_showMainWindow;
//连接自定义信号和其对应的槽函数
connect(&this->subW, p1_sig_hideMainWindow,
this, &Widget::btn1_sub);
connect(&this->subW, p2_sig_hideMainWindow,
this, &Widget::btn2_sub);
}
//主窗口中那个按钮点击信号对应的槽函数
void Widget::showSubWindow()
{
this->hide();
this->subW.show();
}
//子窗口中点击第一个按钮发射出的信号所对应的槽函数(发射的第一个重载的信号)
void Widget::btn1_sub()
{
this->show();
this->subW.hide();
}
//子窗口中第二个按钮发射出的信号所对应的槽函数(发射的第二个重载的信号)
void Widget::btn2_sub(int i, QString s)
{
this->show();
this->subW.hide();
//打印一下发射出的信号所携带的信息
qDebug() <
}
2. 定义子窗口类的头文件:subwindow.cpp
#include "subwindow.h"
//默认构造函数
SubWindow::SubWindow(QWidget *parent) : QWidget(parent)
{
SubWindow::setupUI(); //在构造函数中调用初始化子窗口的函数
}
//定义初始化子窗口的函数
void SubWindow::setupUI()
{
//设置子窗口的相关参数
this->resize(400, 600);
this->move(900, 200);
this->setWindowTitle("Sub Window");
//创建一个按钮,点击它用于发射第一个重载的信号
btn1 = new QPushButton("Show sub window, Hide main window", this);
btn1->resize(300, 50);
btn1->move(50, 200);
btn1->setText("第一个重载信号");
//连接信号与槽
connect(btn1, &QPushButton::clicked, this, &SubWindow::btn1_clicked);
//创建一个按钮,点击它用于发射第二个重载的信号
btn2 = new QPushButton("Show sub window, Hide main window", this);
btn2->resize(300, 50);
btn2->move(50, 300);
btn2->setText("第二个重载信号");
//连接信号与槽
connect(btn2, &QPushButton::clicked, this, &SubWindow::btn2_clicked);
}
//第一个按钮的槽函数
void SubWindow::btn1_clicked()
{
emit this->sig_showMainWindow();
}
//第二个按钮的槽函数
void SubWindow::btn2_clicked()
{
emit this->sig_showMainWindow(1, this->btn2->text());
}
3. main函数:main.cpp
#include "widget.h"
#include
int main(int argc, char *argv[]){
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
结果演示
(不知道画质为啥这么差)
[1] 王维波 栗宝鹃 侯春望. Qt5.9 C++ 开发指南[M].
赶在24点前发出去,为了明天把这个例子用matlab做一下,再发一篇推文。所以推文没多读几遍,可能不少地方表达的不通顺
--END--