赞
踩
设计两个窗口,每个窗口中都包含一个按钮,最开始的时候只显示窗口1,当按下窗口1中的按钮时,窗口1隐藏(hide),同时窗口2显示(show),当按下窗口2中的按钮时,窗口2隐藏,窗口1显示。
这个案例最关键的是,如何让两个窗口建立连接(connect),最开始学QT的时候,我们都是在Widget的构造函数中调用connect函数,但这里不能直接这样做,因为创建的时候,你拿不到另一个Widget对象,如果通过构造函数的参数传进来,则传进来的那个Widget该如何构建?解决这个问题可以使用两种方法:
1 重载构造函数,例如w1通过无参构造函数创建,w2通过有参,w2在创建的时候将w1传进去,然后在有参构造函数中建立联系(connect)
2 新建一个类A,这个类A必须直接或间接继承QObject,这样才能获得connect函数(因为connect是QObject的成员函数),然后将w1和w2都作为A的成员变量,并在A的构造函数中实现两个窗口的连接
需要注意的一点是,信号的发送者是QPushButton指针,而不是窗口对象,并且,为了建立两个窗口的联系,最好将QPushButton指针作为Widget类的成员变量,这样通过窗口就能拿到信号发送者,详见下面的代码。
还有第三种方法,就是使用自定义信号来实现,新建一个窗口类MyWidget,并增加一个信号函数,在构造函数中将按钮与自定义信号建立联系,然后在另一个窗口类的构造函数中,新建一个MyWidget对象,然后建立两个窗口的联系,这个用来练习自定义信号函数。
widget.h内容如下:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include "QPushButton" class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); Widget(const Widget& w2, QWidget *parent = nullptr); public: QPushButton * btn; }; #endif // WIDGET_H
widget.cpp内容如下,为什么用lambda表达式不行,我想了很久都不知道,最后没有使用lambda表达式,不过后面我找到原因了,就是const,具体问题可以看注释:
#include "widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) { btn = new QPushButton("button", this); btn->move(300, 300); } Widget::~Widget() { } Widget::Widget(const Widget& another_w, QWidget *parent) : QWidget(parent) { this->btn = new QPushButton("button", this); this->btn->move(300, 300); /* //下面的代码为何会报错? connect(this->btn, &QPushButton::clicked, [=](){ this->hide(); another_w.show(); }); //another_w在lambda函数中是常对象,不能调用非常成员函数,this是常指针,因此可以调用hide //1 能不能添加mutable选项(即[=]()mutable),让another_w可以在函数内部调用show? // 不能,因为another_w是通过构造函数传入,它已经被声明为了const,这里用mutable会冲突 //2 能不能在调用connect之前,对another_w先进行取址操作,然后在lambda函数内部通过指针调用show,像this一样? // 不能,因为another_w在传入时就已经被声明为了const,无法进行取址操作,除非修改函数声明和定义,去掉const */ connect(this->btn, &QPushButton::clicked, this, &QPushButton::hide); connect(this->btn, &QPushButton::clicked, &another_w, &QPushButton::show); connect(another_w.btn, &QPushButton::clicked, &another_w, &QPushButton::hide); connect(another_w.btn, &QPushButton::clicked, this, &QWidget::show); }
main.cpp内容如下:
#include "widget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w1; Widget w2(w1); w1.setGeometry(100, 100, 600, 600); w1.setWindowTitle("窗口1"); w2.setGeometry(1000, 100, 600, 600); w2.setWindowTitle("窗口2"); w1.show(); return a.exec(); }
widget.h内容:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include "QPushButton" class widget : public QWidget { Q_OBJECT public: explicit widget(QWidget *parent = nullptr); public: QPushButton* btn; signals: }; #endif // WIDGET_H
widget.cpp内容
#include "widget.h"
widget::widget(QWidget *parent) : QWidget(parent)
{
btn = new QPushButton("button", this);
btn->move(300, 300);
}
mainwindow.h 内容如下:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "widget.h" class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); public: widget w1, w2; }; #endif // MAINWINDOW_H
mainwindow.cpp内容如下:
#include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { connect(w1.btn, &QPushButton::clicked, [=](){ //如果写成 [w1, w2]企图捕获类的成员变量w1和w2,会报错 //mainwindow.cpp:6:45: error: 'w2' in capture list does not name a variable this->w1.hide(); this->w2.show(); }); connect(w2.btn, &QPushButton::clicked, [this](){ //将this指针写到捕获参数列表时,函数内部可以直接使用成员函数和成员变量 w2.hide(); //使用w2和w1,无需通过this指针 w1.show(); }); w1.setGeometry(100, 100, 600, 600); w1.setWindowTitle("窗口1"); w2.setGeometry(1000, 100, 600, 600); w2.setWindowTitle("窗口2"); } MainWindow::~MainWindow() { }
main.cpp内容如下:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow mw;
mw.w1.show();
return a.exec();
}
Widget.h内容不修改,用自动生成的:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
};
#endif // WIDGET_H
然后新建一个名为MyWidget类,mywidget.h内容如下:
#ifndef MYWIDGET_H #define MYWIDGET_H #include <QWidget> class MyWidget : public QWidget { Q_OBJECT public: explicit MyWidget(QWidget *parent = nullptr); signals: void btnClicked(); }; #endif // MYWIDGET_H
mywidget.cpp内容如下:
#include "mywidget.h" #include "QPushButton" MyWidget::MyWidget(QWidget *parent) : QWidget(parent) { //窗口设置 this->setGeometry(100, 100, 600, 600); this->setWindowTitle("窗口2"); //新建按钮 QPushButton* btn = new QPushButton("button", this); btn->move(300, 300); //将按钮与自定义信号建立关系 connect(this, &MyWidget::btnClicked, [=](){ emit this->btnClicked(); }); }
Widget.cpp内容还没介绍,刚刚只是演示了头文件,其定义如下:
#include "widget.h" #include "mywidget.h" #include "QPushButton" Widget::Widget(QWidget *parent) : QWidget(parent) { //窗口设置 this->setGeometry(100, 100, 600, 600); this->setWindowTitle("窗口1"); //新建按钮 QPushButton* btn = new QPushButton("button", this); btn->move(300, 300); MyWidget* w2 = new MyWidget(); connect(btn, &QPushButton::clicked, [=](){ this->hide(); w2->show(); }); connect(w2, &MyWidget::btnClicked, [=](){ w2->hide(); this->show(); }); } Widget::~Widget() { }
由于w2是顶层窗口,且开辟在堆中,因此容易出现内存泄漏,可以将其改成通过参数传入到构造函数中,也可以将其作为Widget的成员变量(将指针作为成员变量),然后在析构函数中释放,这里可以回头自己演示。
第三种方法的设计思想比较巧妙,最好学会。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。