Qt学习-- Qt Designer自定义插件(QSwitchButton)

Qt Designer自定义插件(QSwitchButton)

创建自定义插件

在使用Qt Designer设计窗体界面时,我们可以使用Widget Box里的窗体控件非常方便的绘制界面,比如拖进去一个按钮,一个文本编辑器等。虽然Qt Designer里的控件可以满足我们大部分的需求,但是有时候,也会产生一些自定义的需要,比如Switch开关。

img

下面就以此为例,讲解一下如何创建自定义的窗体控件。

第一步:创建QtDesigner自定义控件工程

​ 打开Qt Creator,创建一个Qt4 设计师自定义控件,如下图所示:

![Qt Designer自定义插件(QSwitchButton)](F:\技术资料\Blog\图片\Qt Designer自定义插件(QSwitchButton).PNG)

添加自定义类QSwitchButton

![Qt Designer自定义插件(QSwitchButton)1](F:\技术资料\Blog\图片\Qt Designer自定义插件(QSwitchButton)1.PNG)

添加说明(可以忽略,函数中可以修改):

组:该控件所属的组中的Qt Designer的小工具盒;

工具提示:一个简短的说明,以帮助用户识别Qt Designer中的部件;

这是什么:为Qt Designer用户设计的部件一个较长的描述

![Qt Designer自定义插件(QSwitchButton)1-1](F:\技术资料\Blog\图片\Qt Designer自定义插件(QSwitchButton)1-1.PNG)

dom XML:描述了部件的属性,例如:对象名称、大小提示,以及其它标准的QWidget属性的描述。

![Qt Designer自定义插件(QSwitchButton)1-2](F:\技术资料\Blog\图片\Qt Designer自定义插件(QSwitchButton)1-2.PNG)

定义插件名称:

![Qt Designer自定义插件(QSwitchButton)2](F:\技术资料\Blog\图片\Qt Designer自定义插件(QSwitchButton)2.PNG)

第二步:编译控件工程

​ 为了淌通整个自定义控件的编写流程,我们先不做任何更改,切换为Release版本,直接编译一下。

第三步:部署插件

​ 编译完成后,在输出目录下,将生成的dll文件和lib文件一起拷贝到Qt designer和Qt Creator的插件目录下,以我使用的Qt为例完整路径为:

C:\Qt\Qt5.9.1\5.9.1\msvc2015\plugins\designer。

C:\Qt\Tools\QtCreator\bin\plugins\designer

之后,启动Qt designer或Qt Creator,创建一个窗体,此时就会发现在左侧的Buttons里出现了我们自己的Switch Button控件,我们可以像使用其它控件一样,把我们自己的控件拖绘到窗体上,如下图所示:

switchButton1

switchButton2

如果自定义控件没有出现在Widgetbox里,那么此时你可以通过【帮助-关于插件】菜单,打开插件信息对话框,点击刷新按钮,只要你没有忘记把dll和lib文件拷贝到正确的位置,插件都会自动识别并加载。对于其它版本的Qt也一样,比如我自己的电脑里安装了好几个版本的Qt,对于其它版本的Qt,做法也是一样,只需要把插件工程生成的dll和lib文件放置到相应版本的插件目录下去即可。

插件接口

在自动向导创建的插件QSwitchButtonPlugin继承了接口QDesignerCustomWidgetInterface

#ifndef QSWITCHBUTTONPLUGIN_H
#define QSWITCHBUTTONPLUGIN_H

#include <QDesignerCustomWidgetInterface>

class QSwitchButtonPlugin : public QObject, public QDesignerCustomWidgetInterface
{
    Q_OBJECT
    Q_INTERFACES(QDesignerCustomWidgetInterface)
#if QT_VERSION >= 0x050000
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface")
#endif // QT_VERSION >= 0x050000

public:
    QSwitchButtonPlugin(QObject *parent = 0);

    //true表示部件将用来保存子部件,否则为false
    bool isContainer() const;
    //如果该部件已被初始化,则返回true;否则返回false
    bool isInitialized() const;
    //Qt Designer的插件箱中小窗口的图标
    QIcon icon() const;
    //描述了部件的属性,例如:对象名称、大小提示,以及其它标准的QWidget属性的描述。
    QString domXml() const;
    //该控件所属的组中的Qt Designer的小工具盒
    QString group() const;
    //头文件必须包含在使用该插件的应用程序的。此信息存储在UI文件中,并将由UIC创建用于包含自定义插件形式的代码合适的#includes语句。
    QString includeFile() const;
    //提供了插件的类名称
    QString name() const;
    //一个简短的说明,以帮助用户识别Qt Designer中的部件
    QString toolTip() const;
    //为Qt Designer用户设计的部件一个较长的描述
    QString whatsThis() const;
    //一个指向自定义窗口小部件的QWidget指针实例,构建了所提供的父母。注:createWidget()是一个工厂方法,只负责创建小部件的功能。自定义窗口小部件的属性将不可用,直到load()返回。
    QWidget *createWidget(QWidget *parent);
    //设置了自定义窗口部件扩展等功能
    void initialize(QDesignerFormEditorInterface *core);


private:
    bool m_initialized;
};

