Qt屬性編輯控件QtnProperty

QtnProperty是一個開源的第三方Qt庫,參考下面連接地址能夠下載最新的版本。
git:https://github.com/lexxmark/QtnPropertygit

基礎使用說明,以Qt5.8.0mingw開發環境爲例:github

一、編譯靜態連接庫

目錄Core和PropertyWidget是須要編譯的兩個靜態庫,將其編譯後會在bin-win目錄下生成libQtnPropertyCore.a和libQtnPropertyWidget.a兩個靜態連接庫,注意的是config.pri中已經指定了目標路徑,若是須要改變生成路徑,請在config.pri中修改,一樣的,其餘全部的子項目都應該包含這個文件,方便將全部的生成文件都放到同一個地方;windows

二、在本身的項目中使用QtnProperty庫

在本身的項目*.pro中,包含下面代碼:app

include(../Config.pri)
include(../QtnProperty.pri)

這裏將config.pri包含進來正如前面說的是要將exe程序和.a庫文件生成到同一個地方,引入QtnProperty.pri相似於VC中的庫頭文件同樣。而後將庫文件打包到pro配置文件:ide

INCLUDEPATH += $$PWD/../Core
INCLUDEPATH += $$PWD/../PropertyWidget
DEPENDPATH += $$PWD/../PropertyWidget
DEPENDPATH += $$PWD/../CorelibQtnPropertyCore.a

CONFIG(debug, debug|release): LIBS += $$PWD/../bin-win/libQtnPropertyCore.a
CONFIG(debug, debug|release): LIBS += $$PWD/../bin-win/libQtnPropertyWidget.a

到此就能夠編譯和使用QtnProperty庫的啦!函數

三、屬性設置項詳解

在使用以前,須要先調用initQtnPropertyWidgetLibrary()這個函數,在PropertyDelegateFactory中聲明。進入這個函數能夠看到,該函數主要是註冊屬性項的代理類,若是想了解每一個屬性項是如何實現的,能夠查看其中的實現。好比打開regBoolDelegates()這個函數:ui

void regBoolDelegates()
{
  QtnPropertyDelegateFactory::staticInstance()
    .registerDelegateDefault(&QtnPropertyBoolBase::staticMetaObject
                 , &qtnCreateDelegate<QtnPropertyDelegateBoolCheck, QtnPropertyBoolBase>
                 , "CheckBox");

  QtnPropertyDelegateFactory::staticInstance()
    .registerDelegate(&QtnPropertyBoolBase::staticMetaObject
              , &qtnCreateDelegate<QtnPropertyDelegateBoolCombobox, QtnPropertyBoolBase>
              , "ComboBox");
}

能夠看到對於bool類型,提供了兩個不一樣的實現,一種是CheckBox,一種是ComboBox,默認是CheckBox實現。若是須要本身實現,能夠參考QtnPropertyDelegateBoolCheck的代碼,仿照實現便可。若是須要選擇ComboBox來實現bool,能夠在代碼中這樣寫:this

auto boolValue = new QtnPropertyBool(propertySet);
QtnPropertyDelegateInfo boolNewDelegate;
boolNewDelegate.name = "ComboBox";
boolValue->setDelegate(boolNewDelegate);

再看regIntDelegates()這個函數,提供了SpinBox和SliderBox兩個代理類實現:spa

void regIntDelegates()
{
  QtnPropertyDelegateFactory::staticInstance()
    .registerDelegateDefault(&QtnPropertyIntBase::staticMetaObject
                 , &qtnCreateDelegate<QtnPropertyDelegateInt, QtnPropertyIntBase>
                 , "SpinBox");

  QtnPropertyDelegateFactory::staticInstance()
      .registerDelegate(&QtnPropertyIntBase::staticMetaObject
                 , &qtnCreateDelegate<QtnPropertyDelegateSlideBoxTyped<QtnPropertyIntBase>, QtnPropertyIntBase>
                 , "SliderBox");
}

