在没有预处理步骤的情况下,Qt可用性如何?

我认为图书馆需要用特殊工具预处理我的源代码是不合理的。 也就是说,有几个人向我推荐了Qt库进行跨平台的GUI开发。

没有预处理步骤,Qt的可用性如何?

编辑:好的人,我不是意味着这个问题作为对Qt的裂口 – 太多的Qt粉丝正在对待它,就好像它是。 我不想讨论Qt提出这个预处理工具的优点。 我明白为什么这个工具就在那里,而且我明白为什么Qt的devise有很大一部分是build立在预处理的基础上的。

我从来没有使用过Qt,所以我没有任何权利去解决这个问题。 但是我更愿意自己写小量的样板文件,而不是依靠把整个构build过程拆开。 我不会因为同样的原因在我现在的项目中使用Flex和Bison。 如果我不使用这些工具,我绝对不会使用另一种预处理。

所以,请不要把我当作Qt的翻版。 我无法评论它有多好或不好; 我没有用过 我只是想知道是否有可能使用它没有moc

Qt不需要使用moc就可以使用它,如果你创buildQObject的一个子类,并且需要在你的自定义类中声明信号和插槽,就需要使用它。

这不是不合理的,moc提供了C ++没有的function,信号/槽,内省等。

所以,要做一些最低级的事情,你必须使用moc预处理器。 你要么爱它,要么恨它。

我不认为Qt需要一个特殊的预处理工具是不合理的,因为它考虑了一个库的大小和全面性。

其他类似的综合库如Boost和GLib不需要特殊的预处理工具,但是广泛使用标准的C预处理器。 Qt可以只使用C预处理器来实现,但是通过使用它自己特殊的预处理工具,它可以提供更清晰的语法,并避免许多与C预处理器macros相关的缺陷。

正如已经回答,虽然,你可以使用QT没有MOC,只是没有任何需要信号和插槽。 是的,这包括所有的GUI东西,但Qt绝不仅仅是一个GUI库。

使用Qt,同时避免moc将比仅仅按照预期一起使用它们更困难。 你也将牺牲大部分激发他人推荐Qt的有趣function。

没有moc你不能

  • 使用信号和插槽(这些都是用户界面需要的)
  • 使用dynamic属性系统(除其他外,需要编写插件)
  • 使用国际化function
  • 没有任何工作的时候,希望得到任何人的帮助

如果你想使用Qt,使用moc 。 其实不用担心moc ,只要用QMake即可。 您可以编写一个如下所示的QMake .pro文件:

 TARGET = myApp FORMS += MainWindow.ui HEADERS += MainWindow.h SOURCES += MainWindow.cpp SOURCES += main.cpp 

一切都会自动照顾。 或者你可以花费你所有的时间,试图找出如何避免moc

请参阅http://doc.qt.nokia.com/4.6/metaobjects.html和http://doc.qt.nokia.com/4.6/moc.html#moc

我没有一个完整的答案,但据我了解,moc主要(或者也许只是)生成额外的C ++代码。 所以可能没有什么可做的,你也不能自己手动做。 但是,我不知道可能是多么繁琐,也不知道可能需要多less研究来理解代码中所有必要的概念和细节。


另外,正如我注意到的那样:在我看来,为Qt和moc提供尽可能多的防御的原因是因为你开始用强硬的措辞“我认为这是不合理的”来解决这个问题,这个问题很容易解释为,不要以为moc应该存在。 这分心从您的实际问题。 我认为最好只说“moc不适合我的构build系统”,或者简单地说“我有我自己不想使用它的理由”。

如果不使用QObject,我真的无法想象如此独特和有用的Qt。 我希望他们能够在编译前的一步工作。

你可以在不使用moc的情况下使用Qt,但是你会失去某些function,尤其是那些首先让Qt感兴趣的function(比如大部分的GUI东西,信号和插槽以及string翻译)。 但它仍然是一个很好的通用库,即使没有moc。

可能吗? 只要你没有做任何GUI编程,可能。 就我个人而言,我现在主要使用PyQt运行,所以对我来说不是一个大问题。

为什么你不应该在意:鉴于“预编译”的本质,如果你使用cmake或者qmake,那么在不方便的时候就没什么大不了的了。 如果您现在正在使用GUI进行任何操作,那么无论如何您都应该使用graphicsdevise器来完成大部分工作,因此您已经添加了一些“预编译”步骤。

关于他们为什么这样做:您可能有兴趣阅读Qt的解释: http : //doc.qt.io/qt-4.8/templates.html

归结为:

  • 模板解决scheme缺less属性和重载
  • moc解决scheme可以防止信号破坏二进制兼容性
  • 使用非模板化信号/插槽机制可以进行运行时分析和修改

另外,multithreading信号/插槽也是其系统的一个优点。

目前我需要findMOC的替代品。 到目前为止,我使用GLib进行文本翻译,并且正在使用C ++模板和Cmacros组合在networking(sigslot)上find的信号/插槽库进行重新devise。 枯燥乏味的部分是为我的应用程序重做GUI,并通过小部件升级(Qt Designer的一个特性)用我自己的小部件(即QPushButton – > MyPushButton)replace普通的Qt小部件。 这样我可以让我的小部件发出模板化的信号,而不是Qt的。 有一个问题, 我的“修改”的部件类必须通过预处理器运行,但是这是一个一生中的一步。 之后,我可以继续前进。

我可以负担得起所有这些,只是因为我已经编写了一个带有自己的事件循环的应用程序框架库(嗯,它是一个封装在Qt的事件循环代码上),multithreading和string类等等。我的项目只需要Qt显示漂亮和漂亮的小部件。

