Qt中有哪些功能或概念让你恼火?

时间:2010-09-08 05:03:16

标签: qt qt4

Qt是一个不错的框架和优秀的UI工具包,它有many useful features and concepts。我们大多数人可能都同意Trolltech,最近Nokia,在开发它方面做得非常好。 Qt的最新进展之一是QML,我发现这是一项令人着迷的进步。

但是,我发现一些设计糟糕或执行不当的概念,例如Model/View(概念很好,但实现不是),Phonon媒体框架也是如此。有人说meta-object这个概念让他们疯狂。

所有这些显然或多或少都是主观的,但是你觉得在Qt中使用哪些特征或概念令人烦恼或负担,你如何绕过它们?

5 个答案:

答案 0 :(得分:28)

我对Qt的大多数抱怨来自于API并未完全接受QObject提供的动态。如果你敢于创建一个元对象编译器来为C ++添加动态行为,为什么还要害羞呢?

我在下面列出的所有内容都是我的团队在某些时候需要的东西,我们必须自己编写代码。这很有趣,我们学到了很多关于Qt内部的知识,但我不介意它是否已经完成并准备好使用。

无分布式QObject

你知道,就像在Cocoa一样。他们用QtDBus走了一半 - 唯一剩下的就是网络。我们必须为此实现我们自己的解决方案,因为我们生活在Qt代码之外,我们无法更改内部实现所有不错的功能。

没有用于数据存储的API

当然,每个人都会编写自己不完整的QObject-to-SQLite库。不过,QDataStream是一个非常好的开端。

无数据绑定

好吧,Qt Quick有数据绑定,但数据绑定应该存在于QtCore中。通过良好的数据绑定,编写代表QObject集合的QAbstractItemModel应该是过去的事情:QObjectListModel应该是您所需要的。

(是的,QDataWidgetMapper是个笑话。)

没有QObjects的自动撤消管理

我们的模型类通常是QObjects,Q_PROPERTY有一个可选的NOTIFY信号,正是实现自动撤销所需的信号。这很容易做到它应该已经成为Qt的一部分。 (但是,它需要一些kludges。)

没有收藏属性

并非所有属性都是平等的。其中一些是收藏品。能够以抽象的方式处理这些将是一件好事。

半生不熟的QMetaStuff API

我只讨厌这个API因为我喜欢它。例如,一个人不能:

  1. 动态构建QMetaObjects并替换它们;
  2. 使用QVariants作为参数调用元方法;
  3. 按返回类型,名称或参数类型查询方法;
  4. 使用相应的QMetaMethods(at least not until 4.8);
  5. 连接信号和插槽 例如,
  6. 截取属性set / get的方式与拦截事件的方式相同。
  7. 几乎所有这些都可以轻松解决。 #2的解决方案:

    QVariant call(QObject* object, QMetaMethod metaMethod, QVariantList args)
    {
        QList<QGenericArgument> arguments;
    
        for (int i = 0; i < args.size(); i++) {
    
            // Notice that we have to take a reference to the argument. A 
            // const_cast is needed because calling data() would detach 
            // the QVariant.
    
            QVariant& argument = args[i];
    
            QGenericArgument genericArgument(
                QMetaType::typeName(argument.userType()),
                const_cast<void*>(argument.constData())
            );
    
            arguments << genericArgument;
        }
    
        QVariant returnValue(QMetaType::type(metaMethod.typeName()), 
            static_cast<void*>(NULL));
    
        QGenericReturnArgument returnArgument(
            metaMethod.typeName(),
            const_cast<void*>(returnValue.constData())
        );
    
        // Perform the call
    
        bool ok = metaMethod.invoke(
            object,
            Qt::AutoConnection, // In case the object is in another thread.
            returnArgument,
            arguments.value(0),
            arguments.value(1),
            arguments.value(2),
            arguments.value(3),
            arguments.value(4),
            arguments.value(5),
            arguments.value(6),
            arguments.value(7),
            arguments.value(8),
            arguments.value(9)
        );
    
        if (!ok) {
            // Handle the error...
        } else {
            return returnValue;
        }
    }
    

    可能会删除有用的功能

    在qt-interest中有一个关于DOMstyle sheetscustom file engines将在未来版本的Qt中删除的话题。

    Phonon没有跨平台后端

    除了没有真正起作用之外,Phonon没有稳定的后端可以在三个最常见的平台上运行:Windows,Linux和Mac OS X.有一个VLC后端,但它绝对不稳定,它的许可证尚不清楚,而且,VLC对Mac的支持是“resting on shaky ground”。当然,责任完全在Linux上。多媒体支持有never been one of its strengths。它缺少类似Quicktime或DirectStuff的东西。

    没有加密课程

    有QCryptographicHash和QSSLSocket(及其funny error modes),就是这样。幸运的是,有两个好的库来填补这个空白:BotanQCA。 QCA基于Qt,但是从Java加密类复制其API,所以不是很好。 Botan有一个漂亮的界面,(但?)是“纯粹的”C ++。 Qt风格的加密库仍然缺乏。

