前言
在Qt界面开发过程中,一个主界面或者主窗口看成是各个控件排列组合后的集合,对于一些项目而言,有些常用的控件可以封装成自己想要的控件样式并且复用,比如说,log显示控件,图像/视频显示控件等,可以将常用的控件代码封装起来,以便下次复用,内嵌在不同的主界面内。这里总结了常见的四种方法供大家参考;
第一种方法:直接调用自定义控件项目文件至主界面项目中
- 新建一个自定义控件项目
一般自定义控件,继承于QWidget;
ui文件为
- 另建一个主界面项目,主界面ui文件如图所示,在主界面内添加一个QFrame,在Frame内添加一个布局控件(添加widget控件)
- 将自定义控件的.ui,.h,.cpp文件添加到主界面的项目中
- 在主界面内添加自定义控件类,并建立自定义控件变量
头文件为
#include "CustomWidget.h" //自定义控件
class MainWindows : public QMainWindow
{
Q_OBJECT
public:
MainWindows(QWidget *parent = Q_NULLPTR);
private:
CustomWidget *customWidget; //自定义控件
Ui::MainWindowsClass ui;
};
cpp文件内
#include "MainWindows.h"
MainWindows::MainWindows(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
//加载自定义控件
customWidget = new CustomWidget;
ui.layout->addWidget(customWidget);
//调用自定义控件的接口
customWidget->setText();
}
这样运行之后,便可以看到自定义控件内嵌到主界面内;
自定义控件和主界面之间的数据交互方法
主界面控制自定义控件:可以在子界面内建立一个数据接口函数,这样可以通过直接调用子界面类对象的函数,实现子界面内数据变化;比如说上述,自定义控件的接口setText()可以实现自定义控件的ui刷新;
自定义控件内数据传给主界面:通过信号槽的方式;
第二种方法:自定义控件编译成dll,主界面项目调用
-
创建一个自定义控件项目文件,将项目的输出属性更改为dll
-
在自定义控件类上要加入Q_DECL_EXPORT,这样才能输出lib文件
-
自定义控件的ui文件与方法一相同,自定义控件类的.h文件为
#include <QtWidgets/QWidget>
#include "ui_CustomWidget.h"
//没有Q_DECL_EXPORT,就不会生成lib文件
class Q_DECL_EXPORT CustomWidget : public QWidget
{
Q_OBJECT
public:
CustomWidget(QWidget *parent = Q_NULLPTR);
void setText(QString str); //接口函数
private:
Ui::CustomWidgetClass ui;
public slots:
void on_openBtn();
};
- 新建一个主界面项目,添加QFrame和布局,主控件布局和方法一一样,将自定义控件的dll文件,lib文件,.h文件添加到主界面项目中,注意,在.h文件发布的时候,需要提供ui_XXX.h,并且将.h文件中的Q_DECL_EXPORT去掉,不然会报错,主界面包含的头文件如图所示;
发布的.h文件为
#include <QtWidgets/QWidget>
#include "ui_CustomWidget.h"
//发布时,去掉Q_DECL_EXPORT
class CustomWidget : public QWidget
{
}
- 主界面的定义与方法一相同;主界面与自定义控件之间的数据交互也与方法一相同,最终的效果为
第三种方法:在Qt Designer中提升控件
- 新建一个自定义控件项目,自定义控件与方法一相同
- 新建一个主界面项目,将自定义控件的ui文件,cpp文件,h文件添加到主界面项目中;因为ui编译顺序的问题,要把自定义控件的.h文件放到最前面,不然会报错;
#include "CustomWidget.h" //自定义控件
#include <QtWidgets/QMainWindow>
#include <qpushbutton.h>
#include "ui_MainWindows.h"
-
在主界面的Qt Designer中先新建一个QWidget控件,提升控件;选中控件,选择提升为
手动填入自定义控件类的类名称
可以在对象查看器中看到QWidget已经变成了CustomWidget,同时修改对象名称为customWidget,接下来便可以按照第一种方法,在主界面函数类访问自定义控件的数据;
-
最终主界面效果为
第四种方法:自定义插件–Plugin方式
- 首先在VS中创建一个Qt Designer Custom Widget项目并命名为CustomWidget。如图所示
创建好之后,可以看到并无ui文件。
这里我们讲述的自定义控件是制作成插件的方式,因此设计阶段是需要ui文件的,这里需要在项目文件内自行创建一个ui文件。并且在CustomWidget.h内添加ui文件生成的ui_CustomWidget.h头文件。自行添加槽函数,ui对象等;
#pragma once
#include <QtWidgets/QWidget>
//自行添加ui生成的头文件
#include "ui_CustomWidget.h"
class CustomWidget : public QWidget
{
Q_OBJECT
public:
CustomWidget(QWidget *parent = Q_NULLPTR);
//自行添加ui界面的信号槽函数
public slots:
void on_openBtn();
//这里要跟ui_CustomWidget.h里面命名空间内的界面类对应上,自行添加
private:
Ui::Form ui;
};
#include "CustomWidget.h"
CustomWidget::CustomWidget(QWidget *parent)
: QWidget(parent)
{
//自行添加的代码
ui.setupUi(this);
connect(ui.openBtn,&QPushButton::clicked,this,&CustomWidget::on_openBtn);
}
//自行添加槽函数
void CustomWidget::on_openBtn()
{
ui.textBrowser->append("open widget");
}
可以看出,插件类CustomWidgetPlugin组合类CustomWidget,CustomWidget组合界面类Form;
在自定义插件的生成文件内可以看到:
自定义插件生成dll和lib文件;主界面动态加载dll文件即可;
- 创建一个主界面项目文件,与前两个方法相同;
- 在主界面内可以动态加载dll文件,便可以实现动态加载自定义控件;将dll放到exe同级目录下,动态加载代码为:
头文件:
//插件的头文件
#include "CustomWidget.h"
#include "ui_CustomWidget.h"
//相应的头文件
#include <qpluginloader.h>
#include <QtUiPlugin/QDesignerCustomWidgetInterface>
动态加载代码为:
QPluginLoader loader("CustomWidget.dll");
if (loader.load())
{
QObject *plugin = loader.instance();
if (plugin)
{
QDesignerCustomWidgetInterface *widget = qobject_cast<QDesignerCustomWidgetInterface *>(plugin);
if (widget)
{
//创建的子控件对象
QWidget *customWidget = widget->createWidget(nullptr);
ui.layout->addWidget(customWidget);
}
}
}
最终界面效果为:
四种方法的总结
其实四种方法的本质是将自定义控件封装成一个专门的类,通过调用子控件类对象便可以实现内嵌自定义控件,在开发过程中,使用以上四种方法,相当于把界面分成了各个子模块,主界面通过调用这些子模块,可以实现团队之间快速开发工作;
不同自定义控件或窗口之间数据交互的方式
从主界面传递数据到嵌入的自定义子控件,可以通过直接调用子控件类的接口函数实现从主窗口到子窗口之间的数据传递;而子界面传递到主界面或者子界面之间的数据交互可以按照单例模式,建立一个传递信号的类。其本质是建立一个类,通过connect函数可以传递信号到信号,从而实现自定义控件到主界面之间的数据交互;此代码参考的博主文章为:
Qt 信号在多层次对象间传递 多层嵌套类对象之间信号传递
头文件为:
#include <QObject>
class TransmitSignals : public QObject
{
Q_OBJECT
public:
static TransmitSignals &GetInstance();
private:
TransmitSignals();
~TransmitSignals();
TransmitSignals(const TransmitSignals &) = delete;
TransmitSignals(const TransmitSignals &&) = delete;
TransmitSignals &operator=(const TransmitSignals &) = delete;
signals:
//传递数据
//传给A界面数据
void sigToAWidget(QString ret);
//传给B界面数据
void sigToBWidget(QString ret);
public slots:
};
.cpp文件为
#include "TransmitSignals.h"
TransmitSignals::TransmitSignals()
{
}
TransmitSignals::~TransmitSignals()
{
}
TransmitSignals& TransmitSignals::GetInstance()
{
static TransmitSignals RobotControl;
return RobotControl;
}
最终的效果为
结尾
上述方法的源代码已放置链接中,可下载后查看项目源码:
Qt主界面内嵌自定义控件的四种方法以及不同控件数据交互