#endif

可以看到我们在向导中设置的一些信息在相应的函数中体现出来了。

domXml() 函数的注意事项:

domXml()函数返回一个UI文件代码段,使用Qt Designer窗口工厂创建一个自定义窗口部件和使用特性。从Qt4.4开始,Qt Designer的窗口部件中允许一个完整的UI文件来描述一个自定义窗口部件。UI文件可以使用标签加载。指定标签允许添加元素,其中包含自定义窗口部件的其它信息。如果不需要更多的信息,那么标签已经足够了。如果自定义窗口部件不提供合理的尺寸,有必要通过在子类的domXml()函数返回的字符串中指定默认的位置大小(geometry)。

domXml()函数的另一个特点是,如果它返回一个空字符串,部件不会安装在Qt Designer的窗口部件盒中。然而,它仍然可以被其它形式的部件所使用。这个特性用来隐藏部件,不应由用户显式地创建,但需要其它部件创建。

标签的属性:

属性 呈现形式 内容
language 可选项 “c++”,”jambi” 这个属性指定了自定义窗口部件提供的语言。主要有防止C++插件出现在Qt Jambi中。
displayname 可选项 类名 属性的值将出现在小工具框,可以用来剥去命名空间。

如一个基本的domxml:

QString QSwitchButtonPlugin::domXml() const
{
    return QLatin1String("<ui displayname = \"Switch Button\"\n<widget class=\"QSwitchButton\" name=\"qSwitchButton\">\n</widget>\n</ui>\n");
}

QSwitchButton实现

直接上代码

qswitchbutton.h

注意:

  1. 自定义控件类头文件引入,Qt5.7以下版本为#include <QtDesigner/QDesignerExportWidget> 以上版本为#include <QtUiPlugin/QDesignerExportWidget>
  2. 类名前必须加入 QDESIGNER_WIDGET_EXPORT 宏。否则集成到Qt Creator 中编译会报错。不加的话可以在设计器中加载,但是编译会报错
#ifndef QSWITCHBUTTON_H
#define QSWITCHBUTTON_H

#include <QWidget>
#include <QTimer>
#include <QtUiPlugin/QDesignerExportWidget>
#include <QPainter>
namespace Ui {
class QSwitchButton;
}
class QDESIGNER_WIDGET_EXPORT QSwitchButton : public QWidget
{
    Q_OBJECT

public:
    QSwitchButton(QWidget *parent = 0);
    ~QSwitchButton();
private:
    Ui::QSwitchButton *ui;
public:
    // 返回开关状态 - 打开:true 关闭:false
    bool isToggled() const;
    // 设置开关状态
    void setToggle(bool checked);
    // 设置背景颜色
    void setBackgroundColor(QColor color);
    // 设置选中颜色
    void setCheckedColor(QColor bcolor, QColor tcolor);
    // 设置不可用颜色
    void setDisbaledColor(QColor color);
    //设置画笔
    void setDrawPen(QPen bpen = Qt::NoPen, QPen tpen = Qt::NoPen);
protected:
    // 绘制开关
    void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
    void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    // 大小改变事件
    void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
    // 缺省大小
    QSize sizeHint() const Q_DECL_OVERRIDE;
    QSize minimumSizeHint() const Q_DECL_OVERRIDE;
signals:
    // 状态改变时,发射信号
    void toggled(bool checked);

private slots:
private:
    bool m_bChecked;         // 是否选中
    QColor m_background;     // 背景颜色
    QColor m_checkedColor;   // 选中颜色
    QColor m_disabledColor;  // 不可用颜色
    QColor m_thumbColor;     // 拇指颜色
    QColor m_thumbcheckedColor;
    qreal m_radius0, m_radius1;          // 圆角
    qint16 m_width, m_height;
    qreal m_nX;              // x点坐标
    qreal m_nY;              // y点坐标
    qint16 m_nMargin;        // 外边距
    QPen backPen, thumbPen;
    int direction; //开关方向 ,1水平,-1竖直
    void TogglePosition(void);
};

#endif

qswitchbutton.cpp

#include "qswitchbutton.h"
#include <QMouseEvent>
#include "ui_qswitchbutton.h"
QSwitchButton::QSwitchButton(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::QSwitchButton),
    m_width(16),
    m_height(16),
    m_bChecked(false),
    m_radius0(8.0),
    m_radius1(5.0),
    m_nMargin(3),
    m_checkedColor(75, 216, 99),
    m_thumbcheckedColor(Qt::white),
    m_thumbColor(Qt::white),
    m_disabledColor(190, 190, 190),
    m_background(Qt::gray),
    backPen(Qt::NoPen),
    thumbPen(Qt::NoPen),
    direction(1)
{
    ui->setupUi(this);
    // 鼠标滑过光标形状 - 手型
    setCursor(Qt::PointingHandCursor);

}

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

