c++ - gui - qt license
¿Qué tan útil es Qt sin su paso de preproceso? (12)
¿Es posible? Siempre que no esté haciendo ninguna programación de GUI, probablemente. Personalmente, casi siempre corro con PyQt en estos días, así que no es una gran preocupación para mí.
Por qué no te debería importar: dada la naturaleza de la "precompilación" si usas cmake o qmake, no es realmente un gran problema en términos de inconvenientes. Si está haciendo algo con una GUI en estos días, debe utilizar un diseñador gráfico para la mayoría del trabajo de todos modos, por lo que ya está agregando algunos pasos de "precompilación".
En cuanto a por qué lo hicieron: Puede que le interese leer la explicación de Qt: http://doc.qt.io/qt-4.8/templates.html
Se reduce a:
- La solución de plantilla carece de propiedades y sobrecarga
- La solución moc evita que las señales rompan la compatibilidad binaria
- El análisis y la modificación del tiempo de ejecución son posibles con el mecanismo de señales / ranuras sin plantillas
En una nota lateral, las señales / ranuras de subprocesamiento múltiple también son una ventaja de su sistema.
Creo que no es razonable que una biblioteca requiera el preprocesamiento de mi código fuente con una herramienta especial. Dicho esto, varias personas me recomendaron la biblioteca Qt para el desarrollo de GUI multiplataforma.
¿Qué tan útil es Qt sin el paso de preproceso?
EDITAR: Está bien, no quiero decir que esta pregunta sea un desgarro para Qt: demasiados fanáticos de Qt lo están tratando como si lo fuera. No quiero discutir los méritos del hecho de que Qt creó esta herramienta de preprocesamiento. Entiendo por qué la herramienta está allí, y entiendo por qué hay grandes partes del diseño de Qt que se basan en la idea del preprocesamiento.
Nunca he usado Qt, ergo no estoy en posición de robarlo. Pero preferiría pagar por escrito una pequeña cantidad de texto repetitivo y no depender de desmantelar todo mi proceso de construcción. No usaré Flex y Bison en mi proyecto actual por la misma razón; si no voy a usar esas herramientas, definitivamente no voy a utilizar otro tipo de preprocesamiento.
Entonces, por favor no me tomes como una copia de Qt. No puedo comentar lo bueno o malo que es; No lo he usado. Solo quiero saber si es posible usarlo sin moc
.
(perdón por revivir una publicación tan antigua)
Se me requirió hacer una asignación C / W para mi unidad de MSc en desarrollo de software 3D.
Desafortunadamente, un requisito era usar Qt para proporcionar un contexto OpenGL en lugar de usar Glut, X11 nativo, Gtk, etc.
No quería usar MOC y con un montón de manipulación pude obtener suficientes devoluciones de llamada (como teclado, mouse, pintura, temporizador, etc.) para hacer una presentación utilizable. Entonces, para usar Qt con un motivo principal para el software OpenGL, realmente funciona bien sin MOC.
Sin embargo, no veo cómo se podría desarrollar una aplicación completa sin usar MOC. Que es una pena.
Esta cosa de Qt MOC es un dolor. No entiendo por qué tantos desarrolladores de C ++ parecen encontrarlo aceptable francamente. ¡Es extremadamente poco práctico y se pondrá crujiente rápidamente! (Intente obtener un código Borland Kylix C ++ para compilar. Pronto se dará cuenta de la mala idea que es).
Si quisiera usar C ++ no estándar, solo usaría Microsoft C ++ / CLI.
Actualmente estoy en la posición de necesitar encontrar alternativas a MOC. Hasta ahora uso GLib para la traducción de texto y estoy en el medio de reingeniería de una biblioteca de señales / ranuras que encontré en la web (sigslot) usando plantillas C ++ y macros C combinados. La parte aburrida y agotadora es rehacer la GUI para mi aplicación y reemplazar widgets Qt normales con mis propios widgets (es decir, QPushButton -> MyPushButton) a través de la promoción de widgets (una característica de Qt Designer). De esta forma puedo hacer que mis widgets emitan señales con plantilla en lugar de Qt. Hay una trampa, aunque. Mis clases de widgets "modificadas" DEBEN ejecutarse a través del preprocesador, pero ese es un paso que ocurre una vez en la vida. Después de eso, puedo seguir.
Puedo permitirme hacer todo esto solo porque ya he escrito una biblioteca de Application Framework con su propio bucle de eventos (bueno, es un contenedor que se conecta con el código de bucle de eventos de Qt), multihilo y clases de cadenas, etc. Mi proyecto solo necesitará Qt para mostrar los widgets agradables e ingeniosos.
Pero si no tienes estas herramientas a tu disposición, que estoy seguro que no tienes, créeme, tratar de deshacerte del preprocesador de Qt va a ser un dolor real en el culo.
Aquí está mi mensaje para ti: si puedes usar QMake o moc, simplemente úsalos.
Es completamente utilizable ahora. El mantenedor de moc ha hecho una alternativa con una sintaxis ligeramente más verbosa que la Qt ordinaria, pero usa C ++ estándar 14 por lo que no hay ningún paso adicional.
(como un lado, moc no es realmente un paso de preprocesamiento sino un generador de código. El código que se escribe es C ++ válido, y moc no cambia nada de eso. Simplemente genera código C ++ adicional para ti).
No considero irrazonable que Qt requiera una herramienta especial de preprocesamiento, considerando cuán grande y completa es una biblioteca.
Otras bibliotecas igualmente exhaustivas como Boost y GLib no requieren herramientas especiales de preprocesamiento, pero sí hacen un uso extensivo del preprocesador estándar C. Qt pudo haber sido implementado usando solo el preprocesador C, pero al usar su propia herramienta de preprocesamiento especial, puede proporcionar una sintaxis más limpia y evitar muchas de las trampas asociadas con las macros del preprocesador C.
Sin embargo, como ya se ha respondido, puede usar Qt sin moc, simplemente nada que requiera señales y ranuras. Sí, esto incluye todas las cosas de la GUI, pero Qt no es de ninguna manera una biblioteca de GUI.
No tengo una respuesta completa, pero según tengo entendido, moc principalmente (o quizás solo) genera código C ++ adicional. Así que, potencialmente, no hay nada que hacer que no puedas hacer tú mismo manualmente. Sin embargo, no tengo idea de lo tedioso que podría ser ni de cuánto estudio podría tomar para comprender todos los conceptos y detalles necesarios que entran en ese código.
Además, como nota al margen: en mi opinión, la razón por la que obtienes tanta defensa de Qt y moc es porque comenzaste tu pregunta con la enérgica frase "Creo que no es razonable", lo que se interpreta fácilmente como que significa que no lo haces. Creo que el moc debería haber existido alguna vez. Esto distrae de tu pregunta real. Creo que hubiera sido mejor decir "el moc no encaja en mi sistema de construcción" o simplemente "tengo mis propias razones para no querer usarlo".
Puede usar Qt sin el moc, pero luego pierde ciertas funciones, especialmente aquellas que hacen que Qt sea interesante en primer lugar (como la mayoría de las cosas de la GUI, señales y ranuras, y la traducción de cadenas). Pero sigue siendo una buena biblioteca de propósito general, incluso sin moc.
Qt no requiere el uso de moc solo para usarlo, requiere ese uso si usted crea una subclase de QObject y para declarar las señales y las ranuras en sus clases personalizadas.
No es irrazonable, moc proporciona características que C ++ no tiene, señales / ranuras, introspección, etc.
Entonces, para hacer algo mínimamente avanzado, TENDRÁS que usar el preprocesador moc. Lo amas o lo odias.
Realmente no puedo pensar en algo tan único y útil con Qt sin usar QObjects. Desearía que trabajaran en ese paso previo a la compilación.
Si solo necesita conectarse a señales provenientes de objetos Qt, una solución de pirateo es utilizar objetos QT existentes que tengan ranuras virtuales públicas o protegidas que coincidan con la firma de la señal a la que desea conectarse. Puede subclasificar el objeto QT y volver a implementar la ranura virtual como un proxy para realizar cualquier acción que necesite cuando se emita la señal QT. P.ej,
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, e.g., to a QWebView object
SignalProxy proxy;
QWebView webview;
QObject::connect( &webview, SIGNAL(loadFinished(bool)),
&proxy, SLOT(setVisible(bool)) );
No es bonito, pero hace bien el trabajo. Si estuvieras realmente decidido a prescindir del MOC, probablemente podrías ubicar los objetos Qt existentes para utilizarlos como proxy para casi cualquier firma de señal que necesites, por ejemplo, el QAbstract ... las clases tienen muchas ranuras virtuales, y podrías esconder todo eso maldad en una biblioteca que proporciona señales de refuerzo o API de estilo tr1 :: function <> para conectarse a señales QT.
Llamar ranuras en objetos QT es menos preocupante que recibir señales, ya que generalmente puede invocar el método de ranura directamente.
Tengo una solución, que no es súper limpia y no es 100% satisfactoria, pero que permite conectar señales Qt a tu propio código sin tener que usar el compilador MOC (tenía exactamente la misma restricción que en la pregunta, es decir, no puedo ejecutar el compilador MOC en el proceso de construcción de mi aplicación).
Para poder capturar señales de Qt sin usar MOC, estoy usando los siguientes trucos:
(1) obtenga la definición de QMetaCallEvent (cópielo): en Qt 5.x, tendrá algo como:
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) En su clase de widget que necesita capturar señales Qt, heredará de un widget Qt (digamos QButton), y definirá la siguiente función:
// 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) sobrecarga la función de evento ():
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) ;
}
Ahora, si llama a connect_sender (qobject, signal_name, method_index), esto llamará a event () cada vez que se active la señal, con el method_index especificado recuperado en ev-> id ().
Nota importante: he estado usando este truco en mi aplicación durante varios años, funciona bastante bien, pero no está muy limpio. Una de las consecuencias es que cada vez que cambia la definición de QMetaCallEvent, debe editar su declaración en consecuencia (desafortunadamente no está expuesta en los archivos de encabezado de Qt).
Usar Qt mientras se evita el moc
será más difícil que usarlos juntos como se esperaba. También sacrificará la mayoría de las características interesantes que motivaron a otros a recomendar Qt.
Sin moc
no puedes
- Utilice señales y ranuras (que son casi necesarias para la interfaz de usuario)
- Utilice el sistema de propiedad dinámico (necesario para escribir complementos, entre otras cosas)
- Usa las funciones de internacionalización
- Espere recibir ayuda de alguien cuando nada funciona
Si quieres usar Qt, usa moc
. De hecho, ni siquiera se preocupe por moc
, solo use QMake. Puede escribir un archivo QMake .pro que se vea así:
TARGET = myApp
FORMS += MainWindow.ui
HEADERS += MainWindow.h
SOURCES += MainWindow.cpp
SOURCES += main.cpp
Todo se encargará automáticamente. O puede pasar todo su tiempo tratando de descubrir cómo evitar el moc
.
Ver http://doc.qt.nokia.com/4.6/metaobjects.html y http://doc.qt.nokia.com/4.6/moc.html#moc