Qt之自定義插件(for Qt Designer)


    之前Blog里面有關於QWT的編譯、配置、使用的文章,分別是在VS與Creator下進行的。

    里面介紹了如何將QWT集成到Designer中。如果認真研究過的話,那么對Designer中使用插件應該就不再陌生了。
    下面介紹下自己如何去實現一個插件並將其應用到Designer中。
    也可參考:Creating Custom Widgets for Qt Designer.
 
插件介紹:
    Qt Designer基於插件的架構允許用戶自定義和第三方的自定義窗口部件進行編輯,就像用標准的Qt控件一樣。所有的自定義部件功能提供給Qt Designer,包括部件屬性,信號和槽。由於Qt Designer在設計過程中采用真實部件,所以預覽的時候自定義部件會和設計階段的一樣。
    好的,那先上一個預覽的效果吧!
    如圖,Designer中包含了自定義插件(Clock、Qled)以及第三方插件(QWT),好的,先看看效果,后面會有具體講解怎么實現的,慢慢來。。。
 
    要為Qt Designer集成自定義窗口部件,則需要一個合適的窗口部件和適當的.pro文件。
 
提供了一個接口描述
    為了通知Qt Designer想要提供窗口部件的類型,則需要創建一個QDesignerCustomWidgetInterface的子類,其中描述了部件暴露的各種屬性,其大多數是由基類中的純虛函數提供的,因為只有插件的作者可以提供這方面的信息。

編號

函數

返回值描述

1

name()

提供了插件的類名稱

2

group()

該控件所屬的組中的Qt Designer的小工具盒

3

toolTip()

一個簡短的說明,以幫助用戶識別Qt Designer中的部件

4

whatsThis()

為Qt Designer用戶設計的部件一個較長的描述

5

includeFile()

頭文件必須包含在使用該插件的應用程序的。此信息存儲在UI文件中,並將由UIC創建用於包含自定義插件形式的代碼合適的#includes語句。

6

icon()

Qt Designer的插件箱中小窗口的圖標

7

isContainer()

true表示部件將用來保存子部件,否則為false

8

 

 

 

9

 

 

10

createWidget()

 

 

domXml()

 

 

codeTemplate()

一個指向自定義窗口小部件的QWidget指針實例,構建了所提供的父母。

注:createWidget()是一個工廠方法,只負責創建小部件的功能。自定義窗口小部件的屬性將不可用,直到load()返回。

 

描述了部件的屬性,例如:對象名稱、大小提示,以及其它標准的QWidget屬性的描述。

 

這個函數是預留給Qt Designer將來使用的

 
    其它兩個虛函數也可以重新實現

編號

函數

返回值描述

11

initialize()

設置了自定義窗口部件擴展等功能。自定義容器擴展(見QDesignerContainerExtension)和任務菜單擴展(見QDesignerTaskMenuExtension)應在此函數中設置。

12

isInitialized()

如果該部件已被初始化,則返回true;否則返回false。重新實現通常檢查initialize()函數是否已被調用,並返回本次測試的結果。

 

   
 
domXml() 函數的注意事項:
    domXml()函數返回一個UI文件代碼段,使用Qt Designer窗口工廠創建一個自定義窗口部件和使用特性。
    從Qt4.4開始,Qt Designer的窗口部件中允許一個完整的UI文件來描述一個自定義窗口部件。UI文件可以使用標簽加載。指定標簽允許添加元素,其中包含自定義窗口部件的其它信息。如果不需要更多的信息,那么標簽已經足夠了。
    如果自定義窗口部件不提供合理的尺寸,有必要通過在子類的domXml()函數返回的字符串中指定默認的位置大小(geometry)。例如,由自定義的Widget插件示例提供的AnalogClockPlugin,通過下面的方式來指定默認的部件位置大小:
 
    ...
           "  \n"
           "   \n"
           "    0\n"
           "    0\n"
           "    100\n"
           "    100\n"
           "   \n"
           "  \n"
    ...
    domXml()函數的另一個特點是,如果它返回一個空字符串,部件不會安裝在Qt Designer的窗口部件盒中。然而,它仍然可以被其它形式的部件所使用。這個特性用來隱藏部件,不應由用戶顯式地創建,但需要其它部件創建。
     一個完整的自定義部件格式是這樣的:
 displayname="MyWidget">
    
    
        
            widgets::MyWidget
            addPage
            
                
        
    
標簽的屬性:
屬性 呈現形式 內容
language 可選項 "c++",
"jambi"
這個屬性指定了自定義窗口部件提供的語言。
主要有防止C++插件出現在Qt Jambi中。
displayname 可選項 類名 屬性的值將出現在小工具框,可以用來剝去命名空間。
    標簽告訴Qt Designer和UIC應采用哪種方法將頁面添加到一個容器組件中。這適用於容器構件需要調用特定的方法來添加一個孩子,而不是通過父親來添加孩子。特別是,這是相關的容器,不是一個Qt Designer提供的子類容器,但是基於當前頁面的概念。此外,您需要提供一個容器擴展他們。
    元素可以包含屬性的元信息的列表。目前,支持字符串類型的屬性。對於這些屬性,所述標記都可以使用。該標簽具有以下屬性:
 
