2016-09-02 8 views
-3

私はしばらくQtを使っていましたが、私は彼らのプロパティシステムがどのように機能するのか魅力的です。Qtのようなプロパティシステムを実装する方法は?

QPushButton *button = new QPushButton; // inherits a QObject 
button->setProperty("down", true); 
button->setProperty("angle", 35.0); 

QVariant value = button->property("angle"); 

私はそれをどのように実装できるか不思議に思っていました。とても簡単に使うことができるのは何ですか?

+7

ソースを読み込みます。 –

+1

任意のデータ型を保持できる 'Variant'型を実装する必要があります。次に、プロパティ名としてkeyの文字列とその値の対応するバリアントを持つマップと同じくらい簡単です。これは実際には非常に非効率的であり、オーバーヘッドがたくさんあります。ダイナマリズムが本当に必要な場合にのみお勧めします。 Qtを使うだけで、ホイールを再構成する必要はありません。 – dtech

+0

ようこそスタックオーバーフロー。現在の形でのあなたの質問は広すぎるので、SOの範囲内で答えることはできません。 [ヘルプセンター](http://stackoverflow.com/help)にアクセスし、[よく質問する方法]セクション(http://stackoverflow.com/help/how-to-ask)を読んでください。 –

答えて

1

適切なバリアントクラスを取得したら、簡単です。必要なのは、名前からバリアントへのマップです:

#include <map> 
#include <string> 
#include <cassert> 
#include <boost/variant.hpp> 

class WithProperties { 
public: 
    using variant = boost::variant<std::string, int, double, bool>; 
    template <typename T> T property(const char * name) const { 
     auto it = m_properties.find(name); 
     if (it != m_properties.end()) return boost::get<T>(it->second); 
     return T{}; 
    } 
    void setProperty(const char * name, const variant & value) { 
     m_properties[name] = value; 
    } 
    std::vector<std::string> propertyNames() const { 
     std::vector<std::string> keys; 
     keys.reserve(m_properties.size()); 
     for (auto prop : m_properties) 
      keys.push_back(prop.first); 
     return keys; 
    } 
private: 
    std::map<std::string, variant> m_properties; 
}; 

int main() { 
    WithProperties prop; 
    prop.setProperty("down", true); 
    prop.setProperty("angle", 35.0); 
    prop.setProperty("name", std::string{"foo"}); 
    assert(prop.property<bool>("down") == true); 
    assert(prop.property<double>("angle") == 35.0); 
    assert(prop.property<std::string>("name") == "foo"); 
} 

あなたはQVariantはすべてに対処する方法を知って役立つoperator==コンストラクタを実装しているため、それはさらに簡単です、Qtの種類を使用して行うのか迷っている場合基本的なCの値の型。

#include <QtCore> 

class WithProperties { 
public: 
    QVariant property(const char * name) const { 
     auto it = m_properties.find(name); 
     if (it != m_properties.end()) return *it; 
     return QVariant{}; 
    } 
    void setProperty(const char * name, const QVariant & value) { 
     m_properties[name] = value; 
    } 
    QList<QByteArray> propertyNames() const { 
     return m_properties.keys(); 
    } 
private: 
    QMap<QByteArray, QVariant> m_properties; 
}; 

int main() { 
    WithProperties prop; 
    prop.setProperty("down", true); 
    prop.setProperty("angle", 35.0); 
    prop.setProperty("name", "foo"); 
    Q_ASSERT(prop.property("down") == true); 
    Q_ASSERT(prop.property("angle") == 35.0); 
    Q_ASSERT(prop.property("name") == "foo"); 
} 

Qtのプロパティシステムは、1つのより多くの事を行います。それは、静的に、名前付きプロパティはQ_PROPERTYを使用して宣言し使用しています。これらはメタデータを介して利用でき、上記の動的プロパティと統合されています。以下のように実装することができます(これはQtコードからコピーされません)。

#include <QtCore> 
#include <cstring> 

QMetaProperty findMetaProperty(const QMetaObject * obj, const char * name) { 
    auto count = obj->propertyCount(); 
    for (int i = 0; i < count; ++i) { 
     auto prop = obj->property(i); 
     if (strcmp(prop.name(), name) == 0) 
      return prop; 
    } 
    return QMetaProperty{}; 
} 

class WithProperties { 
    Q_GADGET 
    Q_PROPERTY(QString name READ name WRITE setName) 
    QString m_name; 
public: 
    QString name() const { return m_name; } 
    void setName(const QString & name) { m_name = name; } 
    QVariant property(const char * name) const { 
     auto metaProperty = findMetaProperty(&staticMetaObject, name); 
     if (metaProperty.isValid()) 
      return metaProperty.readOnGadget(this); 
     auto it = m_properties.find(name); 
     if (it != m_properties.end()) return *it; 
     return QVariant{}; 
    } 
    void setProperty(const char * name, const QVariant & value) { 
     auto metaProperty = findMetaProperty(&staticMetaObject, name); 
     if (metaProperty.isValid()) 
      return (void)metaProperty.writeOnGadget(this, value); 
     m_properties[name] = value; 
    } 
    QList<QByteArray> dynamicPropertyNames() const { 
     return m_properties.keys(); 
    } 
private: 
    QMap<QByteArray, QVariant> m_properties; 
}; 

int main() { 
    WithProperties prop; 
    prop.setProperty("down", true); 
    prop.setProperty("angle", 35.0); 
    prop.setProperty("name", "foo"); 
    Q_ASSERT(prop.property("down") == true); 
    Q_ASSERT(prop.property("angle") == 35.0); 
    Q_ASSERT(prop.property("name") == "foo"); 
    Q_ASSERT(prop.dynamicPropertyNames().size() == 2); 
} 
#include "main.moc" 
関連する問題