Qt – actualización de la ventana principal con segundo hilo

tengo una aplicación qt multiproceso. cuando realizo algunos procesos en mainwindow.cpp, al mismo tiempo, deseo actualizar mainwindow.ui desde otro hilo.

tengo mythread.h

#ifndef MYTHREAD_H #define MYTHREAD_H #include  #include "mainwindow.h" class mythread : public QThread { public: void run(); mythread( MainWindow* ana ); MainWindow* ana; private: }; #endif // MYTHREAD_H 

mythread.cpp

 mythread::mythread(MainWindow* a) { cout << "thread created" <setPixmap(i1); ana->ui->horizontalLayout_4->addWidget(label); } 

pero el problema es que no puedo llegar a ana->ui->horizontalLayout_4->addWidget(label);

¿Cómo puedo hacer eso?

pero el problema es que no puedo llegar a ana-> ui-> horizontalLayout_4-> addWidget (label);

Coloque las modificaciones de su UI en una ranura en su ventana principal, y conecte una señal de hilo a esa ranura, es probable que funcione. Creo que solo el hilo principal tiene acceso a la interfaz de usuario en Qt. Por lo tanto, si desea la funcionalidad de la GUI, debe estar allí y solo se puede señalar desde otros subprocesos.

OK, aquí hay un ejemplo simple. Por cierto, tu escenario realmente no requiere extender QThread , por lo que es mejor que no lo hagas, a menos que realmente tengas que hacerlo. Es por eso que en este ejemplo utilizaré un QThread normal con un trabajador basado en QObject , pero el concepto es el mismo si subclase QThread :

La interfaz de usuario principal:

 class MainUI : public QWidget { Q_OBJECT public: explicit MainUI(QWidget *parent = 0): QWidget(parent) { layout = new QHBoxLayout(this); setLayout(layout); QThread *thread = new QThread(this); GUIUpdater *updater = new GUIUpdater(); updater->moveToThread(thread); connect(updater, SIGNAL(requestNewLabel(QString)), this, SLOT(createLabel(QString))); connect(thread, SIGNAL(destroyed()), updater, SLOT(deleteLater())); updater->newLabel("h:/test.png"); } public slots: void createLabel(const QString &imgSource) { QPixmap i1(imgSource); QLabel *label = new QLabel(this); label->setPixmap(i1); layout->addWidget(label); } private: QHBoxLayout *layout; }; 

… y el objeto trabajador:

 class GUIUpdater : public QObject { Q_OBJECT public: explicit GUIUpdater(QObject *parent = 0) : QObject(parent) {} void newLabel(const QString &image) { emit requestNewLabel(image); } signals: void requestNewLabel(const QString &); }; 

El objeto del trabajador se crea y se mueve a otro hilo, luego se conecta a la ranura que crea las tags, luego se invoca su newLabel método newLabel , que es solo un contenedor para emitir la señal requestNewLabel y pasar la ruta a la imagen. La señal se pasa luego del objeto / hilo del trabajador a la ranura de la IU principal junto con el parámetro de la ruta de la imagen y se agrega una nueva etiqueta al diseño.

Como el objeto worker se crea sin parent para poder moverlo a otro hilo, también conectamos la señal thread destroyed al deleteLater() worker deleteLater() .

En primer lugar, “lo estás haciendo mal” . Normalmente desea crear una clase derivada de un QObject y mover esa clase a un nuevo objeto de hilo en lugar de derivar su clase de un Qthread

Ahora, para acceder a los detalles de su pregunta, no puede modificar directamente los elementos de la interfaz de usuario de la secuencia principal de la GUI a partir de una secuencia separada. Tienes que connect una signal de tu segundo hilo a una slot en tu hilo principal. Puede pasar cualquier dato que necesite a través de esta conexión de señal / ranura, pero no puede modificar directamente el elemento ui (lo cual honestamente probablemente no desee si tiene la intención de mantener la interfaz de su aplicación separada del back-end ) Consulte la documentación de señal y ranura de Qt para obtener mucha más información

¿Cómo puedo hacer eso?

Ya tienes las respuestas a lo que deberías estar haciendo, pero no por eso, así que voy a agregar un por qué.

La razón por la que no modifica los elementos de GUI de otro subproceso es porque los elementos de GUI generalmente no son seguros para subprocesos . Esto significa que si tanto el hilo principal de la GUI como el hilo de trabajo actualizan la interfaz de usuario, no puede estar seguro del orden de lo que sucedió cuando.

Para leer datos generalmente, esto a veces puede estar bien (por ejemplo, verificar una condición) pero generalmente no desea que sea el caso. Para escribir datos, esto es casi siempre la fuente de errores muy, muy estresantes que ocurren “al azar”.

Otra respuesta ha puesto de manifiesto los buenos principios de diseño: no solo restringir la lógica de su GUI a un hilo y disparar señales para hablar con él, sino también obligarlo a compartimentar su código de forma agradable. La lógica de presentación (el bit de visualización) y la lógica de procesamiento de datos se pueden separar limpiamente, lo que facilita enormemente el mantenimiento de los dos.

En esta etapa, usted puede pensar: ¡diablos, este negocio de hilos de rosca es demasiado trabajo! Voy a evitar eso. Para ver por qué esta es una mala idea, implemente un progtwig de copia de archivo en un solo hilo con una barra de progreso simple que le indica qué tan lejos está la copia. Ejecútelo en un archivo grande. En Windows, después de un tiempo, la aplicación “se pondrá blanca” (o en XP, creo que se pone gris) y “no responderá”. Esto es muy literalmente lo que está sucediendo.

Las aplicaciones GUI internamente trabajan sobre todo en la variación del procesamiento de “un gran bucle” y el envío de mensajes. Windows, por ejemplo, mide el tiempo de respuesta a esos mensajes. Si un mensaje tarda demasiado en obtener una respuesta, Windows decide que está muerto y se hace cargo. Esto está documentado en GetMessage () .

Así que, aunque parezca bastante trabajo, Signals / Slots (un modelo impulsado por eventos) es básicamente el camino a seguir, otra forma de pensar en esto es que es totalmente aceptable que sus hilos generen “eventos” para la interfaz de usuario también, como actualizaciones de progreso y similares.