有时候我们可能遇到一个问题,我们想在A类里面定义一个事件,当这个事件被触发之后,它可以发射一个信号出来,让B,C,D类等其他类去执行一个功能,这些执行功能的类可能是一个QWidget类,或者是一个普通的类,我们可能遇到的问题是怎么让一个信号和槽跨越几个类?
最难的是,如果这些类之间有相互include的关系,比如A中的按钮单击之后,打开了B窗口,因此A类必须include B的头文件。而如果要利用A类发射其他信号来更改B类的一些特性,就需要在B类建立一个信号槽,而且B类要include A类的头文件,以使得信号槽的发送者可以查到。
从一个简单的例子开始讲起:
我们在VS中新建一个基于QMainwindow的工程,名为qt_signal_test,然后在Mainwindow中添加一个按钮,运行后界面为:
/// main.cpp ///
#include "qt_signal_test.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qt_signal_test w;
w.show();
return a.exec();
}
qt_signal_test.h /
#ifndef QT_SIGNAL_TEST_H
#define QT_SIGNAL_TEST_H
#include <QtWidgets/QMainWindow>
#include "ui_qt_signal_test.h"
#include "qpushbutton.h"
#include "qlabel.h"
class qt_signal_test : public QMainWindow
{
Q_OBJECT
public:
qt_signal_test(QWidget *parent = 0);
~qt_signal_test();
QPushButton *button;
QLabel *label;
private:
Ui::qt_signal_testClass ui;
};
#endif // QT_SIGNAL_TEST_H
qt_signal_test.cpp /
#include "qt_signal_test.h"
qt_signal_test::qt_signal_test(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
this->setGeometry(200, 200, 400, 400);
button = new QPushButton(this);
label = new QLabel(this);
button->setGeometry(50, 50, 60, 30);
label->setGeometry(100, 100, 60, 30);
button->setText(QString::fromLocal8Bit("确定"));
label->setText(QString::fromLocal8Bit("等待"));
}
qt_signal_test::~qt_signal_test()
{
}
我们新建一个关于button的槽函数,单击一次,label的文本就变化了。
qt_signal_test.h //
#ifndef QT_SIGNAL_TEST_H
#define QT_SIGNAL_TEST_H
#include <QtWidgets/QMainWindow>
#include "ui_qt_signal_test.h"
#include "qpushbutton.h"
#include "qlabel.h"
class qt_signal_test : public QMainWindow
{
Q_OBJECT
public:
qt_signal_test(QWidget *parent = 0);
~qt_signal_test();
QPushButton *button;
QLabel *label;
private:
Ui::qt_signal_testClass ui;
public slots:
void changeMyText();
};
#endif // QT_SIGNAL_TEST_H
qt_signal_test.cpp /
#include "qt_signal_test.h"
qt_signal_test::qt_signal_test(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
this->setGeometry(200, 200, 400, 400);
button = new QPushButton(this);
label = new QLabel(this);
button->setGeometry(50, 50, 60, 30);
label->setGeometry(100, 100, 60, 30);
button->setText(QString::fromLocal8Bit("确定"));
label->setText(QString::fromLocal8Bit("等待"));
connect(button, &QPushButton::clicked, this, &qt_signal_test::changeMyText);
}
qt_signal_test::~qt_signal_test()
{
}
void qt_signal_test::changeMyText()
{
label->setText(QString::fromLocal8Bit("您单击了!"));
}
我们新建一个MyWindow类,继承在QMainwindow,修改qt_signal_test的界面,使之包含两个按钮,一个是用于打开新窗体(MyWindow对象),一个用于给MyWindow上的label控件触发的按钮。同时将qt_signal_test上的label控件删去,移至MyWindow上,在qt_signal_test类内新增一个MyWindow窗体对象mywindow,并添加一个槽函数,使得单击打开按钮后,可以让这个对象窗口显示。
qt_signal_test.h //
#ifndef QT_SIGNAL_TEST_H
#define QT_SIGNAL_TEST_H
#include <QtWidgets/QMainWindow>
#include "ui_qt_signal_test.h"
#include "qpushbutton.h"
#include "mywindow.hpp"
class qt_signal_test : public QMainWindow
{
Q_OBJECT
public:
qt_signal_test(QWidget *parent = 0);
~qt_signal_test();
QPushButton *button;
QPushButton *button_2;
MyWindow mywindow;
private:
Ui::qt_signal_testClass ui;
public slots:
void openNewWindow();
};
#endif // QT_SIGNAL_TEST_H
qt_signal_test.cpp /
#include "qt_signal_test.h"
qt_signal_test::qt_signal_test(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
this->setGeometry(200, 200, 400, 400);
button = new QPushButton(this);
button->setGeometry(50, 50, 60, 30);
button->setText(QString::fromLocal8Bit("确定"));
button_2 = new QPushButton(this);
button_2->setGeometry(130, 50, 60, 30);
button_2->setText(QString::fromLocal8Bit("打开"));
connect(button_2, &QPushButton::clicked, this, &qt_signal_test::openNewWindow);
}
qt_signal_test::~qt_signal_test()
{
}
void qt_signal_test::openNewWindow()
{
mywindow.show();
}
// mywindow.hpp ///
#pragma once
#include <QMainWindow>
#include "ui_mywindow.h"
#include "qlabel.h"
class MyWindow : public QMainWindow {
Q_OBJECT
public:
MyWindow(QWidget * parent = Q_NULLPTR);
~MyWindow();
QLabel *label;
private:
Ui::MyWindow ui;
public slots:
void changeMyText();
};
// mywindow.cpp ///
#include "mywindow.hpp"
MyWindow::MyWindow(QWidget * parent) : QMainWindow(parent) {
ui.setupUi(this);
this->setGeometry(700, 200, 400, 400);
label = new QLabel(this);
label->setGeometry(100, 100, 60, 30);
label->setText(QString::fromLocal8Bit("等待"));
//connect(button, &QPushButton::clicked, this, &MyWindow::changeMyText);
}
MyWindow::~MyWindow() {
}
void MyWindow::changeMyText()
{
label->setText(QString::fromLocal8Bit("您单击了!"));
}
我希望实现的功能就是我在第一个窗体上单击“确定”,可以让第二个窗体上的控件上的文字改变。
我们试着把mywindow.cpp的第9行的注释去掉,发现它报错。
我们要将第一个qt_signal_test类的对象做成一个全局变量,怎么做呢?
main.cpp //
#include "qt_signal_test.h"
#include <QtWidgets/QApplication>
qt_signal_test *singal_test;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
singal_test = new qt_signal_test;
singal_test->show();
return a.exec();
}
qt_signal_test.h //
#ifndef QT_SIGNAL_TEST_H
#define QT_SIGNAL_TEST_H
#include <QtWidgets/QMainWindow>
#include "ui_qt_signal_test.h"
#include "qpushbutton.h"
#include "mywindow.hpp"
class qt_signal_test : public QMainWindow
{
Q_OBJECT
public:
qt_signal_test(QWidget *parent = 0);
~qt_signal_test();
QPushButton *button;
QPushButton *button_2;
MyWindow mywindow;
private:
Ui::qt_signal_testClass ui;
public slots:
void openNewWindow();
};
extern qt_signal_test *singal_test;
#endif // QT_SIGNAL_TEST_H
// mywindow.hpp ///
#pragma once
#include <QMainWindow>
#include "ui_mywindow.h"
#include "qlabel.h"
class MyWindow : public QMainWindow {
Q_OBJECT
public:
MyWindow(QWidget * parent = Q_NULLPTR);
~MyWindow();
QLabel *label;
private:
Ui::MyWindow ui;
public slots:
void changeMyText();
};
// mywindow.cpp ///
#include "mywindow.hpp"
#include "qt_signal_test.h"
MyWindow::MyWindow(QWidget * parent) : QMainWindow(parent) {
ui.setupUi(this);
this->setGeometry(700, 200, 400, 400);
label = new QLabel(this);
label->setGeometry(100, 100, 60, 30);
label->setText(QString::fromLocal8Bit("等待"));
connect(singal_test->button, &QPushButton::clicked, this, &MyWindow::changeMyText);
}
MyWindow::~MyWindow() {
}
void MyWindow::changeMyText()
{
label->setText(QString::fromLocal8Bit("您单击了!"));
}
我们发现,程序运行报错,为什么呢?
这是因为mywindow和qt_signal_test两个类的头文件相互包含了。
怎么解决的?
main.cpp //
#include "qt_signal_test.h"
#include "mywindow.hpp"
#include <QtWidgets/QApplication>
qt_signal_test *singal_test;
MyWindow *mywindow;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
singal_test = new qt_signal_test;
mywindow = new MyWindow;
singal_test->show();
return a.exec();
}
qt_signal_test.h //
#ifndef QT_SIGNAL_TEST_H
#define QT_SIGNAL_TEST_H
#include <QtWidgets/QMainWindow>
#include "ui_qt_signal_test.h"
#include "qpushbutton.h"
#include "mywindow.hpp"
class qt_signal_test : public QMainWindow
{
Q_OBJECT
public:
qt_signal_test(QWidget *parent = 0);
~qt_signal_test();
QPushButton *button;
QPushButton *button_2;
private:
Ui::qt_signal_testClass ui;
public slots:
void openNewWindow();
};
extern qt_signal_test *singal_test;
#endif // QT_SIGNAL_TEST_H
qt_signal_test.cpp //
#include "qt_signal_test.h"
qt_signal_test::qt_signal_test(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
this->setGeometry(200, 200, 400, 400);
button = new QPushButton(this);
button->setGeometry(50, 50, 60, 30);
button->setText(QString::fromLocal8Bit("确定"));
button_2 = new QPushButton(this);
button_2->setGeometry(130, 50, 60, 30);
button_2->setText(QString::fromLocal8Bit("打开"));
connect(button_2, &QPushButton::clicked, this, &qt_signal_test::openNewWindow);
}
qt_signal_test::~qt_signal_test()
{
}
void qt_signal_test::openNewWindow()
{
mywindow->show();
}
// mywindow.hpp ///
#pragma once
#include <QMainWindow>
#include "ui_mywindow.h"
#include "qlabel.h"
#include "qpushbutton.h"
#include "qt_signal_test.h"
class MyWindow : public QMainWindow {
Q_OBJECT
public:
MyWindow(QWidget * parent = Q_NULLPTR);
~MyWindow();
QLabel *label;
private:
Ui::MyWindow ui;
public slots:
void changeMyText();
};
extern MyWindow *mywindow;
// mywindow.cpp ///
#include "mywindow.hpp"
MyWindow::MyWindow(QWidget * parent) : QMainWindow(parent) {
ui.setupUi(this);
this->setGeometry(700, 200, 400, 400);
label = new QLabel(this);
label->setGeometry(100, 100, 60, 30);
label->setText(QString::fromLocal8Bit("等待"));
connect(singal_test->button, &QPushButton::clicked, this, &MyWindow::changeMyText);
}
MyWindow::~MyWindow() {
}
void MyWindow::changeMyText()
{
label->setText(QString::fromLocal8Bit("您单击了!"));
}
我们也可以自己定义信号,比如
qt_signal_test.h //
#ifndef QT_SIGNAL_TEST_H
#define QT_SIGNAL_TEST_H
#include <QtWidgets/QMainWindow>
#include "ui_qt_signal_test.h"
#include "qpushbutton.h"
#include "mywindow.hpp"
class qt_signal_test : public QMainWindow
{
Q_OBJECT
public:
qt_signal_test(QWidget *parent = 0);
~qt_signal_test();
QPushButton *button;
QPushButton *button_2;
private:
Ui::qt_signal_testClass ui;
public slots:
void jifa();
signals:
void xianshi();
};
extern qt_signal_test *singal_test;
#endif // QT_SIGNAL_TEST_H
qt_signal_test.cpp //
#include "qt_signal_test.h"
qt_signal_test::qt_signal_test(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
this->setGeometry(200, 200, 400, 400);
button = new QPushButton(this);
button->setGeometry(50, 50, 60, 30);
button->setText(QString::fromLocal8Bit("确定"));
button_2 = new QPushButton(this);
button_2->setGeometry(130, 50, 60, 30);
button_2->setText(QString::fromLocal8Bit("打开"));
connect(button_2, &QPushButton::clicked, this, &qt_signal_test::jifa);
}
qt_signal_test::~qt_signal_test()
{
}
void qt_signal_test::jifa()
{
emit xianshi();
}
// mywindow.cpp ///
#include "mywindow.hpp"
MyWindow::MyWindow(QWidget * parent) : QMainWindow(parent) {
ui.setupUi(this);
this->setGeometry(700, 200, 400, 400);
label = new QLabel(this);
label->setGeometry(100, 100, 60, 30);
label->setText(QString::fromLocal8Bit("等待"));
connect(singal_test, &qt_signal_test::xianshi, this, &MyWindow::changeMyText);
}
MyWindow::~MyWindow() {
}
void MyWindow::changeMyText()
{
mywindow->show();
label->setText(QString::fromLocal8Bit("您单击了!"));
}