QT5 之信号与槽机制(演示控件自带的信号与槽函数关联)
演示控件自带的信号与槽函数的关联
之前手动关联信号槽的例子中,按钮的信号 clicked() 是Qt库自带的,而槽函数是手动编写的。Qt 库各种窗体控件都带有预先定义好的信号和槽函数,这篇文章将使用 Qt 文本编辑控件和标签控件的信号和槽函数,实现信号和槽的一对一关联、一对多关联和多对一关联。在声明匹配的情况下,信号和槽的关联是非常自由的。Qt 的信号和槽函数不仅能实现关联,也能在运行时解除关联。
1.5.1 一对一关联示例
本小节的例子就是在窗口里放置一个单行文本编辑器(QLineEdit)和一个标签控件(QLabel),实现的效果就是当编辑器的内容被编辑时,标签控件同步显示编辑控件里的内容,就是标签内容与文本编辑器同步显示。
打开 QtCreator,新建一个 Qt Widgets Application 项目,在新建项目的向导里填写:
①项目名称 QT_x,创建路径 D:\QT_XX,点击下一步;
②套件选择里面选择全部套件,点击下一步;
③基类选择 MainWindow,其他的选项默认,点击下一步;
④项目管理不修改,点击完成。
建立好项目之后,打开mainwindow.ui文件。在设计窗口里加入一个单行文本编辑器和一个标签控件,拖动这两个控件的边框,可以改变该控件的大小。
效果图:
默认这两个控件对象名字分别为 lineEdit (单行编辑器)和 label(标签),编辑好后保存。当 lineEdit 控件被用户编辑时,它会发出信号:
void textEdited(const QString & text); |
信号源头已经有了,接收端是标签控件,我们希望标签控件自动同步修改文本,标签控件自带槽函数:
void setText(const QString &); |
之前我们一直用这个槽函数当普通成员函数来修改标签控件文本,其实它本质是一个槽函数。接收端的槽函数也是 Qt 库自带的,我们需要做的就是把它们关联起来。
只需要在窗体构造函数加一个 connect 函数调用就行了,手动修改后的mainwindow.cpp文件内容如下:
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); //关联单行编辑控件的信号到标签控件的槽函数 connect(ui->lineEdit, SIGNAL(textEdited(QString)), ui->label, SLOT(setText(QString))); } MainWindow::~MainWindow() { delete ui; } |
源头控件 lineEdit 的信号是 Qt 库自带的,接收端控件 label 的槽函数也是 Qt 库自带的,我们只需要添加 connect 函数调用关联它们就行了。
connect 关联之后,当源头发出信号时,接收端的槽函数就会自动被调用,信号里的参数值也会自动传递给槽函数。
SIGNAL 宏包裹的信号名称与 Qt 帮助文档里的声明稍有差异,实际使用时按照代码编辑器根据 "SIGNAL(" 自动提示的信号名称。SLOT 宏包裹的槽函数名称也是类似的,一般都按照代码编辑器自动提示的名称。
代码编辑好之后,点击 QtCreator 左下角绿色三角形运行按钮,在窗体编辑框输入文本,测试代码运行效果:
程序刚开始运行的时候,编辑框是空白,标签默认显示 TextLabel 字样。当我们在编辑框输入文本,标签控件是完全同步的,如果删除编辑框的文本,标签控件也是同步删除相应的文本。
刚才的示例非常简单,现在有一个问题,怎么知道单行编辑控件、标签控件等有哪些信号和槽函数呢?
最好的办法就是查阅 Qt自带的帮助文档,在帮助界面查找框里输入 QLineEdit ,可以跳转到 QLineEdit对应的文档界面,在帮助文档界面的右边有当前文档的目录Contents。
注意:查找帮助文档时,需要在控件名称前加一个大写的“Q”,加上“Q”才是类名。
效果图:
目录里的“Signals”链接就是信号列表,“Public Slots”就是可用的槽函数列表。
效果图:
QLabel 控件,也可以查它的帮助文档。
效果图:
目录里的“Signals”链接就是信号列表,“Public Slots”就是当前类可用的槽函数列表。
效果图:
编程遇到问题首先要查看帮助文档,帮助文档才是最好的工具。
1.5.2 一对多关联示例
这一小节在窗体里放置一个单行文本编辑控件(QLineEdit)、一个标签控件(QLabel)和一个文本浏览控件(QTextBrowser)。单行文本编辑控件里的文本被编辑时,标签控件和文本浏览控件都会同步显示新的文本。另外还自定义了一个槽函数,同步打印文本的变化到调试输出面板里。
例子程序将示范把单行文本编辑控件的信号同时关联到五个槽函数。
打开 QtCreator,新建一个 Qt Widgets Application 项目,在新建项目的向导里填写:
①项目名称 QT_x,创建路径 D:\QT_XX,点击下一步;
②套件选择里面选择全部套件,点击下一步;
③基类选择 MainWindow,其他的选项默认,点击下一步;
④项目管理不修改,点击完成。
建好项目之后,打开窗体 mainwindow.ui 文件,进入设计模式,向窗体拖入 Line Edit、Label、Text Browser 控件各一个,并大致调整一下控件位置和大小。
效果图:
这时三个控件对象名称默认为 lineEdit、label、textBrowser,就用默认的名字,编辑好界面之后保存。这时信号的源头是单行文本编辑控件,接收端有标签控件和文本浏览控件。
现在回到 QtCreator 代码编辑模式,打开 mainwindow.h头文件,添加自定义的槽函数声明,用于打印文本到输出面板:
代码如下:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); public slots: //添加槽函数打印调试信息 void PrintText(const QString& text); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H |
头文件编辑好之后,再编辑mainwindow.cpp源 文件:
代码如下:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); //关联信号到槽函数 //接收端是标签控件 connect(ui->lineEdit, SIGNAL(textEdited(QString)), ui->label, SLOT(setText(QString))); //接收端是文本浏览控件 connect(ui->lineEdit, SIGNAL(textEdited(QString)), ui->textBrowser, SLOT(setText(QString))); //接收端是主窗口的 PrintText 槽 connect(ui->lineEdit, SIGNAL(textEdited(QString)), this, SLOT(PrintText(QString))); } MainWindow::~MainWindow() { delete ui; } void MainWindow::PrintText(const QString &text) { qDebug()<<text; //打印到调试输出面板 } |
mainwindow.cpp 文件开头增加了头文件包含 <QDebug>。在构造函数里,增加了三行 connect 函数调用:
第一个是将 lineEdit 的编辑信号关联到 label 的设置文本槽函数;
第二个是将 lineEdit 的编辑信号关联到 textBrowser 的设置文本槽函数;
第三个是将 lineEdit 的编辑信号关联到主窗体的 PrintText 槽函数。
PrintText 槽函数的定义代码非常简单,就是将获取的 text 文本打印到调试输出面板。虽然 PrintText 函数定义和声明里的参数看起来有点复杂,在关联函数位置只需要按照 QtCreator 编辑器的代码补全功能自动提示的槽函数名称即可。比如
connect(ui->lineEdit, SIGNAL(textEdited(QString)), this, SLOT(PrintText(QString))); |
槽函数 PrintText 参数里只需要类型名 QString 就够了,信号 textEdited 的参数也是类似的。
如果用 Qt5 新式的关联语法,就如下面示例的这句:
connect(ui->lineEdit, &QLineEdit::textEdited, this, & MainWindow::PrintText); |
代码编辑完毕之后,点击 QtCreator软件左下角的运行按钮,就可以测试代码运行的效果:
效果图:
观察代码的运行结果,三个关联函数都是正常工作的,单行编辑控件文本被编辑之后,窗体里的标签控件和文本浏览控件都是同步显示,在输出面板也是可以看到文本同步打印的。
1.5.3 多对一关联示例
本小节主要是创建三个按钮,分别点击不同的按钮,会弹出不同的信息。需要注意本小节的示例程序,只用了一个槽函数,三个按钮名称不一样,分别点击按钮时,弹出的内容也不一样。
下面开始完成这个示例程序:
打开 QtCreator,新建一个 Qt Widgets Application 项目,在新建项目的向导里填写:
①项目名称 QT_x,创建路径 D:\QT_XX,点击下一步;
②套件选择里面选择全部套件,点击下一步;
③基类选择 MainWindow,其他的选项默认,点击下一步;
④项目管理不修改,点击完成。
建好项目之后,打开窗体 mainwindow.ui 文件,进入设计模式,向窗体拖入3个pushButton控件,调整一下控件位置和大小。将3个按钮控件分别命名为pushButton_1 ,pushButton_2 ,pushButton_3,弹窗显示的内容分别为:Push the button 1,Push the button 2,Push the button 3。
效果图:
pushButton_1 ,pushButton_2 ,pushButton_3三个按钮作为信号源,编辑好之后保存。接下来编写接收信号的槽函数。
回到 QtCreator 代码编辑模式,打开头文件 mainwindow.h,添加槽函数声明。
示例代码:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); public slots: //声明槽函数进行弹窗 void SlotsFunctions_popup(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H |
上边示例代码中SlotsFunctions_popup函数就是我们添加的槽函数,接着打开mainwindow.cpp文件关联信号到槽函数并实现槽函数功能。
示例代码:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QMessageBox> //对话框头文件 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); //将三个按钮的信号都关联到 SlotsFunctions_popup 槽函数 connect(ui->pushButton_1, SIGNAL(clicked()), this, SLOT(SlotsFunctions_popup())); connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(SlotsFunctions_popup())); connect(ui->pushButton_3, SIGNAL(clicked()), this, SLOT(SlotsFunctions_popup())); } MainWindow::~MainWindow() { delete ui; } //槽函数实现 void MainWindow::SlotsFunctions_popup() { //获取信号源头对象的名称 QString objectName_string = this->sender()->objectName(); //将要显示的消息 QString show_info; //判断是哪个按钮发的信号 if( objectName_string == "pushButton_1") { show_info = tr("Push the button 1"); } else if( objectName_string == "pushButton_2") { show_info = tr("Push the button 2"); } else if( objectName_string == "pushButton_3") { show_info = tr("Push the button 3"); } else { //没有按钮按下 return; } //显示弹窗信息 QMessageBox::information(this, tr("message"), show_info); } |
mainwindow.cpp 里面添加了 <QMessageBox>头文件,需要用到对话框。
在主窗口类的构造函数里,将三个按钮的 clicked() 信号都关联到 SlotsFunctions_popup () 槽函数,这就是多个信号关联到同一个槽函数的范例。
我们要实现分别点击不同的按钮,弹出不同信息的对话框,这就需要在程序运行时判断哪个按钮发出的信号。当一个信号触发了它关联的槽函数时,可以在该槽函数里通过 sender() 函数来获取发送信号的源头对象,该函数返回源头信号指针,sender() 函数的声明如下:
QObject * QObject::sender() const |
sender() 函数是个 [protected] 保护类型的函数,在该类及其派生类之外是不能访问的。该函数返回通用基类 QObject * 指针,可以通过 QObject 类对象的 objectName() 函数获取该对象的名称。
SlotsFunctions_popup()函数实现的过程:
首先获取发送信号的源头对象名称,然后根据对象名称进行匹配:
如果源头对象名称是 pushButton_1,就设置消息框显示的信息为Push the button 1;
如果源头对象名称是 pushButton_2,就设置消息框显示的信息为Push the button 2;
如果源头对象名称是 pushButton_3,就设置消息框显示的信息为Push the button 3;
最后如果三个都不符合,就直接返回,不进行弹窗。
设置好显示的信息之后,就调用 QMessageBox::information 函数显示相应的文本消息框。
代码中的tr函数是用来实现国际化字符串,Qt5 规定源文件字符编码是 UTF-8,也可以用trUtf8()函数来实现。
QObject::tr() QObject:: trUtf8() |
代码编辑完毕后,点击 QtCreator 左下角的绿色运行按钮,测试代码运行的效果:
测试结果,点击不同的按钮,弹窗将显示当前按下按钮的名称。
1.5.4 解除关联示例
关联好的源端信号和接收端的槽函数,如果不需要用到它们的关联关系,可以使用 disconnect 函数解除之前的关联关系。disconnect 函数与 connect 函数功能相反,两个函数的参数差不多。
QT5以前旧式语法:
bool QObject::disconnect(const QObject * sender, const char * signal, const QObject * receiver, const char * method) |
QT5新式语法:
bool QObject::disconnect(const QObject * sender, PointerToMemberFunction signal, const QObject * receiver, PointerToMemberFunction method) |
通过disconnect 函数的返回值可以判断解除关联是否执行成功
本小节将示范“关联”和“解除关联”的实现过程。
下面开始完成这个示例程序:
打开 QtCreator,新建一个 Qt Widgets Application 项目,在新建项目的向导里填写:
①项目名称 QT_x,创建路径 D:\QT_XX,点击下一步;
②套件选择里面选择全部套件,点击下一步;
③基类选择 MainWindow,其他的选项默认,点击下一步;
④项目管理不修改,点击完成。
建好项目之后,打开窗体 mainwindow.ui 文件,进入设计模式,向编辑窗口添加两个pushButton(按钮)控件,一个textBrowser(文本浏览)控件,一个label(标签)控件,一个lineEdit(单行编辑控件)控件。修改按钮控件的对象名称分别为pushButton_1和pushButton_2,按钮控件的名称修改为”解除关联”和“关联”,其他控件的名字默认不修改。
效果图:
我们要实现 lineEdit(单行编辑控件)的内容与文本浏览控件和标签控件同步显示,然后通过按钮进行解除解除关联和设置关联关系。 两个按钮的槽函数可以通过软件自动生成,我们只需要写单行编辑控件信号、标签控件、文本浏览控件设置关联和解除关联的槽函数。
在设计模式里选中按钮,右键菜单里点击“转到 槽...”,为两个按钮都添加各自的clicked()槽函数。
效果图:
两个按钮的槽函数添加后,mainwindow.h文件会自动生成槽函数的声明:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: //自动生成的槽函数明 void on_pushButton_1_clicked(); void on_pushButton_2_clicked(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H |
mainwindow.h文件的代码不需要进行修改,只需要修改mainwindow.c的代码,来实现单行编辑控件信号和标签控件槽函数的关联与解除关联。
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); /* *最开始先调用槽函数进行关联 *按钮的槽函数可以当作普通函数来调用。 */ on_pushButton_2_clicked();//实现关联 } MainWindow::~MainWindow() { delete ui; } //按钮1的槽函数 void MainWindow::on_pushButton_1_clicked() { //解除关联 disconnect(ui->lineEdit, SIGNAL(textEdited(QString)), ui->label, SLOT(setText(QString))); disconnect(ui->lineEdit, SIGNAL(textEdited(QString)), ui->textBrowser, SLOT(setText(QString))); //调整按钮可用性 ui->pushButton_1->setEnabled(false); //按钮1不可用---解除不关联可用 ui->pushButton_2->setEnabled(true); //按钮2可用-----关联可用 } //按钮2的槽函数 void MainWindow::on_pushButton_2_clicked() { //关联 connect(ui->lineEdit, SIGNAL(textEdited(QString)), ui->label, SLOT(setText(QString))); connect(ui->lineEdit, SIGNAL(textEdited(QString)), ui->textBrowser, SLOT(setText(QString))); //调整按钮可用性 ui->pushButton_1->setEnabled(true); //按钮1可用---解除关联可用 ui->pushButton_2->setEnabled(false); //按钮2不可用----关联不可用 } |
解除关联按钮对应的槽函数为 :on_pushButton_1_clicked
关联按钮对应的槽函数为 :on_pushButton_2_clicked
在构造函数里面调用on_pushButton_2_clicked是作为普通成员函数调用,主要是一开始就实现单行编辑控件和标签控件的文本同步,并且设置两个按钮的可用性。
on_pushButton_1_clicked函数代码解析:
1) disconnect 函数将单行编辑控件的 textEdited(QString) 信号与标签控件的 setText(QString) 槽函数解除关联。
2) disconnect 函数将单行编辑控件的 textEdited(QString) 信号与文本浏览控件的 setText(QString) 槽函数解除关联。
3) 设置按钮控件的可用性, setEnabled 函数接收一个 bool 参数,如果为 true,按钮就可用,能被点击;如果参数为 false,按钮被禁用,无法点击。当调用这个函数时,说明已经解除了关联,所以设置按钮1(解除关联)不可用。
4) 设置按钮2(关联)可用。
on_pushButton_2_clicked函数代码解析:
1) connect 函数将单行编辑控件的 textEdited(QString) 信号关联到标签控件的setText(QString) 槽函数,当单行编辑控件的文本被用户修改时,标签控件槽函数会被自动调用,根据传递的文本字符串设置标签控件文本,自动与单行编辑控件文本同步。
2) disconnect 函数将单行编辑控件的 textEdited(QString) 信号关联到文本浏览控件的 setText(QString) 槽函数,当单行编辑控件的文本被用户修改时,文本浏览控件槽函数会被自动调用,显示内容自动与单行编辑控件文本同步。
剩下两行设置按钮权限的代码与on_pushButton_1_clicked函数里实现的概念一样。
disconnect 函数可以把之前的关联关系解除掉,disconnect 函数语法和 connect 函数语法基本一样,只是多了 dis 三个字母。
代码编辑完毕后,点击 QtCreator 左下角的绿色运行按钮,测试代码运行的效果:
关联之后,编辑单行编辑器的内容时,下边的两个控件显示内容与单行编辑器同步:
解除关联之后,编辑单行编辑器的内容时,下边的两个控件内容不会改变:
- 点赞
- 收藏
- 关注作者
评论(0)