Qt Designer自定義插件(QSwitchButton)
創建自定義插件
在使用Qt Designer設計窗體界面時,我們可以使用Widget Box裏的窗體控件非常方便的繪製界面,比如拖進去一個按鈕,一個文本編輯器等。雖然Qt Designer裏的控件可以滿足我們大部分的需求,但是有時候,也會產生一些自定義的需要,比如Switch開關。
下面就以此爲例,講解一下如何創建自定義的窗體控件。
第一步:創建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控件,我們可以像使用其它控件一樣,把我們自己的控件拖繪到窗體上,如下圖所示:
如果自定義控件沒有出現在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
注意:
- 自定義控件類頭文件引入,Qt5.7以下版本爲
#include <QtDesigner/QDesignerExportWidget>
以上版本爲#include <QtUiPlugin/QDesignerExportWidget>
- 類名前必須加入
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
這樣就不必對每個項目分別進行設置了。