gpt4 book ai didi

c++ - 属性编辑器的设计模式?

转载 作者:行者123 更新时间:2023-12-02 15:23:51 30 4
gpt4 key购买 nike

警告:这是 super 深度。我了解您甚至不想读这篇文章,这主要是让我理清自己的思维过程。

好的,这就是我想要做的。我有这些对象:

当您单击一个(或选择多个)时,它应在右侧显示其属性(如图所示)。当您编辑上述属性时,应立即更新内部变量。

我正在尝试确定执行此操作的最佳方法。我认为所选对象应存储为指针列表。就是这样,或者在每个对象上都有一个isSelected bool(boolean) 值,然后遍历所有对象,而忽略未选择的对象,这效率很低。因此,我们单击一个,或选择多个,然后填充selectedObjects列表。然后,我们需要显示属性。为了暂时保持简单,我们假设所有对象都是相同的类型(共享相同的属性集)。由于没有任何特定于实例的属性,因此我认为我们应该将这些属性存储为Object类中的静态变量。属性基本上只有一个名称(例如“允许睡眠”)。每种类型的属性(int,bool,double)都有一个PropertyManager。 PropertyManager存储其各自类型的属性的所有值(全部来自Qt API)。不幸的是,因为需要PropertyManagers来创建属性,所以我无法真正将两者分离。我想这意味着我必须将PropertyManager与属性(作为静态变量)一起放置。这意味着我们拥有一组属性,以及一组属性管理器来管理所有对象中的所有变量。每个属性管理器只能有一个回调。这意味着该回调必须针对所有对象(嵌套循环)更新其相应类型的所有属性。这将产生如下内容(以伪代码):

