Qt属性编辑控件QtnProperty

QtnProperty是一个开源的第三方Qt库,参考下面链接地址可以下载最新的版本。
git:https://github.com/lexxmark/QtnProperty

基础使用说明,以Qt5.8.0mingw开发环境为例:

1、编译静态链接库

目录Core和PropertyWidget是需要编译的两个静态库,将其编译后会在bin-win目录下生成libQtnPropertyCore.a和libQtnPropertyWidget.a两个静态链接库,注意的是config.pri中已经指定了目标路径,如果需要改变生成路径,请在config.pri中修改,同样的,其他所有的子项目都应该包含这个文件,方便将所有的生成文件都放到同一个地方;

2、在自己的项目中使用QtnProperty库

在自己的项目*.pro中,包含下面代码:

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

这里将config.pri包含进来正如前面说的是要将exe程序和.a库文件生成到同一个地方,引入QtnProperty.pri类似于VC中的库头文件一样。然后将库文件打包到pro配置文件:

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库的啦!

3、属性设置项详解

在使用之前,需要先调用initQtnPropertyWidgetLibrary()这个函数,在PropertyDelegateFactory中声明。进入这个函数可以看到,该函数主要是注册属性项的代理类,如果想了解每个属性项是如何实现的,可以查看其中的实现。比如打开regBoolDelegates()这个函数:

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,可以在代码中这样写:

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

再看regIntDelegates()这个函数,提供了SpinBox和SliderBox两个代理类实现:

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

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

我们进入QtnPropertyDelegateInt这个代理类,发现所有的代理类其实都实现了两个接口:

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);
4、示例代码
#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;
}

最后上个效果截图:

232827_m4PV_3489228.png

转载于:https://my.oschina.net/u/3489228/blog/1546806

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值