答案 1 :(得分:11)

对于制裁来说,这是一个奇怪的问题,但这里有:

qmake牙齿很长(我not the only one to say so)。我使用cmake,尽管它有自己的尴尬。

信号/插槽/等的元对象预处理构建步骤。是一个巨大的买入。许多愿意接受增加的抽象层次的人是那些被其他环境所吸引的人(Java,C#,无论如何)。在围栏的另一边是硬核C ++程序员,他们宁愿使用std::thread而不是QThread

(如果一个C ++程序更加面向服务器且没有GUI,人们似乎会避开Qt,我明白了他们的观点。)

模型/视图既不在这里也不在那里,但它有点微不足道。我批评了线程亲和力问题:

http://blog.hostilefork.com/qt-model-view-different-threads/

此外,我已经将应用程序交叉编译到Mac,Windows和Linux,并且发现Qt并没有像我希望的那样保护我免受平台问题的影响。如果您查看内部以及如何通过极其多样化的代码(例如qnd_x11.cppqdnd_win.cppqdnd_mac.mm实现拖放,那么您会看到"Leaky Abstraction"原则发挥作用。 Qt并没有强加强烈的形式主义;你会得到不同顺序或重复的消息 - 或者在某些平台上根本没有消息。

但除了所有批评之外,我确实喜欢Qt的设计,文档,社区支持和一般审美。你可以做得更糟! (我在看着你,wxWidgets和GTK。)

答案 2 :(得分:5)

我试图解决的问题是Qt,wxWidgets以及可能的其他UI框架的一般问题:

void MainDialog::OnCppException()
{
    throw std::runtime_error("test unhandled exception");
}

这种未处理的C ++异常被Qt框架捕获,阻止了立即异常调试或生成信息性崩溃转储。在Qt允许处理这种情况的地方,原始异常信息和堆栈跟踪将丢失。我试图在两个框架中解决这个问题,并没有找到可接受的解决方案。 Qt专业人士的建议“就是不要这样做”就是我所拥有的,这实际上意味着:不要犯错误,一切都会好的。这是我对Qt和wxWidjets的最大失望。

答案 3 :(得分:1)

我主要在Qt for S60环境中工作,所以有些问题是针对该平台的。

插件系统+ QObjects

你不能用信号声明插件接口,因为插件实现应该从QObject和多个接口派生,所以接口不应该是QObject本身(如果你想在你的接口中有一些信号,则需要)。我在Qt-interest邮件列表中找到的解决方法是将MyQObject * getter添加到您的插件接口,并将所有信号添加到具体的MyQObject类。它有效,但它违反直觉和丑陋。

QSet和其他Qt容器的功能不如stl或boost容器

例如,您无法定义在将元素插入QSet时应使用的较少函数。我想念的其他东西是remove_if和find_if。

QtMobility包中的QServiceFramework

荒谬的图书馆我最近被迫使用。要使用QServiceFramework中安装的“服务”,您必须链接到包含该服务的dll(考虑到其中一个QSf目标是隐藏依赖项,这是毫无意义的)或使用不提供编译的QMetaObject :: invokeMethod时间检查方法,参数类型等,并降低代码可读性:

// using QMetaObject::invokeMethod
QVariantHash data;
bool ok = QMetaObject::invokeMethod(myObject, "getStuff", 
    Q_RETURN_ARG(QVariantHash, data)
    Q_ARG(QString, QString("blah")));
Q_ASSERT(ok);

// using normal syntax
QVariantHash data(myObject->getStuff("blah"));

更糟糕的是,它使用了很多文件系统(迭代dirs寻找插件,与SQLite数据库进行通信),这在S60上运行缓慢。

QPixmap需要QApplication ...

...只有QPixmap具有在原生S60图像(CFbsBitmap类)和Qt数据之间进行转换的方法。因此,您必须将您的应用程序设为QApplication(这会增加启动时间和内存消耗),或者您必须将数据存储在本机S60结构中(这使得整个代码特定于Symbian)

答案 4 :(得分:1)

我有同样的问题,尝试使用变量参数调用方法。我在这里报告了这个问题:https://bugreports.qt-project.org/browse/QTBUG-28833

他们实际上建议我使用未记录的实现细节来解决问题。所以我认为值得将它链接到这里。

最终接受了这个问题(优先级低,仅限Qt5)。