bool QSwitchButton::isToggled() const
{
    return m_bChecked;
}

void QSwitchButton::setToggle(bool checked)
{
    m_bChecked = checked;
    TogglePosition();
}

void QSwitchButton::setBackgroundColor(QColor color)
{
    m_background = color;
}

void QSwitchButton::setCheckedColor(QColor bcolor, QColor tcolor)
{
    m_checkedColor = bcolor;
    m_thumbcheckedColor = tcolor;
}

void QSwitchButton::setDisbaledColor(QColor color)
{
    m_disabledColor = color;
}

void QSwitchButton::setDrawPen(QPen bpen, QPen tpen)
{
    backPen = bpen;
    thumbPen = tpen;
}

void QSwitchButton::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter painter(this);
    backPen = QPen(QColor(Qt::black),1);
    painter.setRenderHint(QPainter::Antialiasing);

    QPainterPath path;
    QColor background;
    QColor thumbColor;
    qreal dOpacity;
    if (isEnabled())
    { // 可用状态
        if (m_bChecked)
        { // 打开状态
            background = m_checkedColor;
            thumbColor = m_thumbcheckedColor;
            dOpacity = 0.600;
        }
        else
        { //关闭状态
            background = m_background;
            thumbColor = m_thumbColor;
            dOpacity = 0.800;
        }
    }
    else
    {  // 不可用状态
        background = m_background;
        dOpacity = 0.260;
        thumbColor = m_disabledColor;
    }

    // 绘制大椭圆
    painter.setPen(backPen);
    painter.setBrush(background);
    painter.setOpacity(dOpacity);
    path.addRoundedRect(QRectF(m_nMargin, m_nMargin, m_width, m_height), m_radius0, m_radius0);
    painter.drawPath(path.simplified());


    // 绘制小椭圆
    painter.setPen(thumbPen);
    painter.setBrush(thumbColor);
    painter.setOpacity(1.0);
    painter.drawEllipse(QRectF(m_nX - m_radius1, m_nY - m_radius1, 2*m_radius1, 2*m_radius1));
}

void QSwitchButton::mouseDoubleClickEvent(QMouseEvent *event)
{
    if (isEnabled())
    {
        if (event->button() == Qt::LeftButton)
        {
            event->accept();
            m_bChecked = !m_bChecked;
            emit toggled(m_bChecked);
            TogglePosition();
        }
        else
        {
            event->ignore();
        }
    }
}

void QSwitchButton::resizeEvent(QResizeEvent *event)
{
    m_width = event->size().width() - 2*m_nMargin;
    m_height = event->size().height() - 2*m_nMargin;
    if(m_width < m_height)
    {
        m_radius0 = 1.0*m_width/2;
        direction = -1;
    }
    else
    {
        m_radius0 = 1.0*m_height/2;
        direction = 1;

    }
    m_radius1 = m_radius0 - m_nMargin;

    TogglePosition();
    QWidget::resizeEvent(event);
}

QSize QSwitchButton::sizeHint() const
{
    return minimumSizeHint();
}

QSize QSwitchButton::minimumSizeHint() const
{
    return QSize(2 * (16 + m_nMargin), 16 + 2 * m_nMargin);
}


void QSwitchButton::TogglePosition(void )
{
    if(m_bChecked)
    {
        if(direction == 1)//水平方向
            {
            m_nX = m_width - m_radius1;
            m_nY = 2*m_nMargin+m_radius1;
        }
        else if(direction == -1)//竖直方向
        {
            m_nX = 2*m_nMargin+m_radius1;
            m_nY = m_height - m_radius1;
        }
        else
        {
            m_nX = 2*m_nMargin+m_radius1;
            m_nY = 2*m_nMargin+m_radius1;
        }

    }
    else
    {
        m_nX = 2*m_nMargin+m_radius1;
        m_nY = 2*m_nMargin+m_radius1;
    }
    update();
}

QSwitchButton的使用

创建一个Qt Widgets Application项目,并将qspinsliderplugin.lib, qspinsliderplugin.dll,qspinsliderplugin.h三个文件复制到当前项目目录下,在.pro中添加qswitchbuttonplugin库文件

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/./ -lqswitchbuttonplugin
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/./ -lqswitchbuttonplugin

INCLUDEPATH += $$PWD/.
DEPENDPATH += $$PWD/.

也可以将qspinsliderplugin.h复制到Qt的Include文件夹下,将qspinsliderplugin.lib复制到Qt的Lib文件夹下,将qspinsliderplugin.dll复制到Qt的Bin文件下,如

C:\Qt\Qt5.9.1\5.9.1\msvc2015\include
C:\Qt\Qt5.9.1\5.9.1\msvc2015\lib
C:\Qt\Qt5.9.1\5.9.1\msvc2015\bin

这样就不必对每个项目分别进行设置了。

猜你喜欢

转载自blog.csdn.net/yizhou2010/article/details/79962682