工作原因需要用到VS和Qt,在网上搜索了很久都没找到比较全面的在VS下联合开发Qt的教程。使用QT Creater单独开发能通过转到槽函数/双击插件,进行跳转一个插件的响应函数,但是VS上没有转到槽这一项,就挺烦人的。而且说是用过MFC的人转到Qt挺快的,本渣渣表示并不是啊,看其他博客我还是看的可蒙圈。于是本渣渣决定还是自己一边学,一边把要注意的点记录下来,希望能给和我有一样困惑的小伙伴们提供一些帮助吧。
堆栈窗体 QStackedWidget 类
在实际应用中,堆栈窗体多与列表框 QListWidget 及下拉列表框 QComboBox 配合使用。
例子:简单堆栈窗体
步骤1:新建一个Qt Widgets Application项目(注意Base class选择QWidget!我一开始选的QMainWindow,然后程序运行三个窗口叠在一起了)
步骤2:双击QtWidgetsApplication1.ui文件打开UI界面,这个例子因为是用layout画图指针来绘制布局相关控件,所以在UI界面暂时不需要添加什么控件。关闭UI界面,在VS解决方案中选中方案,右键->Qt->Refresh intelliSense进行刷新,在VS解决方案中右键 .ui 文件 -> "编译",会生成对应的 ui_XX.h 头文件。
这里补充一下Layout布局和QLayout的相关知识。
Layout:布局容器,其下可嵌套 Header Sider Content Footer或Layout本身,可以放在任何父容器中。
Header:顶部布局,自带默认样式,其下可嵌套任何元素,只能放在Layout中。
Sider:侧边栏,自带默认样式及基本功能,其下可嵌套任何元素,只能放在Layout中。
Content:内容部分,自带默认样式,其下可嵌套任何元素,只能放在Layout中。
Footer:底部布局,自带默认样式,其下可嵌套任何元素,只能放在Layout中。
QLayout类是布局管理器的基类。
QLayout是由具体类 QBoxLayout、QGridLayout、QFormLayout 和 QStackedLayout继承的抽象基类。一些详细的用法大家可以在其他博客里多看看,这里就不详细说明了。大家也可以根据我下面的例子来体会一下layout的用法。
步骤3:修改.cpp文件和.h文件实现对应窗口功能。
.h
#ifndef QTWINDOWTEST_H
#define QTWINDOWTEST_H
#include <QtWidgets/QWidget>
#include "ui_qtWindowTest.h"
#include <QListWidget>
#include <QStackedWidget>
#include <QLabel>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QGridLayout>
#include <QString>
namespace Ui {
class qtWindowTestClass;
}
class qtWindowTest : public QWidget
{
Q_OBJECT
public:
qtWindowTest(QWidget *parent = nullptr);
~qtWindowTest();
private:
Ui::qtWindowTestClass ui;
private:
QListWidget* list; //声明一个QListWidget控件对象指针,用于在控件中插入三个条目,作为选择项
QStackedWidget* stack; //声明一个QStackedWidget堆栈窗口指针,用于将创建的三个标签依次插入堆栈窗体中
QLabel* Label1; //声明一个QLabel控件标签指针,用于插入窗口中
QLabel* Label2;
QLabel* Label3;
};
#endif // QTWINDOWTEST_H
.cpp
#include "qtWindowTest.h"
#include "ui_qtWindowTest.h"
qtWindowTest::qtWindowTest(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
setWindowTitle(tr("StackedWidget")); //设置主窗口的名称
list = new QListWidget(this); //新建一个 QListWidget 控件对象
//在新建的QListWidget 控件中插入三个条目,作为选择项
list->insertItem(0, tr("Window1"));
list->insertItem(1, tr("Window2"));
list->insertItem(2, tr("Window3"));
//创建三个QLabel 标签控件对象,作为堆栈窗口需要显示的三层窗体
Label1 = new QLabel(tr("WindowTest1"));
Label2 = new QLabel(tr("WindowTest2"));
Label3 = new QLabel(tr("WindowTest3"));
stack = new QStackedWidget(this);//新建一个QStackedWidget堆栈窗体对象
//将创建的三个QLabel 标签控件依次插入堆栈窗体中
stack->addWidget(Label1);
stack->addWidget(Label2);
stack->addWidget(Label3);
QHBoxLayout* mainLayout = new QHBoxLayout(this);
//对整个对话框进行布局
mainLayout->setMargin(5); //设定对话框(或窗体)的边距为5
mainLayout->setSpacing(5); //设定各个控件之间的间距为5
mainLayout->addWidget(list);
mainLayout->addWidget(stack, 0, Qt::AlignHCenter);
mainLayout->setStretchFactor(list, 1); //(a)
mainLayout->setStretchFactor(stack, 3);
connect(list, SIGNAL(currentRowChanged(int)), stack, SLOT(setCurrentIndex(int)));
}
qtWindowTest::~qtWindowTest()
{}
运行结果
现在我们希望将这个堆栈窗体和我们上篇文章中的槽函数的一些例子结合起来,实现在不同的窗口实现不同的功能。
例子:进阶版堆栈窗体
步骤1:在上一个例子的VS项目中,增添qtWindowTestx.h和qtWindowTestx.cpp文件。功能为四则运算。
qtWindowTestx.h
#ifndef QTWINDOWTESTX_H
#define QTWINDOWTESTX_H
#include <QWidget>
#include "ui_qtWindowTest.h"
#include <QListWidget>
#include <QStackedWidget>
#include <QLabel>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QString>
namespace Ui {
class qtWindowTest;
}
class qtWindowTestx : public QWidget
{
Q_OBJECT
public:
qtWindowTestx(QWidget* parent = nullptr);
~qtWindowTestx();
private:
Ui::qtWindowTestClass ui;
private:
QPushButton* button, * button1; // 声明按钮指针
QLineEdit* edit1, * edit2, * edit3, * edit4; //声明文本框指针
QGridLayout* layout; //声明画图指针
private slots:
void on_clicked(); //声明按钮信号触发调用的函数
void on_clicked1();
};
#endif // QTWINDOWTESTX_H
qtWindowTestx.cpp
#include "qtWindowTestx.h"
#include "ui_qtWindowTest.h"
qtWindowTestx::qtWindowTestx(QWidget* parent)
: QWidget(parent)
{
ui.setupUi(this);
button = new QPushButton;
button1 = new QPushButton;
layout = new QGridLayout(this);
edit1 = new QLineEdit;
edit2 = new QLineEdit;
edit3 = new QLineEdit;
edit4 = new QLineEdit;
button1->setText("Clear");
button->setText("Output");
connect(button, SIGNAL(clicked(bool)), this, SLOT(on_clicked())); //连接按钮
connect(button1, SIGNAL(clicked(bool)), this, SLOT(on_clicked1()));
layout->addWidget(button, 1, 0, Qt::Alignment()); //初始化画图
layout->addWidget(edit1, 0, 0, Qt::Alignment()); //用于初始化控件位置
layout->addWidget(edit2, 0, 1, Qt::Alignment());
layout->addWidget(edit3, 0, 2, Qt::Alignment());
layout->addWidget(edit4, 1, 1, Qt::Alignment());
layout->addWidget(button1, 1, 2, Qt::Alignment());
}
void qtWindowTestx::on_clicked() //计算大小
{
int a = edit1->text().toInt();
int b = edit3->text().toInt();
QString c = edit2->text();
if (c == "+")
{
edit4->setText(QString::number(a + b));
}
if (c == "-")
{
edit4->setText(QString::number(a - b));
}
if (c == "*")
{
edit4->setText(QString::number(a * b));
}
if (c == "/")
{
edit4->setText(QString::number(a / b));
}
}
void qtWindowTestx::on_clicked1() //清除
{
edit1->clear();
edit2->clear();
edit3->clear();
edit4->clear();
}
qtWindowTestx::~qtWindowTestx()
{}
步骤2:前面的qtWindowTest.h和qtWindowTest.cpp文件也要做一些小改动。
qtWindowTest.h
#ifndef QTWINDOWTEST_H
#define QTWINDOWTEST_H
#include <QtWidgets/QWidget>
#include "ui_qtWindowTest.h"
#include <QListWidget>
#include <QStackedWidget>
#include <QLabel>
#include <QHBoxLayout>
#include "qtWindowTestx.h"
#include <QPushButton>
#include <QLineEdit>
#include <QGridLayout>
#include <QString>
namespace Ui {
class qtWindowTestClass;
}
class qtWindowTest : public QWidget
{
Q_OBJECT
public:
qtWindowTest(QWidget *parent = nullptr);
~qtWindowTest();
private:
Ui::qtWindowTestClass ui;
private:
QListWidget* list; //声明一个QListWidget控件对象指针,用于在控件中插入三个条目,作为选择项
QStackedWidget* stack; //声明一个QStackedWidget堆栈窗口指针,用于将创建的三个标签依次插入堆栈窗体中
QLabel* Label1; //声明一个QLabel控件标签指针,用于插入窗口中
QLabel* Label2;
QLabel* Label3;
qtWindowTestx *ff;
};
#endif // QTWINDOWTEST_H
qtWindowTest.cpp
#include "stdafx.h"
#include "qtWindowTest.h"
#include "ui_qtWindowTest.h"
qtWindowTest::qtWindowTest(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
setWindowTitle(tr("StackedWidget")); //设置主窗口的名称
list = new QListWidget(this); //新建一个 QListWidget 控件对象
//在新建的QListWidget 控件中插入三个条目,作为选择项
list->insertItem(0, tr("Window1"));
list->insertItem(1, tr("Window2"));
list->insertItem(2, tr("Window3"));
//创建三个QLabel 标签控件对象,作为堆栈窗口需要显示的三层窗体
Label1 = new QLabel(tr("WindowTest1"));
Label2 = new QLabel(tr("WindowTest2"));
Label3 = new QLabel(tr("WindowTest3"));
stack = new QStackedWidget(this);//新建一个QStackedWidget堆栈窗体对象
//将创建的三个QLabel 标签控件依次插入堆栈窗体中
stack->addWidget(Label1);
ff = new qtWindowTestx; //此处仿照 Label1 类,创建qtWindowTestx类
stack->addWidget(ff);
stack->addWidget(Label3);
QHBoxLayout* mainLayout = new QHBoxLayout(this);
//对整个对话框进行布局
mainLayout->setMargin(5); //设定对话框(或窗体)的边距为5
mainLayout->setSpacing(5); //设定各个控件之间的间距为5
mainLayout->addWidget(list);
mainLayout->addWidget(stack, 0, Qt::AlignHCenter);
mainLayout->setStretchFactor(list, 1); //(a)
mainLayout->setStretchFactor(stack, 3);
connect(list, SIGNAL(currentRowChanged(int)), stack, SLOT(setCurrentIndex(int)));
}
qtWindowTest::~qtWindowTest()
{}
运行结果
窗体
还可以把之前做的文本显示还有圆面积计算或者其他什么功能都放在另外两个窗口。方法是类似的。这里不详细写步骤啦。代码我传到GitHub上了(key-cc/QT_EX: This repository is about some exercise code of QT while learning, hope this can help you for QT learning. (github.com)),大家可以自行下载。不方便上GitHub的话,CSDN我也传了一份(【免费】VS2022联合Qt5开发项目(复杂堆栈窗体)资源-CSDN文库)。关于GitHub加速的问题,我在另外一篇博文(Github访问速度慢的解决方案-CSDN博客)里有写到方法,希望对大家有帮助。
关于这个程序,因为我参考的博客(Qt5开发从入门到精通——第三篇一节(窗口篇——堆栈窗口)_qt堆叠窗口_别形的博客-CSDN博客)文件名和我的不一样(我总感觉吧,文件名还是写内容相关的英语,比较方便以后的审阅,而且取名字用widget真的很容易和Qt本身的库里的widget混掉欸。小小的吐槽一下,啊大佬原谅我吧。)我在把自己新写好的窗口导入到原来的窗口就各种错。我总结起来就是,一定要看清楚你的新建功能窗口文件的名称,比如我这里就是qtWindowTestx,所以我在.h文件里新声明一个qtWindowTestx的指针,
qtWindowTestx *ff;
然后在.cpp文件中创建这个窗口对象并且将它插入到堆栈窗体中。
ff = new qtWindowTestx;
stack->addWidget(ff);
并且这里还用到了条件编译用于防止发生重复定义或声明。
#ifndef QTWINDOWTEST_H
#define QTWINDOWTEST_H
...//头文件内容
#endif // QTWINDOWTEST_H
下划线“__”属于编程风格的内容,对程序没有影响。不用下划线也可以,用几个下划线也由个人习惯。 如果你再练习的时候用的是其他的文件名,一定要记得修改成自己的文件名,千万别直接copy忘记改了!(别问我怎么知道的ORZ)
这一篇有点长,其他窗体结构我就放在下一篇来讲了。