2015-08-10 2 views
0

info: Мы пытаемся создать свойство, дополнительные свойства которого могут быть добавлены/удалены в зависимости от значения другого вспомогательного свойства.Как динамически отображать/скрывать вспомогательные свойства лично определенного свойства с использованием свойства qt

Примером этого может быть растительный объект. У этого объекта есть одно свойство, которое будет выпадающим, состоящим из типов растений, скажем (маргаритка, нарцисс и ловушка для мух венеза). Если выбрана Венера, я бы хотел, чтобы свойство отображалось ниже под названием avgFlyIntake, но если выбрано daffodil, это свойство должно исчезнуть.

example: 
Plant 
    type  venus 
    avgFlyI 2.0 
    avgHight 3.0 

Or 

Plant 
    type  daffodil 
    avgHight 8.0 
    //Fly Property gone or grayed out. 

Edit: По сути завод является собственностью другой модели, которую я предполагаю, можно было бы назвать livingThing. Свойство отображается иерархически в таблице из 2 столбцов. Я бы хотел, чтобы свойства растения были динамически скрыты, если это возможно.

c++ src: 
PlantProperty::PlantProperty(const QString& name /*= QString()*/, QObject* propertyObject /*= 0*/, QObject* parent /*= 0*/) 
    : Property(name, propertyObject, parent) 
{ 

    m_type = new Property("id", this, this); 
    m_avgFlyIntake = new Property("avgFlyIntake", this, this); 
    m_avgHeight = new Property("avgHeight", this, this); 

    //setEditorHints("..."); 
} 
enum PlantProperty::getType() const{ 
    return value().value<Plant>().getType(); 
} 

void PlantProperty::setType(enum enabled){ 
    //if enum changed show and hide relevant properties associated with selection 
    Property::setValue(QVariant::fromValue(Plant(...))); 
} 


c++ h: 
class PlantProperty : public Property{ 
    Q_OBJECT 
/**/ 
    Q_PROPERTY(int type READ getType WRITE setType DESIGNABLE true USER true) 
    Q_PROPERTY(float avgFlyIntake READ getavgFlyIntake WRITE setAvgFlyIntake DESIGNABLE true USER ture) 
    Q_PROPERTY(float avgHeight READ getavgHeight WRITE setavgHeihgt DESIGNABLE true USER true) 

public: 
    PlantProperty (const QString&name = QString(), QObject* propertyObject = 0, QObject* parent = 0); 

    QVariant data(const QModelIndex &index, int role) const; 
    int rowCount(const QModelIndex &parent = QModelIndex()) const; 

    QVariant value(int role = Qt::UserRole) const; 
    virtual void setValue(const QVariant& value); 

    void setEditorHints(const QString& hints); 

    int getType() const; 
    void setType(int id); 

private: 
    QString parseHints(const QString& hints, const QChar component); 

    Property* type; 
    Property* avgFlyIntake; 
    Property* avgHeight; 

}; 

Q_DECLARE_METATYPE(Plant) 
#endif //PLANTPROPERTY_H 


q property model: 
// ************************************************************************************************* 
// 
// QPropertyEditor v 0.3 
// 
// -------------------------------------- 
// Copyright (C) 2007 Volker Wiendl 
// Acknowledgements to Roman alias banal from qt-apps.org for the Enum enhancement 
// 
// 
// The QPropertyEditor Library is free software; you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation version 3 of the License 
// 
// The Horde3D Scene Editor is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
// GNU General Public License for more details. 
// 
// You should have received a copy of the GNU General Public License 
// along with this program. If not, see <http://www.gnu.org/licenses/>. 
// 
// ************************************************************************************************* 

#include "QPropertyModel.h" 

#include "Property.h" 
#include "EnumProperty.h" 

#include <QtGui/QApplication> 
#include <QtCore/QMetaProperty> 
#include <QtGui/QItemEditorFactory> 

struct PropertyPair 
{ 
    PropertyPair(const QMetaObject* obj, QMetaProperty property) : Property(property), Object(obj) {} 

    QMetaProperty  Property; 
    const QMetaObject* Object; 

    bool operator==(const PropertyPair& other) const {return QString(other.Property.name()) == QString(Property.name());} 
}; 


