вызов exec () для Qdialog в потоке не работает хорошо - PullRequest
1 голос
/ 04 октября 2019

Я хочу вызвать my_dialog.exec () в потоке, но он плохо работает, когда mainwindow (имеется в виду основной поток) обрабатывает событие, я хочу знать, как решить эту проблему

это мой тестпрограмма:

import sys
from PyQt5.Qt import *
from threading import Thread
from time import sleep

class Main(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setGeometry(500, 500, 500, 200)

        self.dialog = QDialog(self)
        self.dialog.setGeometry(500, 500, 200, 100)

        btn = QPushButton('click', self)
        btn.clicked.connect(self.show_dialog)

        self.show()

    def show_dialog(self):
        Thread(target=self.execute).start()

    def execute(self):
        sleep(2)
        # keep moving mainwindow untill dialog have shown
        self.dialog.exec_()

app = QApplication(sys.argv)
e = Main()
sys.exit(app.exec_())

, когда я нажимаю кнопку, сначала она будет спать две секунды. это нормально, когда нет события главного окна. но когда я продолжаю двигать главное окно (или другое событие, например изменение размера) в течение двух секунд сна, оба они перестают отвечать

1 Ответ

1 голос
/ 04 октября 2019

Нет, вы не можете изменить GUI из другого потока, используйте сигналы.

TL; DR;

Я разделяю золотое правило в Qt: Вы не можетеи не должен изменять графический интерфейс из другого потока. Для получения дополнительной информации читайте: Поток GUI и рабочий поток .

Учитывая вышеизложенное, естественным способом взаимодействия между элементами, которые живут в разных потоках в Qt, является использование сигналов, поскольку они потокобезопасный , как показано ниже:

class Main(QMainWindow):
    <b>customSignal = pyqtSignal()</b>

    def __init__(self):
        # ...

        self.show()
        <b>self.customSignal.connect(self.dialog.exec_)</b>

    def show_dialog(self):
        Thread(target=self.execute).start()

    def execute(self):
        sleep(2)
        # keep moving mainwindow untill dialog have shown
        <b>self.customSignal.emit()</b>
...