function valueChanged(property, value) {
if(property == xPosProp) {
foreach(selectedObj as obj) {
obj->setXPos(value);
}
} else if(property == ...

这已经让我有些烦恼,因为我们在不需要的地方使用了if语句。解决此问题的方法是为每个属性创建一个不同的属性管理器,以便我们可以拥有唯一的回调。这也意味着我们每个属性都需要两个对象,但是对于更干净的代码来说,这可能是一个值得付出的代价(我真的不知道现在的性能成本是多少,但是正如我所知道的,您还会说-优化何时这成为一个问题)。因此,我们最终得到了大量的回调:
function xPosChanged(property, value) {
foreach(selectedObj as obj) {
obj->setXPos(value);
}
}

这消除了整个if / else垃圾,但增加了十几个事件监听器。假设我使用这种方法。因此,现在我们有了一堆静态属性,以及它们对应的静态PropertyManager。大概我也将所选对象的列表存储为Object::selectedObjects,因为它们在逻辑上属于对象类的所有事件回调中使用。因此,我们也有一堆静态事件回调。很好,花花公子。

因此,现在当您编辑属性时,我们可以通过事件回调为所有选定对象更新内部变量。但是,当通过其他方式更新内部变量时会发生什么,我们如何更新属性?这恰好是一个物理模拟器,因此所有对象的许多变量将不断更新。我无法为此添加回调,因为物理是由另一个第三方库处理的。我想这意味着我只需要假设在每个时间步骤之后所有变量都已更改。因此,在每个时间步骤之后,我都必须更新所有选定对象的所有属性。好,我可以做到。

最后一个问题(我希望),就是当多个对象被选中的存在不一致性值,我们应该显示?我猜我的选择是将其保留为空白/ 0或显示随机对象的属性。我认为没有一个选项比另一个更好,但希望Qt提供一种突出显示此类属性的方法,以便至少可以通知用户。那么,如何确定要“突出显示”哪些属性?我想我会遍历所有选定的对象及其所有属性,进行比较,一旦出现不匹配,我便可以突出显示它。因此,澄清一下,在选择了一些对象之后:
  • 将所有对象添加到selectedObjects列表
  • 填充属性编辑器
  • 查找哪些属性具有相同的值,并适当地更新编辑器

  • 我想我也应该将属性存储在列表中,这样我就可以将整个列表推送到属性编辑器中,而不是单独添加每个属性。我认为应该在以后提供更多的灵活性。

    我认为涵盖了这一点……我仍然不确定拥有这么多静态变量和一个半单类的感觉(我猜想,当创建第一个对象时,静态变量将被初始化一次)。但是我看不到更好的解决方案。

    如果您确实读过这篇文章,请发表您的想法。我想这不是一个真正的问题,所以让我对讨厌的人改写一下: 我可以对建议的设计模式进行哪些调整,以产生更简洁,更易懂或更有效的代码? (或类似方式)。

    看来我需要澄清。 “属性”是指“允许睡眠”或“速度”-所有对象都具有这些属性-但是它们的值对于每个实例都是唯一的。 属性包含需要显示的字符串,值的有效范围以及所有小部件信息。 PropertyManagers 是实际持有值的对象。它们控制回调以及显示的值。该值还有另一个副本,该副本实际上已由其他第三方物理库“内部”使用。

    现在尝试真正实现这种疯狂。我有一个EditorView(图像中的黑色区域),它捕获了mouseClick事件。然后,mouseClick事件告诉物理模拟器查询光标处的所有物体。每个物理主体都存储有一个引用(一个空指针!),该引用返回我的对象​​类。指针被投射回对象,并被推到选定对象的列表上。然后,EditorView发出信号。然后,EditorWindow捕获此信号,并将其与所选对象一起传递到PropertiesWindow。现在,PropertiesWindow需要查询对象以获取要显示的属性列表……而这是我到目前为止所获得的。烦死了!

    解决方案
    /* 
    * File: PropertyBrowser.cpp
    * Author: mark
    *
    * Created on August 23, 2009, 10:29 PM
    */

    #include <QtCore/QMetaProperty>
    #include "PropertyBrowser.h"

    PropertyBrowser::PropertyBrowser(QWidget* parent)
    : QtTreePropertyBrowser(parent), m_variantManager(new QtVariantPropertyManager(this)) {
    setHeaderVisible(false);
    setPropertiesWithoutValueMarked(true);
    setIndentation(10);
    setResizeMode(ResizeToContents);
    setFactoryForManager(m_variantManager, new QtVariantEditorFactory);
    setAlternatingRowColors(false);

    }

    void PropertyBrowser::valueChanged(QtProperty *property, const QVariant &value) {
    if(m_propertyMap.find(property) != m_propertyMap.end()) {
    foreach(QObject *obj, m_selectedObjects) {
    obj->setProperty(m_propertyMap[property], value);
    }
    }
    }

    QString PropertyBrowser::humanize(QString str) const {
    return str.at(0).toUpper() + str.mid(1).replace(QRegExp("([a-z])([A-Z])"), "\\1 \\2");
    }

    void PropertyBrowser::setSelectedObjects(QList<QObject*> objs) {
    foreach(QObject *obj, m_selectedObjects) {
    obj->disconnect(this);
    }
    clear();
    m_variantManager->clear();
    m_selectedObjects = objs;
    m_propertyMap.clear();
    if(objs.isEmpty()) {
    return;
    }
    for(int i = 0; i < objs.first()->metaObject()->propertyCount(); ++i) {
    QMetaProperty metaProperty(objs.first()->metaObject()->property(i));
    QtProperty * const property
    = m_variantManager->addProperty(metaProperty.type(), humanize(metaProperty.name()));
    property->setEnabled(metaProperty.isWritable());
    m_propertyMap[property] = metaProperty.name();
    addProperty(property);
    }
    foreach(QObject *obj, m_selectedObjects) {
    connect(obj, SIGNAL(propertyChanged()), SLOT(objectUpdated()));
    }
    objectUpdated();
    }

    void PropertyBrowser::objectUpdated() {
    if(m_selectedObjects.isEmpty()) {
    return;
    }
    disconnect(m_variantManager, SIGNAL(valueChanged(QtProperty*, QVariant)),
    this, SLOT(valueChanged(QtProperty*, QVariant)));
    QMapIterator<QtProperty*, QByteArray> i(m_propertyMap);
    bool diff;
    while(i.hasNext()) {
    i.next();
    diff = false;
    for(int j = 1; j < m_selectedObjects.size(); ++j) {
    if(m_selectedObjects.at(j)->property(i.value()) != m_selectedObjects.at(j - 1)->property(i.value())) {
    diff = true;
    break;
    }
    }
    if(diff) setBackgroundColor(topLevelItem(i.key()), QColor(0xFF,0xFE,0xA9));
    else setBackgroundColor(topLevelItem(i.key()), Qt::white);
    m_variantManager->setValue(i.key(), m_selectedObjects.first()->property(i.value()));
    }
    connect(m_variantManager, SIGNAL(valueChanged(QtProperty*, QVariant)),
    this, SLOT(valueChanged(QtProperty*, QVariant)));
    }

    非常感谢 TimW

    最佳答案

    您看过Qt的(dynamic) property system吗?

    bool QObject::setProperty ( const char * name, const QVariant & value );
    QVariant QObject::property ( const char * name ) const
    QList<QByteArray> QObject::dynamicPropertyNames () const;
    //Changing the value of a dynamic property causes a
    //QDynamicPropertyChangeEvent to be sent to the object.


    function valueChanged(property, value) {
    foreach(selectedObj as obj) {
    obj->setProperty(property, value);
    }
    }



    这是一个不完整的示例,可让您对属性(property)制度有个大概的了解。
    我猜 SelectableItem * selectedItem在您的情况下必须替换为项目列表。
    class SelectableItem : public QObject
    {
    Q_OBJECT
    Q_PROPERTY(QString name READ name WRITE setName );
    Q_PROPERTY(int velocity READ velocity WRITE setVelocity);

    public:
    QString name() const { return m_name; }
    int velocity() const {return m_velocity; }

    public slots:
    void setName(const QString& name)
    {
    if(name!=m_name)
    {
    m_name = name;
    emit update();
    }
    }
    void setVelocity(int value)
    {
    if(value!=m_velocity)
    {
    m_velocity = value;
    emit update();
    }
    }

    signals:
    void update();

    private:
    QString m_name;
    int m_velocity;
    };

    class MyPropertyWatcher : public QObject
    {
    Q_OBJECT
    public:
    MyPropertyWatcher(QObject *parent)
    : QObject(parent),
    m_variantManager(new QtVariantPropertyManager(this)),
    m_propertyMap(),
    m_selectedItem(),
    !m_updatingValues(false)
    {
    connect(m_variantManager, SIGNAL(valueChanged(QtProperty*, QVariant)), SLOT(valueChanged(QtProperty*,QVariant)));
    m_propertyMap[m_variantManager->addProperty(QVariant::String, tr("Name"))] = "name";
    m_propertyMap[m_variantManager->addProperty(QVariant::Int, tr("Velocity"))] = "velocity";
    // Add mim, max ... to the property
    // you could also add all the existing properties of a SelectableItem
    // SelectableItem item;
    // for(int i=0 ; i!=item.metaObject()->propertyCount(); ++i)
    // {
    // QMetaProperty metaProperty(item.metaObject()->property(i));
    // QtProperty *const property
    // = m_variantManager->addProperty(metaProperty.type(), metaProperty.name());
    // m_propertyMap[property] = metaProperty.name()
    // }
    }

    void setSelectedItem(SelectableItem * selectedItem)
    {
    if(m_selectedItem)
    {
    m_selectedItem->disconnect( this );
    }

    if(selectedItem)
    {
    connect(selectedItem, SIGNAL(update()), SLOT(itemUpdated()));
    itemUpdated();
    }
    m_selectedItem = selectedItem;
    }


    private slots:
    void valueChanged(QtProperty *property, const QVariant &value)
    {
    if(m_updatingValues)
    {
    return;
    }

    if(m_selectedItem && m_map)
    {
    QMap<QtProperty*, QByteArray>::const_iterator i = m_propertyMap.find(property);
    if(i!=m_propertyMap.end())
    m_selectedItem->setProperty(m_propertyMap[property], value);
    }
    }

    void itemUpdated()
    {
    m_updatingValues = true;
    QMapIterator<QtProperty*, QByteArray> i(m_propertyMap);
    while(i.hasNext())
    {
    m_variantManager->next();
    m_variantManager->setValue(
    i.key(),
    m_selectedItem->property(i.value()));
    }
    m_updatingValues = false;
    }

    private:
    QtVariantPropertyManager *const m_variantManager;
    QMap<QtProperty*, QByteArray> m_propertyMap;
    QPointer<SelectableItem> m_selectedItem;
    bool m_updatingValues;
    };

    关于c++ - 属性编辑器的设计模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1303893/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com