QPropertyModel::QPropertyModel(QObject* parent /*= 0*/) : QAbstractItemModel(parent) 
{ 
    m_rootItem = new Property("Root",0, this); 
} 


QPropertyModel::~QPropertyModel() 
{ 
} 

QModelIndex QPropertyModel::index (int row, int column, const QModelIndex & parent /*= QModelIndex()*/) const 
{ 
    Property *parentItem = m_rootItem; 
    if (parent.isValid()) 
     parentItem = static_cast<Property*>(parent.internalPointer()); 
    if (row >= parentItem->children().size() || row < 0) 
     return QModelIndex();  
    return createIndex(row, column, parentItem->children().at(row));  

} 

QModelIndex QPropertyModel::parent (const QModelIndex & index) const 
{ 
    if (!index.isValid()) 
     return QModelIndex(); 

    Property *childItem = static_cast<Property*>(index.internalPointer()); 
    Property *parentItem = qobject_cast<Property*>(childItem->parent()); 

    if (!parentItem || parentItem == m_rootItem) 
     return QModelIndex(); 

    return createIndex(parentItem->row(), 0, parentItem); 
} 

int QPropertyModel::rowCount (const QModelIndex & parent /*= QModelIndex()*/) const 
{ 
    Property *parentItem = m_rootItem; 
    if (parent.isValid()) 
     parentItem = static_cast<Property*>(parent.internalPointer()); 
    return parentItem->children().size(); 
} 

int QPropertyModel::columnCount (const QModelIndex & /*parent = QModelIndex()*/) const 
{ 
    return 2; 
} 

QVariant QPropertyModel::data (const QModelIndex & index, int role /*= Qt::DisplayRole*/) const 
{ 
    if (!index.isValid()) 
     return QVariant(); 

    Property *item = static_cast<Property*>(index.internalPointer()); 
    switch(role) 
    { 
    case Qt::ToolTipRole:  
    case Qt::DecorationRole: 
    case Qt::DisplayRole: 
    case Qt::EditRole: 
     if (index.column() == 0) 
      return item->objectName().replace('_', ' '); 
     if (index.column() == 1) 
      return item->value(role); 
    case Qt::BackgroundRole: 
     if (item->isRoot()) return QApplication::palette("QTreeView").brush(QPalette::Normal, QPalette::Button).color(); 
     break; 
    }; 
    return QVariant(); 
} 

// edit methods 
bool QPropertyModel::setData (const QModelIndex & index, const QVariant & value, int role /*= Qt::EditRole*/) 
{ 
    if (index.isValid() && role == Qt::EditRole) 
    { 
     Property *item = static_cast<Property*>(index.internalPointer()); 
     item->setValue(value); 
     emit dataChanged(index, index); 
     return true; 
    } 
    return false; 
} 

Qt::ItemFlags QPropertyModel::flags (const QModelIndex & index) const 
{ 
    if (!index.isValid()) 
     return Qt::ItemIsEnabled; 
    Property *item = static_cast<Property*>(index.internalPointer()); 
    // only allow change of value attribute 
    if (item->isRoot()) 
     return Qt::ItemIsEnabled; 
    else if (item->isReadOnly()) 
     return Qt::ItemIsDragEnabled | Qt::ItemIsSelectable;  
    else 
     return Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; 
} 


QVariant QPropertyModel::headerData (int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/) const 
{ 
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) 
    { 
     switch (section) 
     { 
      case 0: 
       return tr("Name"); 
      case 1: 
       return tr("Value"); 
     } 
    } 
    return QVariant(); 
} 

QModelIndex QPropertyModel::buddy (const QModelIndex & index) const 
{ 
    if (index.isValid() && index.column() == 0) 
     return createIndex(index.row(), 1, index.internalPointer()); 
    return index; 
} 

void QPropertyModel::addItem(QObject *propertyObject) 
{ 
    // first create property <-> class hierarchy 
    QList<PropertyPair> propertyMap; 
    QList<const QMetaObject*> classList;  
    const QMetaObject* metaObject = propertyObject->metaObject(); 
    do 
    { 
     int count = metaObject->propertyCount(); 
     for (int i=0; i<count; ++i) 
     { 
      QMetaProperty property = metaObject->property(i); 
      if(property.isUser()) // Hide Qt specific properties 
      {    
       PropertyPair pair(metaObject, property); 
       int index = propertyMap.indexOf(pair); 
       if (index != -1) 
        propertyMap[index] = pair; 
       else 
        propertyMap.push_back(pair);     
      } 
     }  
     classList.push_front(metaObject); 
    } 
    while ((metaObject = metaObject->superClass())!=0); 

    QList<const QMetaObject*> finalClassList; 
    // remove empty classes from hierarchy list 
    foreach(const QMetaObject* obj, classList) 
    { 
     bool keep = false; 
     foreach(PropertyPair pair, propertyMap) 
     { 
      if (pair.Object == obj) 
      { 
       keep = true; 
       break; 
      } 
     } 
     if (keep) 
      finalClassList.push_back(obj); 
    } 

    // finally insert properties for classes containing them 
    int i=rowCount(); 
    Property* propertyItem = 0; 
    beginInsertRows(QModelIndex(), i, i + finalClassList.count()); 
    foreach(const QMetaObject* metaObject, finalClassList) 
    { 
     // Set default name of the hierarchy property to the class name 
     QString name = metaObject->className(); 
     // Check if there is a special name for the class 
     int index = metaObject->indexOfClassInfo(qPrintable(name)); 
     if (index != -1) 
      name = metaObject->classInfo(index).value(); 
     // Create Property Item for class node 
     propertyItem = new Property(name, 0, m_rootItem);  
     foreach(PropertyPair pair, propertyMap) 
     { 
      // Check if the property is associated with the current class from the finalClassList 
      if (pair.Object == metaObject) 
      { 
       QMetaProperty property(pair.Property); 
       Property* p = 0; 
       if (property.type() == QVariant::UserType && !m_userCallbacks.isEmpty()) 
       { 
        QList<QPropertyEditorWidget::UserTypeCB>::iterator iter = m_userCallbacks.begin(); 
        while(p == 0 && iter != m_userCallbacks.end()) 
        { 
         p = (*iter)(property.name(), propertyObject, propertyItem);   
         ++iter; 
        } 
       } 
       if(p == 0){ 
        if(property.isEnumType()){ 
         p = new EnumProperty(property.name(), propertyObject, propertyItem); 
        } else { 
         p = new Property(property.name(), propertyObject, propertyItem); 
        } 
       } 
       int index = metaObject->indexOfClassInfo(property.name()); 
       if (index != -1)   
        p->setEditorHints(metaObject->classInfo(index).value());    
      } 
     } 
    } 
    endInsertRows(); 
    if(propertyItem) addDynamicProperties(propertyItem, propertyObject); 
} 

void QPropertyModel::updateItem (QObject* propertyObject, const QModelIndex& parent /*= QModelIndex() */) 
{ 
    Property *parentItem = m_rootItem; 
    if (parent.isValid()) 
     parentItem = static_cast<Property*>(parent.internalPointer()); 
    if (parentItem->propertyObject() != propertyObject)  
     parentItem = parentItem->findPropertyObject(propertyObject); 
    if (parentItem) // Indicate view that the data for the indices have changed 
    { 
     QModelIndex itemIndex = createIndex(parentItem->row(), 0, static_cast<Property*>(parentItem)); 
     dataChanged(itemIndex, createIndex(parentItem->row(), 1, static_cast<Property*>(parentItem)));  
     QList<QByteArray> dynamicProperties = propertyObject->dynamicPropertyNames(); 
     QList<QObject*> childs = parentItem->parent()->children(); 
     int removed = 0; 
     for(int i = 0; i < childs.count(); ++i) 
     { 
      QObject* obj = childs[i]; 
      if(!obj->property("__Dynamic").toBool() || dynamicProperties.contains(obj->objectName().toLocal8Bit())) 
       continue; 
      beginRemoveRows(itemIndex.parent(), i - removed, i - removed); 
      ++removed; 
      delete obj; 
      endRemoveRows(); 
     } 
     addDynamicProperties(static_cast<Property*>(parentItem->parent()), propertyObject); 
    } 
} 

void QPropertyModel::addDynamicProperties(Property* parent, QObject* propertyObject) 
{ 
    // Get dynamic property names 
    QList<QByteArray> dynamicProperties = propertyObject->dynamicPropertyNames(); 

    QList<QObject*> childs = parent->children(); 

    // Remove already existing properties from list 
    for(int i = 0; i < childs.count(); ++i) 
    {  
     if(!childs[i]->property("__Dynamic").toBool()) continue; 

     int index = dynamicProperties.indexOf(childs[i]->objectName().toLocal8Bit()); 
     if(index != -1) 
     { 
      dynamicProperties.removeAt(index);   
      continue; 
     } 
    } 

    // Remove invalid properites and those we don't want to add 
    for(int i = 0; i < dynamicProperties.size(); ++i) 
    { 
     QString dynProp = dynamicProperties[i]; 
     // Skip properties starting with _ (because there may be dynamic properties from Qt with _q_ and we may 
     // have user defined hidden properties starting with _ too 
     if(dynProp.startsWith("_") || !propertyObject->property(qPrintable(dynProp)).isValid()) 
     { 
      dynamicProperties.removeAt(i); 
      --i; 
     }  
    } 

    if(dynamicProperties.empty()) return; 

    QModelIndex parentIndex = createIndex(parent->row(), 0, static_cast<Property*>(parent)); 
    int rows = rowCount(parentIndex); 
    beginInsertRows(parentIndex, rows, rows + dynamicProperties.count() - 1); 
    // Add properties left in the list 
    foreach(QByteArray dynProp, dynamicProperties) 
    { 
     QVariant v = propertyObject->property(dynProp); 
     Property* p = 0; 
     if(v.type() == QVariant::UserType && !m_userCallbacks.isEmpty()) 
     { 
      QList<QPropertyEditorWidget::UserTypeCB>::iterator iter = m_userCallbacks.begin(); 
      while(p == 0 && iter != m_userCallbacks.end()) 
      { 
       p = (*iter)(dynProp, propertyObject, parent);   
       ++iter; 
      } 
     } 
     if(p == 0) p = new Property(dynProp, propertyObject, parent); 
     p->setProperty("__Dynamic", true); 
    } 
    endInsertRows(); 
} 

void QPropertyModel::clear() 
{ 
    beginRemoveRows(QModelIndex(), 0, rowCount()); 
    delete m_rootItem; 
    m_rootItem = new Property("Root",0, this); 
    endRemoveRows(); 
} 

void QPropertyModel::registerCustomPropertyCB(QPropertyEditorWidget::UserTypeCB callback) 
{ 
    if (!m_userCallbacks.contains(callback)) 
     m_userCallbacks.push_back(callback); 
} 

void QPropertyModel::unregisterCustomPropertyCB(QPropertyEditorWidget::UserTypeCB callback) 
{ 
    int index = m_userCallbacks.indexOf(callback); 
    if(index != -1) 
     m_userCallbacks.removeAt(index); 
} 
+0

Что вы имеете в виду, так это то, что вы хотели бы иметь объект, * тип * которого является свойством, а затем он будет преобразовывать себя на основе этого свойства. Конечно, объект не нуждается в морфинге. Он может просто удалить себя и заменить себя чем-то другим :) –

+0

Я также не понимаю, для чего у вас есть тип 'Property', когда вы по существу дублируете то, что делает' QStandardItem', за исключением того, что вы добавляете прямые C++-интерфейсы, которые не выглядят для использования. И, конечно, ваш интерфейс 'Property' претендует на роль модели, но это не так. –

+0

@KubaOber добавленная модель свойств. –

ответ

0

QObject имеет динамическую систему свойств, так что вам не нужно вручную объявлять какие-либо свойства вообще. Было бы легко сопоставить такие объекты с представлением элемента. Но похоже, что использование QObject является излишним.

Похоже, вы были бы полностью покрыты с помощью QStandardItemModel и его элементов, расположенных на дереве. Элементом может быть либо растение, либо имущество завода.

+0

Большая часть проекта написана с этим шаблоном, вы можете подумать о решении, сохраняющем этот образец qProperty? Если у вас нет ссылок на примеры такого поведения, которые создаются по-другому. –

+0

@richgreen Дело в том, что вы не демонстрируете никакой необходимости в использовании 'QObject' и для ручного объявления свойств как объектов, имеющих имена, известные компилятору C++. Все имена пригодны для просмотра и т. Д. Вам нужно будет сделать пример использования макросов 'Q_PROPERTY' и свойств, о которых компилятор знает. Я еще этого не вижу. –

Смежные вопросы