屬性 呈現形式 內容
name 必須的 該屬性的名稱
type 必須 見下表 該屬性的值決定了屬性編輯器將如何處理它們。
notr 可選項 "true",
"false"
如果屬性是“true”,則該值意味着不再被翻譯。
字符串屬性的類型屬性的值:
類型
"richtext" 富文本
"multiline" 多行純文本
"singleline" 單行純文本
"stylesheet" 一個CSS樣式表
"objectname" 對象名稱(受限制的一組有效字符)
"url" URL、文件名.
插件要求
    為了讓插件在所有平台上正常工作,你需要確保他們導出了Qt Designer所需要的符號。
    首先,插件類必須被Qt Designer加載的插件按順序導出。使用Q_PLUGIN_METADATA()宏來做到這一點。此外,QDESIGNER_WIDGET_EXPORT宏必須被使用,來定義Qt Designer將實例化的插件中每一個自定義窗口部件類。
 
創建一個良好的插件:
    一些自定義窗口部件有專門的用戶界面功能,可以使他們的行為不同於Qt Designer中的其它標准窗口部件。特別是,如果一個自定義小部件由於調用QWidget::grabKeyboard()來捕獲鍵盤,Qt Designer的操作將受到影響。
    為了讓自定義部件在Qt Designer有特殊行為,提供 initialize()函數來配置窗口部件運行過程中的特定行為。該函數在被第一次調用之前先調用createWidget(),可以設定一個內部標志來測試什么時候調用createWidget()函數。
 
1. 構建插件
    為了簡單期間,這里只提供QLed的源碼,customwidgetplugin的源碼可在安裝目錄中的Demo里面查找(例:D:\Qt\Qt5.1.1\5.1.1\msvc2010\examples\designer\customwidgetplugin)。
 
qledplugin.pro
#CONFIG      += designer plugin debug_and_release
#TARGET      = $$qtLibraryTarget($$TARGET)
#TEMPLATE    = lib
#QT += svg

#QTDIR_build:DESTDIR     = $$QT_BUILD_TREE/plugins/designer

CONFIG      += plugin
CONFIG      += designer
CONFIG      += debug_and_release
TEMPLATE    = lib
QT          += svg widgets designer

HEADERS     = qled.h \
              qledplugin.h
SOURCES     = qled.cpp \
              qledplugin.cpp

RESOURCES = qled.qrc

target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target sources

# install
#target.path = $$[QT_INSTALL_PLUGINS]/designer
#sources.files = $$SOURCES $$HEADERS *.pro
#sources.path = $$[QT_INSTALL_EXAMPLES]/designer/qledplugin
#INSTALLS += target sources
qled.h
#ifndef QLED_H
#define QLED_H

#include <</span>Qt> #include <</span>QWidget> #include <</span>QtDesigner/QDesignerExportWidget> class QColor; class QSvgRenderer; class QDESIGNER_WIDGET_EXPORT QLed : public QWidget { Q_OBJECT Q_ENUMS (ledColor) Q_ENUMS (ledShape) Q_PROPERTY(bool value READ value WRITE setValue); Q_PROPERTY(ledColor onColor READ onColor WRITE setOnColor); Q_PROPERTY(ledColor offColor READ offColor WRITE setOffColor); Q_PROPERTY(ledShape shape READ shape WRITE setShape) public: QLed(QWidget *parent = 0); virtual ~QLed(); bool value() const { return m_value; } enum ledColor { Red=0,Green,Yellow,Grey,Orange,Purple,Blue }; enum ledShape { Circle=0,Square,Triangle,Rounded}; ledColor onColor() const { return m_onColor; } ledColor offColor() const { return m_offColor; } ledShape shape() const { return m_shape; } public slots: void setValue(bool); void setOnColor(ledColor); void setOffColor(ledColor); void setShape(ledShape); void toggleValue(); protected: bool m_value; ledColor m_onColor, m_offColor; int id_Timer; ledShape m_shape; QStringList shapes; QStringList colors; void paintEvent(QPaintEvent *event); private: QSvgRenderer *renderer ; }; #endif 
qled.cpp
#include 
#include 
#include 
#include 
#include 
#include 

#include "qled.h"

QLed::QLed(QWidget *parent)
    : QWidget(parent)
{
    m_value=false;
    m_onColor=Red;
    m_offColor=Grey;
    m_shape=Circle;
    shapes << ":/resources/circle_" << ":/resources/square_" << ":/resources/triang_" << ":/resources/round_";
    colors << "red.svg" << "green.svg" << "yellow.svg" << "grey.svg" << "orange.svg" << "purple.svg" << "blue.svg";

    renderer = new QSvgRenderer();
}
QLed::~QLed() {
    delete renderer;
}


