0

信息:我们正在尝试创建一个属性,其子属性可以根据另一个子属性的值添加/删除。

这方面的一个例子可能是植物对象。这个对象有一个属性,它是一个由植物类型组成的下拉列表,比如说(雏菊、水仙花和捕蝇草)。如果选择了 venus,我希望在下面显示一个名为 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.

编辑:本质上,植物是另一个模型的属性,我猜它可以称为 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);
}
4

1 回答 1

0

QObject具有动态属性系统,因此您根本不需要手动声明任何属性。将这些对象映射到项目视图很容易。但似乎使用 aQObject是矫枉过正。

看起来你会完全被使用 aQStandardItemModel和它的项目所覆盖,排列在一棵树中。物品可以是植物,也可以是植物的财产。

于 2015-08-10T21:28:56.637 回答