Qt-自定义控件

前言

1. Qt实现自定义控件的方法主要有两种,一是提升法,二是插件法,本文将对这两种方法进行详细介绍。

2. 完整的代码示例在绑定的资源中,审核通过后,大家可以免费下载。

一 提升法

1. 说明

1.1 Qt 提升法是一种将界面设计工具(Qt Designer)中的标准控件替换为自定义控件,并对自定义控件进行高度定制的技术。

1.2 提升法制作的自定义控件是对标准控件的扩展。

1.3 提升法制作的自定义控件只能在本程序中使用。

2. 步骤

 1. 在UI设计界面中拖拽一个标准控件,可以拖拽任意类型的控件,例如:QWidget、QPushButton 等。

 2. 创建一个自定义类,继承于1中拖拽的控件类型。

 3. 在UI涉及界面中选中控件,右键点击,选择"提升为",在弹出的界面中填写相关信息,最后点击"提升"按钮完成提升操作。此时,Qt Designer 会将所选的控件替换为自定义控件。

 4. 使用提升后的控件:在UI设计界面修改自定义控件的属性、在代码中重写自定义控件的方法等

补充:将多个控件组合为自定义控件的方法:

  4.1 在UI设计界面中拖拽一个 QWidget 控件

  4.2 创建一个自定义类,继承于 QWidget;并在类中创建组合控件中的各个子控件实例对象,在类的构造函数中使用布局来管理子控件组件,重写方法实现自定义组合控件的功能。

  4.3 将  QWidget 控件提升为自定义类。

3. 举例

        创建一个自定义控件,根据鼠标的不同事件,自定义控件显示不同的状态。

        完整代码在绑定的资源中,审核通过后,大家可以免费下载。

二 插件法

1. 说明

1.1 Qt 插件法是一种通过创建插件并在插件中添加自定义控件,使自定义控件能在多个 Qt 项目中共享和使用的技术。

1.2 插件法制作的自定义控件是完全独立的控件。

1.3 插件法制作的自定义控件是一个插件,可以提供给其他程序使用;还可以在 Qt Designer 中拖拽使用。

2. 制作自定义控件插件

2.1 使用 Qt 向导创建一个包含 Widgets 模块的动态库项目。

2.2 创建插件

第一步:添加一个继承于 QObject 和 QDesignerCustomWidgetInterface 的插件类,生成插件类的 .h 和 .cpp 文件。

第二步:修改 CMakeLists.txt,添加 QDesignerCustomWidgetInterface 模块:
#查找 Designer 模块
find_package(Qt${QT_VERSION_MAJOR} NAMES Qt6 Qt5 QUIET COMPONENTS Designer)

add......

#指定 Designer 模块头文件的搜索路径
target_include_directories(QtPlugin PRIVATE ${Qt${QT_VERSION_MAJOR}_DESIGNER_INCLUDE_DIRS})

#链接 Designer 模块的库文件
target_link_libraries(QtPlugin PRIVATE Qt${QT_VERSION_MAJOR}::Designer)

第三步:声明插件必须的宏
//启用 Qt 的元对象系统
Q_OBJECT;

//声明插件类实现的接口
Q_INTERFACES(QDesignerCustomWidgetInterface)

//向插件中添加接口IID,用于标识插件
Q_PLUGIN_METADATA(IID QDesignerCustomWidgetInterface_iid)
第四步 重写 QDesignerCustomWidgetInterface 的纯虚函数
 

2.3 创建自定义控件
第一步:添加一个继承于 QWidget 的自定义控件类,生成自定义控件类的 .h 和 .cpp 文件;不要创建UI文件。
第二步:通过代码实现自定义控件的功能,不要使用UI设计界面拖拽控件。

第三步:使用宏 QTPLUGIN_EXPORT 将自定义控件类声明为导入/导出类。 
第四步:在插件类的 createWidget() 函数中实例化自定义控件,并传出(QWidget *)。

3. 使用自定义控件插件

使用自定义插件的方法有四种,如下:

3.1 使用 Qt Designer 加载自定义插件
      3.1.1 将编译生成的插件库(.dll)复制到MSVC编译器路径下,路径参考:...\MSVC...\plugins\designer

      3.1.2 打开MSVC2019版本的qt设计师软件,在软件左侧最下面就可以看到刚刚我们生成的插件,可以通过拖拽的方式使用自定义控件。

      3.1.3 说明:因为我使用的编译器是 MinGW 而不是 MSVC,所以不再做深层次的研究。

3.2 使用 QtCreator 加载自定义插件
      3.2.1 将编译生成的插件库(.dll)复制到 QtCreator 路径下

      3.2.2 重启 QtCreator,创建一个新的 Qt 窗口程序,进入UI设计界面,点击“工具”—>“Form Editor"—>”About Qt Designer Plugins“,在弹窗界面点一下”刷新“,然后就可以看到已经识别到我们的插件了。可以通过拖拽的方式使用自定义控件。

      3.2.3 注意:生成自定义控件插件的编译器版本要和 QtCreator 版本一致。因为我使用的编译器是 MinGW,QtCreator 版本是 Based on Qt 6.6.3 (MSVC 2019, x86_64),所以不再做深层次的研究。

3.3 像使用动态库一样,隐式链接插件库,静态调用插件提供的功能函数

3.4 通过 PluginInterface 动态加载插件,使用插件提供的功能函数

4. 部分代码示例,完整的代码在绑定的资源中,审核通过后大家可以免费下载 

//一 插件类
class CustomControlPlugin : public QObject, public QDesignerCustomWidgetInterface
{
    //启用 Qt 的元对象系统
    Q_OBJECT;