咱們進入QtnPropertyDelegateInt這個代理類,發現全部的代理類其實都實現了兩個接口:debug

QWidget* QtnPropertyDelegateInt::createValueEditorImpl(QWidget* parent, const QRect& rect, QtnInplaceInfo* inplaceInfo)
{
    QSpinBox* spinBox = new QSpinBox(parent);
    spinBox->setGeometry(rect);

    new QtnPropertyIntSpinBoxHandler(owner(), *spinBox);

    if (inplaceInfo)
    {
        spinBox->selectAll();
    }

    return spinBox;
}

bool QtnPropertyDelegateInt::propertyValueToStrImpl(QString& strValue) const
{
    strValue = QString::number(owner().value());
    return true;
}

這裏最主要的實現就是這個createValueEditorImpl()函數了,能夠看到SpinBox和SliderBox的區別也就主要在於建立的窗口不同。一樣,若是想提供ComboBox來實現下拉選擇呢?固然也是同樣的,仿照這個類,寫一個相似的代理接口類,在這個函數中實現combobox來選擇數據,那麼問題來了?ComboBox中的數據如何提供?接下來看一個已經實現好的數據選擇類QtnPropertyDelegateIntList,如何將ComboBox中的數據傳遞進去,實現代碼:

QWidget* QtnPropertyDelegateIntList::createValueEditorImpl(QWidget* parent, const QRect& rect, QtnInplaceInfo* inplaceInfo)
{
    if (owner().isEditableByUser())
    {
        QComboBox *comboBox = new QComboBox(parent);

        auto delegate = owner().delegate();
        if (delegate)
        {
            QList<int> values;
            qtnGetAttribute(delegate->attributes, "values", values);
            for (auto value : values)
            {
                comboBox->addItem(QString::number(value), value);
            }
        }

        comboBox->setGeometry(rect);

        // connect widget and property
        new QtnPropertyIntComboBoxHandler(owner(), *comboBox);

        if (inplaceInfo)
            comboBox->showPopup();

        return comboBox;
    }
    else
    {
        QLineEdit *lineEdit = new QLineEdit(parent);
        lineEdit->setReadOnly(true);
        lineEdit->setText(QString::number((int)owner()));

        lineEdit->setGeometry(rect);

        return lineEdit;
    }
}

代碼已經很清晰了,請注意看這兩行:
QList<int> values;
qtnGetAttribute(delegate->attributes, "values", values);
建立ComboBox以後,從一個叫作delegate->attributes的屬性中獲取到QList<int>,而後將其加入到ComboBox中,這個delegate是一個QtnPropertyDelegateInfo類,這就是前面bool屬性設置代碼時用到的QtnPropertyDelegateInfo類,它除了有name屬性外,還有一個attributes屬性,支持QVariant類型,能夠將任意類型的變量傳遞過去。當咱們不知道如何傳遞屬性參數時,就能夠找到代理類,找到createValueEditorImpl()函數,看看中間究竟使用到了那些屬性變量。在這裏只須要傳遞一個QList<int>就能夠了:

QList<int> list;
    for (auto i=0; i<10; i++) {
        list.append(i);
    }
    QtnPropertyDelegateInfo deleInfo;
    deleInfo.name = "IntList";
    deleInfo.attributes.insert("values", QVariant::fromValue(list));
    intValue->setDelegate(deleInfo);

四、示例代碼

