代码之家  ›  专栏  ›  技术社区  ›  Tyler McHenry

如何支持对包含自定义类型的QVariant对象进行比较?

  •  22
  • Tyler McHenry  · 技术社区  · 15 年前

    QVariant::operator== 如果变量包含自定义类型,则无法正常工作:

    将此变量与qv和 否则返回false。

    不调用相等运算符。 相比。

    在标题中:

    enum MyEnum { Foo, Bar };
    
    Q_DECLARE_METATYPE(MyEnum);
    

    函数中的某处:

    QVariant var1 = QVariant::fromValue<MyEnum>(Foo);
    QVariant var2 = QVariant::fromValue<MyEnum>(Foo);
    assert(var1 == var2); // Fails!
    

    我理解 为什么? 它不起作用——每个变量都存储枚举值的一个单独副本,因此它们有不同的地址。我想知道如何改变将这些值存储在变量中的方法,以便这不是问题,或者它们都引用相同的基础变量。

    QComboBox 我希望能够使用 QComboBox::findData

    3 回复  |  直到 15 年前
        1
  •  15
  •   Adam W    15 年前

    显而易见的答案是把数据从 var1.value<MyEnum>() == var2.value<MyEnum>() 但这需要你在比较时知道它们的类型。在你看来这是可能的。

    如果只是使用枚举,还可以将其转换为int以存储在QVariant中。

    QComboBox ,它 uses the model of the combo box to find the data . 具体来说,它使用 match() 系统的功能 QAbstractItemModel 检查是否相等。幸运的是,这个函数是虚拟的,所以您可以在子类中重写它。

        2
  •  4
  •   j0k gauthamp    13 年前

    typedef bool (*f_compare)(const Private *, const Private *);
    

    并将其设置为qvariant handler;

    struct Handler {
        f_construct construct;
        f_clear clear;
        f_null isNull;
      #ifndef QT_NO_DATASTREAM
        f_load load;
        f_save save;
     #endif
        f_compare compare;
        f_convert convert;
        f_canConvert canConvert;
        f_debugStream debugStream;
    };
    

    class HackVariant : private QVariant
    {
    public:
         static void hackIt() {
             origh = handler;
             Handler* h = new Handler;
             *h = *origh;
             h->convert = convert;
             h->debugStream = hackStreamDebug;
             handler = h;
         }
    
    private:
         static bool convert(const QVariant::Private *d, QVariant::Type t, void *result, bool *ok)
         {
             //qDebug() << Q_FUNC_INFO << "type:" << d->type;
             if (d->type >= QVariant::UserType)
             {
                 QString& str = *((QString*)result);
                 Identifier* ident = (Identifier*)(constData(d));
                 str = ident->toString();
             }
             else
                 return origh->convert(d, t, result, ok);
             return true;
         }
    
         static void hackStreamDebug(QDebug dbg, const QVariant &v) {
             if (v.canConvert<Identifier>())
                 dbg << v.value<Identifier>();
             else
                 origh->debugStream(dbg, v);
         }
    
         static const Handler* origh;
    
         static const void *constData(const QVariant::Private *d)
         {
             return d->is_shared ? d->data.shared->ptr : reinterpret_cast<const void *>(&d->data.ptr);
         }
    
    };
    

    必须创建函数并将其设置为handler。别忘了打电话 HackVariant::hackIt() 在main.cpp中使用(var1==var2)。

        3
  •  4
  •   emkey08    10 年前

    Qt 5溶液

    Qt从版本5.2开始就支持这种开箱即用的方式。看到了吗 QVariant::operator== QMetaType::registerComparators .

    Qt 4的解决方案

    CustomVariantComparator 我为我的一个项目写的课程。

    你可以这样使用它。假设我们有课 Foo operator== 应该在一个小时内使用 QVariant :

    class Foo {
    public:
        bool operator==(const Foo &other) { return ...; }
    };
    Q_DECLARE_METATYPE(Foo)
    

    然后,简单地把 Q_DEFINE_COMPARATOR 宏旁执行 (即在 Foo.cpp 文件,但不在 Foo.h 文件):

    Q_DEFINE_COMPARATOR(Foo)
    

    之后 QApplication QCoreApplication )例如,启用自定义变量比较器(只需执行一次):

    int main(int argc, char *argv[]) {
        QApplication app(argc, argv);
        CustomVariantComparator::setEnabled(true);
        // more code...
    }
    

    Foo::operator== ).

    QVariant::fromValue(Foo()) == QVariant::fromValue(Foo())