    //声明插件类实现的接口
    Q_INTERFACES(QDesignerCustomWidgetInterface)

    //向插件中添加接口IID,用于标识插件
    Q_PLUGIN_METADATA(IID QDesignerCustomWidgetInterface_iid)

public:
    explicit CustomControlPlugin(QObject *parent = nullptr);
    ~CustomControlPlugin();

    bool isContainer() const override;
    bool isInitialized() const override;
    QIcon icon() const override;
    QString domXml() const override;
    QString group() const override;
    QString includeFile() const override;
    QString name() const override;
    QString toolTip() const override;
    QString whatsThis() const override;
    QWidget *createWidget(QWidget *parent) override;
    void initialize(QDesignerFormEditorInterface *core) override;

private:
    bool m_initialized = false;

    //自定义控件对象
    QWidget *m_pWidget;
};


2. 源文件:

CustomControlPlugin::CustomControlPlugin(QObject *parent)
    : QObject(parent)
{}
CustomControlPlugin::~CustomControlPlugin()
{
    qDebug()<<"插件法创建自定义控件的插件的析构函数调用!";
    delete m_pWidget;
}

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

    // Add extension registrations, etc. here

    m_initialized = true;
}

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

//在插件类的 createWidget 函数中实例化自定义控件对象,并传出对象指针
QWidget *CustomControlPlugin::createWidget(QWidget *parent)
{
    m_pWidget = new CustomControl(parent);
    return m_pWidget;
}

QString CustomControlPlugin::name() const
{
    return QLatin1String("CustomControl");
}

QString CustomControlPlugin::group() const
{
    return QLatin1String("");
}

QIcon CustomControlPlugin::icon() const
{
    return QIcon(":/new/prefix1/qyc.png");
}

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

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

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

QString CustomControlPlugin::domXml() const
{
    return QLatin1String(R"(<widget class="CustomControl" name="customControl">
</widget>)");
}

QString CustomControlPlugin::includeFile() const
{
    return QLatin1String("customcontrol.h");
}
//二 自定义控件类
class QTPLUGIN_EXPORT CustomControl : public QWidget
{
    Q_OBJECT
public:
    explicit CustomControl(QWidget *parent = nullptr);
    ~CustomControl();

private:

    //标签对象
    QLabel *m_pLabel;
    //定时器对象
    QTimer* m_pTimer;
};


3.2 源文件

CustomControl::~CustomControl()
{
    qDebug()<<"插件法创建的自定义控件析构函数调用!";

    //停止定时器
    m_pTimer->stop();
    delete m_pTimer;
}

//在自定义控件类的构造函数中定制自定义控件
CustomControl::CustomControl(QWidget *parent)
    : QWidget{parent}
{
    //设置自定义控件的大小
    this->resize(300, 300);

    //实例化标签对象
    m_pLabel = new QLabel(this);
    //设置标签控件的大小
    m_pLabel->resize(200, 100);
    //设置标签控件显示的初始值
    m_pLabel->setText("自定义控件测试");

    //创建水平布局对象
    QHBoxLayout *layout = new QHBoxLayout(this);
    //将子控件添加到布局中
    layout->addWidget(m_pLabel);
    //将水平布局设置给父窗口对象
    this->setLayout(layout);

    // 实例化定时器对象
    m_pTimer = new QTimer;
    // 设置定时器的时间间隔为1000毫秒
    m_pTimer->setInterval(1000);
    // 设置定时器的精度级别为实时
    m_pTimer->setTimerType(Qt::PreciseTimer);
    // 将定时器信号和 Lambda 表达式表示的槽函数关联
    connect(m_pTimer, &QTimer::timeout, this, [&](){
        // 获取当前系统时间
        QTime curTime = QTime::currentTime();
        // 格式化时间显示
        QString strTime = curTime.toString("hh时 mm分 ss秒 zzz 毫秒");
        // 在控件中显示当前时间
        m_pLabel->setText(strTime);
    });

    //启动定时器
    m_pTimer->start();
}
//三 加载插件,使用插件

    //实例化 QPluginLoader,传入父对象,以管理其生命周期
    loader = new QPluginLoader(this);

    //设置插件的文件路径
    loader->setFileName("G:\\0_Code\\Qt\\15_CustomControl\\2_CustomControl_Plugin\\QtPlugin\\build\\Desktop_Qt_6_7_1_MinGW_64_bit-Debug\\libQtPlugin.dll");

    //获取插件实例
    QObject *plugin = loader->instance();
    if (plugin)
    {
        //将插件实例转换为接口指针
        QDesignerCustomWidgetInterface* interface = qobject_cast<QDesignerCustomWidgetInterface*>(plugin);
        if (interface)
        {
#if 1
            //传入父对象(当前窗口)
            //创建自定义控件对象,并获取指向自定义控件对象的指针
            QWidget *widget = interface->createWidget(this);
#else
            //不传入父对象
            //创建自定义控件对象,并获取指向自定义控件对象的指针
            QWidget *widget = interface->createWidget(nullptr);
            //显示自定义控件
            widget->show();
#endif
        }
        else
        {
            qDebug() << "插件实例转换为接口指针失败!";
        }
    }
    else
    {
        //若获取插件实例失败,打印错误信息
        qDebug() << "获取插件实例失败,错误信息:" << loader->errorString();
    }


    //2. 卸载插件

    //5秒后卸载插件
    QTimer::singleShot(5000, this, [&](){

        //检查插件是否已加载
        if (loader->isLoaded())
        {
            //卸载插件
            loader->unload();
        }
        //delete loader;
    });

  • 14
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值