Информация:
Мы пытаемся создать свойство, подчиненные свойства которого могут быть добавлены / удалены в зависимости от значения другого подчиненного свойства.
Примером этого может быть объект растения. Этот объект обладает одним свойством, которое будет раскрывающимся списком типов растений, скажем (маргаритка, нарцисс и ловушка для мухи Венеры). Если выбрана Венера, я бы хотел, чтобы ниже отображалось свойство 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. Свойство отображается иерархически в виде таблицы с двумя столбцами. Я бы хотел, чтобы свойства растений были динамически скрыты, если это возможно.
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);
}
QObject
имеет динамическую систему свойств, поэтому вам не нужно вручную объявлять какие-либо свойства. Было бы легко сопоставить такие объекты с видом элемента. Но похоже, что использование QObject
это перебор.
Похоже, что вы будете полностью покрыты с помощью QStandardItemModel
и его предметы, расположенные в дереве. Предметом может быть либо растение, либо собственность завода.