void QLed::paintEvent(QPaintEvent *)
{

    QString ledShapeAndColor;
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);

    ledShapeAndColor=shapes[m_shape];

    if(m_value)
        ledShapeAndColor.append(colors[m_onColor]);
    else
        ledShapeAndColor.append(colors[m_offColor]);

    renderer->load(ledShapeAndColor);
    renderer->render(&painter);

}

void QLed::setOnColor(ledColor newColor)
{
    m_onColor=newColor;
    update();
}

void QLed::setOffColor(ledColor newColor)
{
    m_offColor=newColor;
    update();
}

void QLed::setShape(ledShape newShape)
{
    m_shape=newShape;
    update();
}

void QLed::setValue(bool value)
{
    m_value=value;
    update();
}

void QLed::toggleValue()
{
    m_value=!m_value;
    update();
}
qledplugin.h
#ifndef CUSTOMWIDGETPLUGIN_H
#define CUSTOMWIDGETPLUGIN_H

#include <</span>QDesignerCustomWidgetInterface>
class QLedPlugin : public QObject, public QDesignerCustomWidgetInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface" FILE "QLedPlugin.json") Q_INTERFACES(QDesignerCustomWidgetInterface) public: QLedPlugin(QObject *parent = 0); bool isContainer() const; bool isInitialized() const; QIcon icon() const; QString domXml() const; QString group() const; QString includeFile() const; QString name() const; QString toolTip() const; QString whatsThis() const; QWidget *createWidget(QWidget *parent); void initialize(QDesignerFormEditorInterface *core); private: bool initialized; }; #endif
qledplugin.cpp
#include "qled.h" #include "qledplugin.h" #include <</span>QtPlugin> QLedPlugin::QLedPlugin(QObject *parent) : QObject(parent) { initialized = false; } void QLedPlugin::initialize(QDesignerFormEditorInterface * ) { if (initialized) return; initialized = true; } bool QLedPlugin::isInitialized() const { return initialized; } QWidget *QLedPlugin::createWidget(QWidget *parent) { return new QLed(parent); } QString QLedPlugin::name() const { return "QLed"; } QString QLedPlugin::group() const { return "Led Widgets"; } QIcon QLedPlugin::icon() const { return QIcon(":resources/qled.png"); } QString QLedPlugin::toolTip() const { return tr("Led Custom widget Plugin fot Qt Designer"); } QString QLedPlugin::whatsThis() const { return tr("Led Custom widget Plugin fot Qt Designer"); } bool QLedPlugin::isContainer() const { return false; } QString QLedPlugin::domXml() const { return "\n" " \n" " \n" " 0\n" " 0\n" " 50\n" " 50\n" " \n" " \n" " \n" " Binary Led\n" " \n" " \n" " false\n" " \n" " \n" " Led widget\n" " \n" " \n" " QLed::Red\n" " \n" " \n" " QLed::Grey\n" " \n" " \n" " QLed::Circle\n" " \n" "\n"; } QString QLedPlugin::includeFile() const { return "qled.h"; } 
    我相信到這里所有的東西都已經很清楚了,記得不要忘記QLedPlugin.json文件喔,當然最后也不能少資源文件:

    經過編譯,后會生成一個qledplugin.lib與qledplugin.dll,
 
2.配置插件
    qt安裝目錄以D:\Qt\Qt5.1.1\5.1.1\msvc2010為例:
(1)將編譯好的qledplugin.dll拷貝到D:\Qt\Qt5.1.1\5.1.1\msvc2010\bin目錄下,
   將qledplugin.lib拷貝到D:\Qt\Qt5.1.1\5.1.1\msvc2010\lib下
(2)將qledplugin.dll拷貝到D:\Qt\Qt5.1.1\5.1.1\msvc2010\plugins\designer目錄下。
(3)將qled.h和qled.cpp放入一個空文件夾QLed中,再將該文件夾拷貝到D:\Qt\Qt5.1.1\5.1.1\msvc2010\include目錄下。
 
3.使用插件
 新建項目,然后進行配置,主要看下.pro的寫法,如下:  
QT       += core gui svg

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = TestCustomWidgetPlugin
TEMPLATE = app

INCLUDEPATH += $$(QTDIR)/include/QCustomWidgetPlugin
INCLUDEPATH += $$(QTDIR)/include/QLed

LIBS += $$(QTDIR)/lib/customwidgetplugin.lib \
        $$(QTDIR)/lib/qledplugin.lib

SOURCES += main.cpp\
        widget.cpp

HEADERS  += widget.h

FORMS    += widget.ui
這樣所有的任務都完成了,很輕松的就可以在designer里面設計並預覽了。
 
效果如下:
 
 
注:
    技術在於交流、溝通,轉載請注明出處並保持作品的完整性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM