QT
的布局Qt
中的布局有三种方式: 水平布局,垂直布局,栅格布局。
ui
设置布局我们先创建一个窗口应用程序,程序名叫 layout,
基类选择 QDialog
,Qt
会为我们自动生成 login.cpp
、login.h
和 login.ui
文件。
我们进入 ui
文件编辑,添加一个 label
,提示改为"用户"。
在后边添加一个 lineEdit
控件,按住 ctrl
鼠标依次点击这两个控件选中后,再点击工具栏的水平布局按钮就可以看到用户 label
和输入框处于同一水平线了。但是输入框会被拉长,而且 label
和输入框占满了整个水平空间。这时我们可以通过拖动左侧控件列表中的 Horizonal Spacer
,将其放入用户标签的左侧,再拖动一个 Horizonal Spacer
将其放在输入框的右侧,就可以看到用户标签和输入框被挤在中间了,并且两侧留有空间了。
Spacer
可以设置几种模式,包括 fixed
、expanding
、maximum
、minimum
等模式。
依次类推,我们在添加密码标签和输入框,以及登录和注册按钮,通过 ui
界面的控件调整布局。
上面我们通过 ui
设置了布局,接下来我们通过代码设置布局,设置注册界面的布局。
注册类的声明如下:
#ifndef REGISTER_H
#define REGISTER_H
#include <QDialog>
#include <memory>
using namespace std;
class Login; // 声明一下
namespace Ui {
class Register;
}
class Register : public QDialog
{
Q_OBJECT
public:
explicit Register(QWidget *parent = nullptr);
~Register();
void set_login(const weak_ptr<Login>& login);
void showLogin();
private:
Ui::Register *ui;
// 因为要实现登录和注册界面之间的切换,所以 Register 类包含了 Login 类的弱指针
// weak_ptr 对象的 lock 成员函数可以取出其对应的 shared_ptr 对象
weak_ptr<Login> login_;
QPushButton* register_button_;
};
#endif // REGISTER_H
因为要实现登录和注册界面之间的切换,所以 Register
类包含了 Login
类的弱指针。Register
类的具体实现如下:
用代码的话,弹簧是不分垂直和水平的,放在垂直布局中就是垂直弹簧,放在水平布局中就是水平弹簧。
#include "register.h"
#include "ui_register.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QSpacerItem>
Register::Register(QWidget *parent) :
QDialog(parent),
ui(new Ui::Register)
{
ui->setupUi(this);
this->setMaximumSize(QSize(300,350));
this->setMinimumSize(QSize(300,350));
auto vbox_layout = new QVBoxLayout();
auto verticalSpacer1 = new QSpacerItem(40,20, QSizePolicy::Minimum, QSizePolicy::Expanding);
vbox_layout->addItem(verticalSpacer1);
QSpacerItem *name_item1 = new QSpacerItem(40,20, QSizePolicy::Fixed, QSizePolicy::Minimum);
QLabel * name_label = new QLabel();
name_label->setText("邮箱:");
QLineEdit * name_edit = new QLineEdit();
auto name_layout = new QHBoxLayout();
name_layout->addItem(name_item1);
name_layout->addWidget(name_label);
name_layout->addWidget(name_edit);
QSpacerItem *name_item2 = new QSpacerItem(40,20, QSizePolicy::Fixed, QSizePolicy::Minimum);
name_layout->addItem(name_item2);
vbox_layout->addLayout(name_layout);
QLabel * pwd_label = new QLabel();
pwd_label->setText("密码:");
QLineEdit * pwd_edit = new QLineEdit();
auto verticalSpacer2 = new QSpacerItem(40,20, QSizePolicy::Maximum, QSizePolicy::Maximum);
vbox_layout->addItem(verticalSpacer2);
auto pwd_layout = new QHBoxLayout();
QSpacerItem *pwd_item2 = new QSpacerItem(40,20, QSizePolicy::Fixed, QSizePolicy::Minimum);
QSpacerItem *pwd_item1 = new QSpacerItem(40,20, QSizePolicy::Fixed, QSizePolicy::Minimum);
pwd_layout->addItem(pwd_item1);
pwd_layout->addWidget(pwd_label);
pwd_layout->addWidget(pwd_edit);
pwd_layout->addItem(pwd_item2);
vbox_layout->addLayout(pwd_layout);
auto verticalSpacer3 = new QSpacerItem(40,30, QSizePolicy::Fixed, QSizePolicy::Maximum);
vbox_layout->addItem(verticalSpacer3);
QSpacerItem* reg_btn_item1 = new QSpacerItem(150,20, QSizePolicy::Fixed, QSizePolicy::Minimum);
register_button_ = new QPushButton();
register_button_->setText("注册");
auto regbtn_layout = new QHBoxLayout();
regbtn_layout->addItem(reg_btn_item1);
regbtn_layout->addWidget(register_button_, 5);
QSpacerItem* reg_btn_item2 = new QSpacerItem(40,20, QSizePolicy::Fixed, QSizePolicy::Minimum);
regbtn_layout->addItem(reg_btn_item2);
vbox_layout->addLayout(regbtn_layout);
auto verticalSpacer4 = new QSpacerItem(40,20, QSizePolicy::Fixed, QSizePolicy::Expanding);
vbox_layout->addItem(verticalSpacer4);
this->setLayout(vbox_layout);
// register 页面跳转到 login 页面
connect(register_button_, &QPushButton::clicked, this, &Register::showLogin);
}
Register::~Register()
{
delete ui;
}
void Register::set_login(const weak_ptr<Login>& login){
login_ = login;
}
void Register::showLogin(){
this->close();
// this->login_.lock()->show();
// auto shared_ptr_login = login_.lock();
std::shared_ptr<Login> shared_ptr_login = login_.lock();
shared_ptr_login->show();
}
Register
的构造函数中用代码的方式创建了一个垂直布局,垂直布局中增加了两个 spacer
,分别是 verticalSpacer1
和 verticalSpacer4
,以及三个水平布局 pwd_layout
,name_layout
以及 regbtn_layout
,然后分别用代码的方式在三个布局中添加 spacer
和控件。
Login
类的声明如下:
#ifndef LOGIN_H
#define LOGIN_H
#include <QDialog>
#include <memory>
class Register;
using namespace std;
QT_BEGIN_NAMESPACE
namespace Ui { class Login; }
QT_END_NAMESPACE
class Login : public QDialog, public std::enable_shared_from_this<Login>
{
Q_OBJECT
public:
Login(QWidget *parent = nullptr);
~Login();
void initSignals();
private slots:
void on_registerButton_clicked();
private:
Ui::Login *ui;
std::shared_ptr<Register> register_;
};
#endif // LOGIN_H
std::shared_ptr
互引用问题:Login
类里面有 std::shared_ptr<Register> register_
可以用来调用 register
页面(那么在 register
好了之后肯定得跳转到 login
页面,所以在 register
类里面也得有调用显示 login
页面的 Login
对象的啊),但是如果 register
类也用 std::shared_ptr<Login>
的话,就会出现互为引用的空间不能释放的问题(register
类得用 std::weak_ptr<Login>
解决这个问题)。
在自己的类里面,拿到已创建的 std::shared_ptr
,共享引用计数: Login
类继承 public std::enable_shared_from_this<Login>
可以实现在 Login
自己的类里面,用 this->shared_from_this()
取到自己的 std::shared_ptr<Login>
传递给 register
去用 std::weak_ptr<Login>
来记录自己这个 Login
对象。
Login
实现如下:
#include "login.h"
#include "ui_login.h"
#include <QBitmap>
#include <QPainter>
#include "register.h"
Login::Login(QWidget *parent)
: QDialog(parent)
, ui(new Ui::Login)
{
ui->setupUi(this);
}
Login::~Login()
{
delete ui;
}
void Login::initSignals(){
register_ = std::make_shared<Register>();
register_->set_login(this); // error: 右值不能 绑定到弱指针里面的
register_->set_login(std::make_shared<Register>(this)); // error: 两个智能指针管理 this,会有两次析构的问题
// 从本类转化为共享的智能指针给 register 类
register_->set_login(shared_from_this()); // 在调用这一行之前得有一个 std::shared_ptr<Login>,不然会有 std::bad_weak_ptr 的报错
}
void Login::on_registerButton_clicked() // login 界面 registerButton 按钮的点击事件
{
this->close();
register_->show();
}
main
函数的实现如下:
#include "login.h"
#include <QApplication>
#include <memory>
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Login w;
// w.show();
std::shared_ptr<Login> login = std::make_shared<Login>(); // 在下面使用 shared_from_this() 之前得有一个 std::shared_ptr<Login> 对象的哦
login->initSignals();
login->show();
return a.exec();
}
点击运行按钮,程序运行起来就可以从登录界面切换到注册界面了,注册页面注册好了之后可以点击注册按钮跳转到登陆页面。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。