es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

No se puede agregar un botón en un hilo de PyQt5.

No entendí por qué este código no funciona.

import sys
from threading import Thread

from PyQt5.QtCore import QSize, Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Mi App")
        self.setFixedSize(QSize(400, 300))

        Thread(target=self.AddButton).start()

    def AddButton(self):
        button = QPushButton("Presióname", self)
        print("Ok")


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

Y alguien me dijo que tenía que usar señales porque no puedo modificar la interfaz de usuario desde hilos externos, así que hice este ejemplo pero aún no funcionó.

class WorkerSignals(QObject):
    starting = pyqtSignal()


class Worker(QRunnable):
    def __init__(self):
        super(Worker, self).__init__()
        self.signals = WorkerSignals()

    @pyqtSlot()
    def run(self):
        self.signals.starting.emit()


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Mi App")
        self.setFixedSize(QSize(400, 300))

        self.threadpool = QThreadPool()
        worker = Worker()
        worker.signals.starting.connect(self.makebutton)
        self.threadpool.start(worker)

    def makebutton(self):
        button = QPushButton("Presióname", self)
        print("gad")

Si alguien puede ayudar, sería encantador.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El problema con el código original es que intenta modificar la IU desde un hilo separado, lo cual no está permitido en PyQt. El enfoque recomendado es utilizar señales y ranuras para comunicarse entre hilos y actualizar la IU desde el hilo principal.

    En el código de ejemplo actualizado, se crea una clase Worker para ejecutar la función makebutton en un hilo separado. Se crea la clase WorkerSignals para definir las señales disponibles. Estas señales se conectan a ranuras en la clase MainWindow, que actualizan la IU en consecuencia.

    Sin embargo, todavía hay un problema con el código actualizado. La función makebutton crea un widget QPushButton en el hilo separado, lo cual no está permitido. Cualquier creación de elementos de IU debe realizarse en el hilo principal. Para resolver este problema, la función makebutton puede emitir una señal con la información necesaria para crear el botón en el hilo principal. La clase MainWindow puede luego conectar esta señal a una ranura que crea el botón.

    Aquí hay un ejemplo de código actualizado que debería funcionar:

    import sys
    from PyQt5.QtCore import QSize, QObject, QRunnable, pyqtSignal, pyqtSlot, QThreadPool
    from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
    
    class WorkerSignals(QObject):
        button_created = pyqtSignal(str)
    
    class Worker(QRunnable):
        def __init__(self):
            super(Worker, self).__init__()
            self.signals = WorkerSignals()
    
        @pyqtSlot()
        def run(self):
            self.signals.button_created.emit("¡Presióname!")
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("Mi Aplicación")
            self.setFixedSize(QSize(400, 300))
    
            self.threadpool = QThreadPool()
            self.worker = Worker()
            self.worker.signals.button_created.connect(self.handle_button_created)
            self.threadpool.start(self.worker)
    
        @pyqtSlot(str)
        def handle_button_created(self, text):
            button = QPushButton(text, self)
            print("Botón creado")
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        window = MainWindow()
        window.show()
        sys.exit(app.exec_())
    

Comments are closed.