#include "widget.h"
#include "ui_widget.h"
#include "PropertySet.h"
#include "PropertyCore.h"
#include "PropertyBase.h"
#include "Core/GUI/PropertyButton.h"
#include "Core/GUI/PropertyQBrush.h"
#include "Core/GUI/PropertyQColor.h"
#include "Core/GUI/PropertyQFont.h"
#include "Core/GUI/PropertyQPen.h"
#include <QMessageBox>
#include <QVector>
#include <QFileDialog>

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

    initQtnPropertyWidgetLibrary();

    QtnPropertySet* propertySet = new QtnPropertySet(this);

    // BOOL的兩種表現形式
    {
        QtnPropertySet* propertyBOOL = new QtnPropertySet(propertySet);
        propertyBOOL->setName("BOOL的兩種表現形式");
        //CheckBox形式
        auto boolValue = new QtnPropertyBool(propertyBOOL);
        boolValue->setName("Bool_CheckBox");
        boolValue->setDescription("It is bool value");
        boolValue->setValue(true);
        //ComboBox形式
        auto boolValue2 = new QtnPropertyBool(propertyBOOL);
        boolValue2->setName("Bool_ComboBox");
        boolValue2->setDescription("It is bool value");
        boolValue2->setValue(false);
        QtnPropertyDelegateInfo boolNewDelegate;
        boolNewDelegate.name = "ComboBox";
        boolNewDelegate.attributes["labelFalse"] = "否";
        boolNewDelegate.attributes["labelTrue"] = "是";
        boolValue2->setDelegate(boolNewDelegate);
    }

    //INT和FLOAT的表現形式
    {
        QtnPropertySet* propertyINT = new QtnPropertySet(propertySet);
        propertyINT->setName("INT的三種表現形式");
        //SpinBox形式
        auto intValue = new QtnPropertyInt(propertyINT);
        intValue->setName("Int_SpinBox");
        intValue->setDescription("This is integer Value 0 ~ 9");
        intValue->setMaxValue(9);
        intValue->setMinValue(0);
        intValue->setValue(1);
        //SliderBox形式
        auto intValue2 = new QtnPropertyInt(propertyINT);
        intValue2->setName("Int_SliderBox");
        intValue2->setDescription("This is integer Value 0 ~ 9");
        intValue2->setMaxValue(9);
        intValue2->setMinValue(0);
        intValue2->setValue(2);
        QtnPropertyDelegateInfo intNewDel1;
        intNewDel1.name = "SliderBox";
        intValue->setDelegate(intNewDel1);
        //IntList形式
        auto intValue3 = new QtnPropertyInt(propertyINT);
        intValue3->setName("Int_List");
        intValue3->setDescription("This is integer Value 0 ~ 9");
        intValue3->setMaxValue(9);
        intValue3->setMinValue(0);
        intValue3->setValue(2);
        QList<int> IntList;
        for (auto i=0; i<10; i++) {
            IntList.append(i);
        }
        QtnPropertyDelegateInfo intNewDel2;
        intNewDel2.name = "IntList";
        intNewDel2.attributes.insert("values", QVariant::fromValue(IntList));
        intValue3->setDelegate(intNewDel2);
        //FLOAT的默認形式
        auto floatValue = new QtnPropertyFloat(propertyINT);
        floatValue->setName("FloatValue");
        floatValue->setDescription("Float value");
        floatValue->setMaxValue(10.f);
        floatValue->setMinValue(0.f);
        floatValue->setStepValue(0.5f);
        floatValue->setValue(5.0f);
    }

    //Enum的表現形式
    {
        QtnPropertySet* propertyENUM = new QtnPropertySet(propertySet);
        propertyENUM->setName("Enum的表現形式");
        auto enumValue = new QtnPropertyEnum(propertyENUM);
        enumValue->setName("設備串口編號:");
        enumValue->setDescription("請選擇正確的設備鏈接端口");

        QVector<QtnEnumValueInfo> vec;
        vec.push_back(QtnEnumValueInfo(0, "NONE", "未選擇"));
        vec.push_back(QtnEnumValueInfo(1, "COM1", "COM1"));
        vec.push_back(QtnEnumValueInfo(2, "COM2", "COM2"));
        vec.push_back(QtnEnumValueInfo(3, "COM3", "COM3"));
        auto enumInfo = new QtnEnumInfo("請選擇串口", vec);
        enumValue->setEnumInfo(enumInfo);
    }

    //窗口屬性
    {
        QtnPropertySet* propertyWnd = new QtnPropertySet(propertySet);
        propertyWnd->setName("Windows窗口屬性");
        //QPoint形式
        auto wndPt = new QtnPropertyQPoint(propertyWnd);
        wndPt->setName("Point");
        wndPt->setDescription("This is Windows Point");
        wndPt->setValue(QPoint(320, 240));
        //QSize形式
        auto wndSize = new QtnPropertyQSize(propertyWnd);
        wndSize->setName("Size");
        wndSize->setDescription("This is Windows Size");
        wndSize->setValue(QSize(640, 480));
        //QRect形式
        auto wndRect = new QtnPropertyQRect(propertyWnd);
        wndRect->setName("Rect");
        wndRect->setDescription("This is the windows rectange.");
        wndRect->setValue(QRect(0, 0, 10, 20));
    }

    //String的三種形式
    {
        QtnPropertySet* propertyStr = new QtnPropertySet(propertySet);
        propertyStr->setName("String的三種形式");
        //LineEdit形式
        auto strEdit = new QtnPropertyQString(propertyStr);
        strEdit->setName("窗口標題");
        strEdit->setDescription("請輸入窗口的標題");
        strEdit->setValue("未命名");
        //File形式
        auto strFile = new QtnPropertyQString(propertyStr);
        strFile->setName("選擇文件路徑");
        strFile->setDescription("請選擇指定的文件");
        QtnPropertyDelegateInfo fileDele;
        fileDele.name = "File";
        fileDele.attributes["acceptMode"] = QFileDialog::AcceptOpen;
        fileDele.attributes["defaultSuffix"] = "Text File | *.txt";
        fileDele.attributes["fileMode"] = QFileDialog::ExistingFile;
        fileDele.attributes["options"] = QFileDialog::ExistingFile;
        fileDele.attributes["viewMode"] = QFileDialog::Detail;
        strFile->setDelegate(fileDele);
        //List形式
        auto strList = new QtnPropertyQString(propertyStr);
        strList->setName("設備類型");
        strList->setDescription("請選擇設備的類型");
        QtnPropertyDelegateInfo listDele;
        listDele.name = "List";
        listDele.attributes["items"] = QStringList()<<"單機設備"<<"聯網設備"<<"其餘類型";
        strList->setDelegate(listDele);
    }

    //雜項
    {
        QtnPropertySet* propertyOther = new QtnPropertySet(propertySet);
        propertyOther->setName("雜項");
        //Button
        auto button = new QtnPropertyButton(propertyOther);
        button->setName("HelloButton");
        button->setDescription("This is Button");
        button->setClickHandler([this](const QtnPropertyButton* btn){
            QMessageBox::information(this, "Message", QString("Button Message from %1 : Hello, I am Button Style !").arg(btn->name()));
        });
        //Brush
        auto brush = new QtnPropertyQBrushStyle(propertyOther);
        brush->setName("Brush");
        brush->setDescription("This is Brush");
        brush->setValue(Qt::SolidPattern);
        //Color
        auto color = new QtnPropertyQColor(propertyOther);
        color->setName("Color");
        color->setDescription("This is Color");
        color->setValue(QColor(255, 0, 0));
        //Font
        auto font = new QtnPropertyQFont(propertyOther);
        font->setName("Font");
        font->setDescription("This is Font");
        font->setValue(QFont("宋體", 10));
        //PenStyle
        auto penStyle = new QtnPropertyQPenStyle(propertyOther);
        penStyle->setName("PenStyle");
        penStyle->setDescription("This is Pen");
        penStyle->setValue(Qt::SolidLine);
        //Pen
//        auto pen = new QtnPropertyQPen(propertyOther);
//        pen->setName("Pen");
//        pen->setValue(QPen(Qt::SolidLine));
    }

    ui->property->setPropertySet(propertySet);
}

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

最後上個效果截圖:

相關文章
相關標籤/搜索