(提升法参考:Qt将两个组件封装成一个组件(自定义接口函数)_qt怎么把两个项目整合成一个-CSDN博客

1、参考链接

QT中自定义控件的创建到封装到工具栏过程(一):自定义控件的创建_qt 工具栏添加控件-CSDN博客

2、说明

使用QTCreator是可以的

注意事项:

        1.新项目使用的时候加入lib库,引用头文件就ok,如果是用Debug构建的,那对应的也只能用于Debug下的项目

        2.如果designer界面无显示则需要把release模式下发布的dll与lib放入C:\Qt\Qt5.12.3\5.12.3\msvc2017_64\plugins\designer

        3.

这个QDESIGNER_WIDGET_EXPORT必加(对于QtCreator),我们进行控件封装的时候要加,引用该控件的话不需要加,去掉该宏

        4.如果带有UI文件,#include "ui_qclasstest4.h"这个需要放在CPP文件中,然后在头文件中还需要一系列声明,可参考例子2.2

        5.createWidget函数与name()函数的类名要一样

        6.domxml函数"<widget class=\"QArrowLine\" name=\"arrowLine\">\n",注意这两个名字不是一样的,一个是类类型,一个是类名字

2.1 以下为不添加UI文件的示例:

#ifndef QTTESTWIDGET_H
#define QTTESTWIDGET_H

#include <QWidget>
#include <QtUiPlugin/QDesignerExportWidget>
class QDESIGNER_WIDGET_EXPORT  QtTestWidget : public QWidget
{
    Q_OBJECT

public:
    QtTestWidget(QWidget *parent = 0);
};

#endif // QTTESTWIDGET_H
#include "qttestwidget.h"
#include "qpushbutton.h"

QtTestWidget::QtTestWidget(QWidget *parent) :
    QWidget(parent)
{
    QPushButton *button = new QPushButton(this);
        button->setText("custom button");
}

2.2 带UI文件

#ifndef QCLASSTEST4_H
#define QCLASSTEST4_H

#include <QWidget>
#include <QtUiPlugin/QDesignerExportWidget>
namespace Ui {
class QCLASSTEST4;
}

class QDESIGNER_WIDGET_EXPORT QCLASSTEST4 : public QWidget
{
    Q_OBJECT

public:
    explicit QCLASSTEST4(QWidget *parent = nullptr);
    ~QCLASSTEST4();

private:
    Ui::QCLASSTEST4 *ui;
};

#endif // QCLASSTEST4_H
#include "qclasstest4.h"
#include "ui_qclasstest4.h"

QCLASSTEST4::QCLASSTEST4(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::QCLASSTEST4)
{
    ui->setupUi(this);
}

QCLASSTEST4::~QCLASSTEST4()
{
    delete ui;
}
#include "qttestwidget.h"
#include "qttestwidgetplugin.h"

#include <QtPlugin>
#include "testwidget2.h"
#include "classtestwidget2.h"
#include "qclasstestwidget3.h"
#include "qclasstest4.h"

QtTestWidgetPlugin::QtTestWidgetPlugin(QObject *parent)
    : QObject(parent)
{
    m_initialized = false;
}

void QtTestWidgetPlugin::initialize(QDesignerFormEditorInterface * /* core */)
{
    if (m_initialized)
        return;

    // Add extension registrations, etc. here

    m_initialized = true;
}

bool QtTestWidgetPlugin::isInitialized() const
{
    return m_initialized;
}

QWidget *QtTestWidgetPlugin::createWidget(QWidget *parent)
{
    return new QCLASSTEST4(parent);
}

QString QtTestWidgetPlugin::name() const
{
    return QLatin1String("QCLASSTEST4");
}

QString QtTestWidgetPlugin::group() const
{
    return QLatin1String("My Plugins");
}

QIcon QtTestWidgetPlugin::icon() const
{
    return QIcon();
}

QString QtTestWidgetPlugin::toolTip() const
{
    return QLatin1String("");
}

QString QtTestWidgetPlugin::whatsThis() const
{
    return QLatin1String("");
}

bool QtTestWidgetPlugin::isContainer() const
{
    return false;
}

QString QtTestWidgetPlugin::domXml() const
{
    return QLatin1String("<widget class=\"QCLASSTEST4\" name=\"mQCLASSTEST4\">\n</widget>\n");
}

QString QtTestWidgetPlugin::includeFile() const
{
    return QLatin1String("qclasstest4.h");
}
#if QT_VERSION < 0x050000
Q_EXPORT_PLUGIN2(qttestwidgetplugin, QtTestWidgetPlugin)
#endif // QT_VERSION < 0x050000

3、关于在同一个DLL中封装多个自定义控件

参考链接:Qt-QtDesigner插件编写_qdesignercustomwidgetcollectioninterface-CSDN博客

 介绍:

Plugin结尾的类用于提供有用的组件信息给Qt Designer,非Plugin结尾的类表示自定义组件的实现。每一个组件都需要一个Plugin类

bool isContainer() const;//组件是否为容器,容器可包含其他QWidget
bool isInitialized() const;//是否已经初始化
QIcon icon() const;//Designer中的Widget Box的icon
QString domXml() const;//组件的属性描述。主要包括拖入时的默认大小
QString group() const;//Designer中的Widget Box的分组
QString includeFile() const;//uic自动生成时自动包括的头文件
QString name() const;//组件名称
QString toolTip() const;//Designer中组件tips
QString whatsThis() const;//Designer中组件详细说明
QWidget *createWidget(QWidget *parent);//创建组件
void initialize(QDesignerFormEditorInterface *core);//初始化组件
 

注意:

        如果是多个控件,每个组件的plug类都需要把下图中Q_PLUGIN_METADATA注释掉

 创建一个管理类,用来管理多个组件plug,参考如下图

#pragma once

#include <QObject>
#include <QtUiPlugin/QDesignerCustomWidgetCollectionInterface>

class CustomWidgets : public QObject, public QDesignerCustomWidgetCollectionInterface
{
	Q_OBJECT
		Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface")
		Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)

public:
	CustomWidgets(QObject* parent = 0);
	QList<QDesignerCustomWidgetInterface*> customWidgets() const override;

private:
	QList<QDesignerCustomWidgetInterface*> widgets;
};



#include "QtClass2.h"
#include "QtDesignerWidget2Plugin.h"
#include "QtClassPlugin2.h"
#include <QtCore/QtPlugin>

CustomWidgets::CustomWidgets(QObject* parent)
	: QObject(parent)
{
	widgets.append(new QtDesignerWidget2Plugin(this));
	widgets.append(new QtClassPlugin2(this));
}

QList<QDesignerCustomWidgetInterface*> CustomWidgets::customWidgets() const
{
	return widgets;
}

4、关于VS下封装自定义控件

目前不带UI的控件可以,QDESIGNER_WIDGET_EXPORT可以不需要这个引申,

Q_DECL_EXPORT 用这个宏来代替,需要注意封装控件dll的时候要加该宏,如果对应的给其他项目调用该控件的话一般需要把这个宏去掉

进阶方式使用宏定义来进行一个判断(在封装dll项目中添加宏定义,可以右键点击工程-->属性-->c/c++-->预处理器-->预处理器定义)

#ifdef QtDesignerWidget3Test
	class Q_DECL_EXPORT SwitchButton : public QWidget
#else
	class  SwitchButton : public QWidget
#endif

示例程序如下

#pragma once

#include <QtWidgets/QWidget>
#include <QtUiPlugin/QDesignerExportWidget>

class  QtDesignerWidget2 : public QWidget
{
    Q_OBJECT

public:
    QtDesignerWidget2(QWidget *parent = nullptr);
};





#include "QtDesignerWidget2.h"
#include "QPushButton"

QtDesignerWidget2::QtDesignerWidget2(QWidget *parent)
    : QWidget(parent)
{
	QPushButton *button = new QPushButton(this);
	button->setText("custom button");
}

5、给自定义控件加属性栏

参考链接:Qt之自定义属性Q_PROPERTY专题(1)充分理解其概念以及用途-WinFrom控件库|.net开源控件库|HZHControls官网 

一个属性的行为就像类的数据成员,但是它还具有附加的特性,这些特性可以被元数据对象系统操作。这些特性是:

需要一个READ访问器函数。用于读属性的值。理想情况下,有一个不变的函数用于此目的,并且它必须返回属性的类型的值或指针或引用。例如,QWidget::focus是一个只读的属性,它对应一个读函数:QWidget::hasFocus()。

一个可选的WRITE访问器函数。它用于设置属性的值。它必须返回空并且至少具有一个参数,参数是属性类型的值或指针或引用。例如:QWidget::enabled具有WRITE函数QWidget::setEnable()。只读属性不需要写函数。例如,QWidget::focus没有对应的写函数。

一个可选的RESET函数。用于设置属性的值到它的默认值。例如:QWidget::cursor具有典型的READ和WRITE函数,QWidget::cursor()和QWidget::setCursor(),并且它也具有一个RESET函数,QWidget::unsetCursor()。RESET函数必须返回void并且不带有任何参数。

一个可选的NOTIFY信号。如果被定义了,信号将在属性的值改变时发出。信号必须带有一个参数,这个参数的类型必须与属性相同;参数保存的是属性的新值。

一个DESIGNABLE变量表明此属性是否在界面设计器的属性编辑器中出现。大多数属性是可见的,除了为这个变量传入true或false,你还可以指定一个bool型的成员函数。

SCRIPTABLE变量表明这个属性是否可以被一个脚本引擎操作(默认是true)。你也可以赋予它true或false或bool型函数。

STORED变量表明了属性是否被认为是独立存在还是依赖于其它的值而存在。它也表明是否在保存对象状态时保存此属性的值。大多数属性都是需要保存的,但是,如QWidget::minimumWidth()就是不被保存的,因为它的值是从另一个属性QWidget::minimumSize()得来的。

USER变量表明属性是否被设计为面向用户的或用户可修改的类属性。通常,每个类只有一个USER属性。例如,QAbstractButton::checked是按钮类的用户可修改属性。注意QItemDelegate获取和设置widget的USER属性。

CONSTANT的出现表明属性的值是不变的。对于一个object实例,常量属性的READ方法在每次被调用时必须返回相同的值。此常量值可能在不同的object实例中不相同。一个常量属性不能具有WRITE方法或NOYIFY信号。

FINAL变量的出现表明属性不能被派生类所重写。有些情况下,这可以用于效率优化,但不是被moc强制的。程序员必须永远注意不能重写一个FINAL属性。

READ,WRITE和RESET函数都可以被继承。它们也可以是虚函数。当它们在被多重继承中被继承时,它们必须出现在第一个被继承的类中。属性的类型可以是被QVariant支持的所有类型,也可以是用户定义的类型。在下面的例子中,类QDate被当作用户自定义类型。

Q_PROPERTY(QDate data READ getDate WRITE setDate)

因为QDate是用户定义的,你必须包含<QDate>头文件。

   对于QMap,QList和QValueList属性,属性的值是一个QVariant,它包含整个list或map。注意Q_PROPERTY字符串不能包含逗号,因为逗号会划分宏的参数。因此,你必须使用QMap作为属性的类型而不是QMap<QString,QVariant>。为了保持一致性,也需要用QList和QValueList而不是QList<QVariant>和QValueList<QVariant>。

 1.在头文件进行声明

Q_PROPERTY(QString m_text READ getText WRITE setText)

QString m_text 自定义变量

READ,WRITE 关键词

getText,setText 自定义函数  getText为const修饰不变的

2.示例代码

#ifndef QCLASSTEST4_H
#define QCLASSTEST4_H

#include <QWidget>
#include <QtUiPlugin/QDesignerExportWidget>
namespace Ui {
class QCLASSTEST4;
}

class QDESIGNER_WIDGET_EXPORT QCLASSTEST4 : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(QString m_text READ getText WRITE setText)
public:
    explicit QCLASSTEST4(QWidget *parent = nullptr);
    ~QCLASSTEST4();

    QString getText() const
    {
        return m_text;
    }

    void setText(QString s);

private:
    Ui::QCLASSTEST4 *ui;
    QString m_text;
};

#endif // QCLASSTEST4_H


#include "qclasstest4.h"
#include "ui_qclasstest4.h"

QCLASSTEST4::QCLASSTEST4(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::QCLASSTEST4)
{
    ui->setupUi(this);
}

QCLASSTEST4::~QCLASSTEST4()
{
    delete ui;
}

void QCLASSTEST4::setText(QString s)
{
    m_text = s;
    ui->label->setText(s);
}

注意:

如果像有枚举类型这种特殊类型,需要加头文件进行引用 

例如:

Q_OBJECT
		Q_ENUMS(ButtonStyle)

		Q_PROPERTY(int space READ getSpace WRITE setSpace)

Q_ENUMS 是 Qt 提供的一种宏,用于将一个枚举类型注册为 Qt 的元对象系统中的一个类型。这样,我们就可以使用 Qt 的反射机制来操作这个枚举类型,比如通过字符串名字来查找枚举值,或者在 Qt 的各种属性框架中使用这个枚举类型等。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