但是,如果您没有这些工具可供您使用 – 我相信您没有 – 相信我,试图摆脱Qt的预处理器将是一个皇家的痛苦。

这里是我给你的信息:如果你可以使用QMake或者moc,就使用它们。

如果您只需要连接来自Qt对象的信号,则解决scheme就是利用现有的QT对象,这些QT对象具有与要连接的信号签名相匹配的公共或受保护的虚拟插槽。 您可以对QT对象进行子类化,并重新实现虚拟插槽作为代理,以在发出QT信号时执行您所需的任何操作。 例如,

 class SignalProxy : public QWidget { public: SignalProxy() {} void setVisible( bool isVisible ) { // Do whatever you want to do when the signal is emitted. } }; // code to connect the signal, eg, to a QWebView object SignalProxy proxy; QWebView webview; QObject::connect( &webview, SIGNAL(loadFinished(bool)), &proxy, SLOT(setVisible(bool)) ); 

这不是很好,但它完成了工作。 如果你真的打算在没有MOC的情况下做,你可能会find现有的Qt对象来用作你所需要的任何信号签名的代理,例如,QAbstract …类有很多虚拟槽,你可以隐藏所有在库中提供一个提升信号或tr1 :: function <>样式的API来连接QT信号。

在QT对象上调用插槽与接收信号相比不那么重要,因为通常可以直接调用插槽方法。

现在完全可用。 moc的维护者已经做了一个比普通的Qt稍微冗长的语法,但它使用标准的C ++ 14,所以没有额外的步骤。

它被称为“Verdigris”

(另外,moc并不是一个预处理步骤,而是一个代码生成器,你编写的代码是有效的C ++,moc不会改变它,它只是为你生成额外的C ++代码。

(对于重振这样一个旧post感到抱歉)

我被要求在3D软件开发中为我的硕士课程做C / W作业。

不幸的是,需要使用Qt来提供OpenGL上下文,而不是使用Glut,本机X11,Gtk等等。

我不想使用MOC,而且有很多的摆弄,我只能得到足够的callback(如键盘,鼠标,绘画,定时器等)来提交可用的内容。 所以对于使用Qt的OpenGL软件的主要原因,它实际上工作正常,没有MOC。

但是,我不明白如何在不使用MOC的情况下开发完整的应用程序。 这是一个耻辱。

这Qt MOC的东西是一个痛苦。 我不明白为什么有这么多的C ++开发者坦率地认为它是可以接受的。 这是非常不可移动的,将快得硬! (只要尝试获得一些Borland Kylix C ++代码来编译,你很快就会意识到这是一个坏主意)。

如果我想使用非标准的C ++,我只能使用Microsoft C ++ / CLI。

我有一个解决scheme,这是不是超级干净,不是100%满意,但允许连接Qt信号到您自己的代码,而不必使用MOC编译器(我有完全相同的约束,如在问题,即不能在我的应用程序的构build过程中运行MOC编译器)。

为了能够在不使用MOC的情况下捕获Qt信号,我正在使用以下技巧:

(1)获取QMetaCallEvent的定义(从它复制):在Qt 5.x,你会有这样的:

 class QMetaCallEvent : public QEvent { public: inline int id() const { return method_offset_ + method_relative_; } virtual void placeMetaCall(QObject *object); private: QMetaCallEvent(); void* slotObj_; const QObject *sender_; int signalId_; int nargs_; int *types_; void **args_; void *semaphore_; void *callFunction_; ushort method_offset_; ushort method_relative_; }; 

(2)在需要捕获Qt信号的小部件类中,您将从Qt小部件(如QButton)inheritance,并定义以下函数:

 // Inspired by QObject::connect() in src/corelib/kernel/qobject.cpp bool connect_sender( const QObject* sender, const char* signal, int method_index ) { // We need to generate MetaCall events (since QObject::event() // is the only virtual function we can overload) // (note that the other connection types do not generate events). Qt::ConnectionType type = Qt::QueuedConnection ; if(sender == 0 || signal == 0) { std::cerr << "null sender or signal" << std::endl ; return false ; } QByteArray tmp_signal_name; const QMetaObject *smeta = sender->metaObject(); ++signal; //skip code int signal_index = smeta->indexOfSignal(signal); if (signal_index < 0) { // check for normalized signatures tmp_signal_name = QMetaObject::normalizedSignature(signal).prepend(*(signal - 1)); signal = tmp_signal_name.constData() + 1; signal_index = smeta->indexOfSignal(signal); if (signal_index < 0) { std::cerr << "Signal \'" << signal << "\' not found" << std::endl ; return false; } } int *types = 0; QMetaObject::connect( sender, signal_index, this, method_index, type, types ) ; return true ; } 

(3)重载event()函数:

 bool event(QEvent* e) { if(e->type() == QEvent::MetaCall) { QMetaCallEvent* ev = static_cast<QMetaCallEvent*>(e); switch(ev->id()) { // insert your handling code here } return true; } return QObject::event(e) ; } 

现在,如果调用connect_sender(qobject,signal_name,method_index),每次触发信号时都会调用event(),并在ev-> id()中检索指定的method_index。

重要提示:我已经在我的应用程序中使用了这个技巧好几年了,它工作的很好,但它不是很干净。 其中一个后果是,无论何时QMetaCallEvent的定义发生变化,您都需要相应地编辑您的声明(不幸的是它不会在Qt的头文件中公开)。