QT作业1:实现两个窗口的切换

1 需求

在这里插入图片描述
设计两个窗口,每个窗口中都包含一个按钮,最开始的时候只显示窗口1,当按下窗口1中的按钮时,窗口1隐藏(hide),同时窗口2显示(show),当按下窗口2中的按钮时,窗口2隐藏,窗口1显示。

2 分析

这个案例最关键的是,如何让两个窗口建立连接(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对象,然后建立两个窗口的联系,这个用来练习自定义信号函数。

3 第一种方法

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();
}

4 第二种方法

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();
}

5 第三种方法

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的成员变量(将指针作为成员变量),然后在析构函数中释放,这里可以回头自己演示。

第三种方法的设计思想比较巧妙,最好学会。

猜你喜欢

转载自blog.csdn.net/weixin_44457930/article/details/129648781
今日推荐