本文共 10165 字,大约阅读时间需要 33 分钟。
QtPropertyBrowser提供了丰富的示例来展示该扩展是如何使用的。
示例simple展示如下:比如在group中来增加两个按钮,实现组内成员的增减,效果如下:
需要解决以下问题:
选用simple示例中展示的size类型来进行重写,当然你可以选择你感兴趣的任何类型。
QtVectorPropertyManager的实现
继承QtVariantPropertyManager,实现以下接口:
QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property); QtProperty *addProperty(const QString &name);
QtVectorEditoryFactory的实现
继承QtAbstractEditorFactory,实现以下接口:
void connectPropertyManager(QtArrayPropertyManager *manager); QWidget *createEditor(QtArrayPropertyManager *manager, QtProperty *property, QWidget *parent); //关于按钮的,主要在createEditor这个函数里实现。 void disconnectPropertyManager(QtArrayPropertyManager *manager); void pushGroupItem(QtProperty *property); void delGroupItem(QtProperty* property); void btnSignalsSlots();
QtVectorPropertyManager.h
class QtVectorPropertyManager: public QtVariantPropertyManager{ Q_OBJECTpublic: explicit QtVectorPropertyManager(QWidget *parent = 0); virtual ~QtVectorPropertyManager();public: // must a name to identity different group QtProperty *addProperty(const QString &name);// void setValue(const QString &value); void setTreeBrowser(QtAbstractPropertyBrowser* browser); QtAbstractPropertyBrowser* getTreeBrowser();protected: QString displayText(const QtProperty *property) const; QString valueText(const QtProperty *property) const; virtual void initializeProperty(QtProperty *property); virtual void uninitializeProperty(QtProperty *property);private: QMap_propertyToGroup; // 用于动态绑定 QtAbstractPropertyBrowser *_browser;};
QtVectoryPropertyManager.cpp
QtVectoryPropertyManager::QtVectoryPropertyManager(QWidget *parent) : QtVectoryPropertyManager(parent){ }QtVectoryPropertyManager::~QtVectoryPropertyManager(){ }// must a name to identity different groupQtProperty* QtVectoryPropertyManager::addProperty(const QString &name){ // add a top item QtProperty* topItem = QtVariantPropertyManager::addProperty(QVariant::Size, name); _propertyToGroup[topItem] = name; topItem->setGroupBox(true); return topItem;}//void QtVectoryPropertyManager::setValue(const QString &value){ return;}void QtVectoryPropertyManager::setTreeBrowser(QtAbstractPropertyBrowser* browser){ _browser = browser;}QtVectoryPropertyManager* QtArrayPropertyManager::getTreeBrowser(){ return _browser;}QString QtVectoryPropertyManager::displayText(const QtProperty *property) const{ return "";}QString QtVectoryPropertyManager::valueText(const QtProperty *property) const{ // nothing return; //QString text = QtVariantPropertyManager::valueText(property); //if (!_propertyToGroup.contains(property)) // return text; //QString data = _propertyToGroup[property]; return "";}void QtVectoryPropertyManager::initializeProperty(QtProperty *property){ return;}void QtVectoryPropertyManager::uninitializeProperty(QtProperty *property){ QtVariantPropertyManager::uninitializeProperty(property);}
使用模板,确保多类型的兼容。由于用了模板,类的实现也必须在头文件里完成。
templateclass QtVectorEditorFactory : public QtAbstractEditorFactory { public: explicit QtVectorEditorFactory(QObject *parent = 0); virtual ~QtVectorEditorFactory(); PropertyManager* subManager(); EditorFactory* subFactory();protected: void connectPropertyManager(QtVectoryPropertyManager*manager); QWidget *createEditor(QtVectoryPropertyManager*manager, QtProperty *property, QWidget *parent); void disconnectPropertyManager(QtVectoryPropertyManager *manager); void pushGroupItem(QtProperty *property); void delGroupItem(QtProperty* property); void btnSignalsSlots(); private: struct UserEditor { QPushButton* btnAdd = nullptr; QPushButton* btnRemove = nullptr; bool isConnected = false; }; QtVariantEditorFactory *_originalFactory = nullptr; PropertyManager* _manager = nullptr; EditorFactory *_factory = nullptr; QMap _porpertyToEditor; //different group,different index. // auto add index. QMap _propertyIndex; };template QtVectorEditorFactory< PropertyManager, EditorFactory >::QtArrayEditorFactory(QObject *parent) : QtAbstractEditorFactory (parent){ _originalFactory = new QtVariantEditorFactory(this); _manager = new PropertyManager(this); _factory = new EditorFactory(this);}template QtVectorEditorFactory< PropertyManager, EditorFactory >::~QtArrayEditorFactory(){ // not need to delete editor widgets, because they will be deleted by originalFactory in its destructor}template PropertyManager* QtVectorEditorFactory< PropertyManager, EditorFactory >::subManager(){ return _manager;}template EditorFactory* QtVectorEditorFactory< PropertyManager, EditorFactory >::subFactory(){ return _factory;}template void QtVectorEditorFactory< PropertyManager, EditorFactory >::connectPropertyManager(QtVectoryPropertyManager *manager){ _originalFactory->addPropertyManager(manager); // set factory for tpl. manager->getTreeBrowser()->setFactoryForManager(_manager, _factory);}template void QtVectorEditorFactory< PropertyManager, EditorFactory >::prepareSignalsSlots(){ QMap ::Iterator it = _porpertyToEditor.begin(); while (it != _porpertyToEditor.end()) { QtProperty* prop = it.key(); UserEditor ueditor = it.value(); if (!ueditor.isConnected) { // add button click singal and slot; connect(ueditor.btnAdd, &QPushButton::clicked, this, [=] { _propertyIndex[prop]++; this->pushBackGroupItem(prop); }); // del button clicked singal and slot; connect(ueditor.btnRemove, &QPushButton::clicked, this, [=] { this->removeGroupItem(prop); }); ueditor.isConnected = true; _porpertyToEditor[prop] = ueditor; } it++; }}template QWidget *QtVectorEditorFactory< PropertyManager, EditorFactory >::createEditor(QtVectoryPropertyManager*manager, QtProperty *property, QWidget *parent){ // 这里指定了widget的parent,无需delete ... ???? QWidget* groupEditor = new QWidget(); QPushButton* btnAdd = new QPushButton(groupEditor); QPushButton* btnRemove = new QPushButton(groupEditor); UserEditor editor{ btnAdd,btnRemove,false }; _porpertyToEditor[property] = editor; groupEditor->setParent(parent); groupEditor->setToolTip("manager your properties here"); QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); QHBoxLayout *layout = new QHBoxLayout(groupEditor); groupEditor->setAttribute(Qt::WA_StyledBackground, true); groupEditor->setLayout(layout); layout->addItem(spacer); layout->setContentsMargins(0, 0, 0, 0); btnAdd->setFixedWidth(24); btnAdd->setToolTip("add"); btnRemove->setFixedWidth(24); btnRemove->setToolTip("remove"); btnAdd->setIcon(QIcon(":/res/add.svg")); btnRemove->setIcon(QIcon(":/res/remove.svg")); layout->addWidget(btnAdd); layout->addWidget(btnRemove); // bind signals and slots. // prepare signals and slots. btnSignalsSlots(); return groupEditor;}template void QtVectorEditorFactory< PropertyManager, EditorFactory >::disconnectPropertyManager(QtVectoryPropertyManager*manager){ _originalFactory->removePropertyManager(manager); _originalFactory->addPropertyManager(manager);}template void QtVectorEditorFactory< PropertyManager, EditorFactory >::pushGroupItem(QtProperty *property){ QtArrayPropertyManager *manager = propertyManager(property); if (!manager) return; QtProperty* itemTop = property; QList properies = itemTop->subProperties(); QtProperty* item = _manager->addProperty(QString::number(_propertyIndex[property])); properies.append(item); itemTop->addSubProperty(item);}template void QtVectorEditorFactory< PropertyManager, EditorFactory >::delGroupItem(QtProperty* property){ QtVectoryPropertyManager*manager = propertyManager(property); if (!manager) return; QtProperty* itemTop = property; QList subProperties = itemTop->subProperties(); QtBrowserItem * curItem = manager->getTreeBrowser()->currentItem(); // select nothing. if (curItem == nullptr) return; QtProperty* curSelProperty = curItem->property(); // select top item. if (curSelProperty == itemTop) return; // remove selected from subproperties; for (int i = 0; i < subProperties.size(); i++) { if (subProperties.contains(curSelProperty)) { int ret = QMessageBox::warning(NULL, "warning", "Are you sure to remove?", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (ret == QMessageBox::Yes) { //... // remove from list. itemTop->removeSubProperty(curSelProperty); return; } return; } }}
使用方法,以文件的类型为例:
// 创建一个array _arrayManager = new QtVectorPropertyManager(this); _arrayFactory = new QtVectorEditorFactory(this); _arrayManager->setTreeBrowser(_brower); _brower->setFactoryForManager(_arrayManager, _arrayFactory); connect(_arrayFactory->subManager(), &QtFilePathPropertyManager::valueChanged, _arrayFactory->subFactory(), [=](QtProperty *subprop, const QString& val){ // do something ... });
例如:按钮正常状态下也要显示/不设置焦点捕获等
这个group组,正常状态下是需要显示“+”,“-”的,并不是每次点击属性都需要运行createEditor这个函数。这里就需要改qtpropertybrowser的源码了。修改文件qttreepropertybrowser.cpp 函数propertyInserted
void QtTreePropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex){ QTreeWidgetItem *afterItem = m_indexToItem.value(afterIndex); QTreeWidgetItem *parentItem = m_indexToItem.value(index->parent()); QTreeWidgetItem *newItem = 0; if (parentItem) { newItem = new QTreeWidgetItem(parentItem, afterItem); } else { newItem = new QTreeWidgetItem(m_treeWidget, afterItem); } m_itemToIndex[newItem] = index; m_indexToItem[index] = newItem; newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); if ( index->property()->isGroupBox() ) // index->property()->isGroupBox() 是个属性控制,区分正常显示与组框显示的风格。自己添加。。。 { QWidget* editor = createEditor(index->property(), m_treeWidget); editor->setFocusPolicy(Qt::NoFocus); m_treeWidget->setItemWidget(newItem, 1, editor); } m_treeWidget->setItemExpanded(newItem, true); updateItem(newItem);}
至此,基本功能大概完成。很草率,写的代码自己都看不下去,只是提供个思路而已,抛转引玉…哎…
转载地址:http://dmvmb.baihongyu.com/