从线程(concurrent.futures)更改窗口小部件的可见性,在正常模式下不起作用,在调试模式下它起作用,为什么?

时间:2019-04-13 22:51:29

标签: python multithreading pyqt5

我想更改gui中rect的可见性。因此,我在线程中使用了无尽的时间,但它不起作用(仅在调试模式下)。他有人回答了吗?

您能帮我完成我的想法或给我小费以其他方式完成这项工作吗?

最后,我要检查以太网连接,并通过绿色或红色矩形显示它。为了进行测试,我正在向服务器发送一条指定的消息,该服务器会发送回一个答案。

我的代码:

import sys
from PyQt5 import QtWidgets, QtGui
from concurrent import futures
from time import sleep


class MainApplication(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(MainApplication, self).__init__(parent)

        # configure the main window
        self.setWindowTitle('Msg Tool')
        self.resize(230, 330)

        # Check if ethernet is ok
        self.close_connection_test = [0]

        self.e = futures.ThreadPoolExecutor(max_workers=1)
        self.e.submit(self.connection_test)

        # RedRect
        self.red_rect = RedRect(self)
        self.red_rect.move(180, 12.5)
        self.red_rect.setVisible(True)

        # GreenRect
        self.green_rect = GreenRect(self)
        self.green_rect.move(180, 12.5)
        self.green_rect.setVisible(False)

    # Function called at the end of the application
    def closeEvent(self, event):
        self.close_connection_test = [1]  # To stop the endless loop in the task
        self.e.shutdown()  # Shutdown the executer

    def connection_test(self):
        i = 0
        while True:
            i += 1
            if self.close_connection_test == [1]:
                break
            if (i % 2) == 0:
                self.red_rect.setVisible(False)
            else:
                self.red_rect.setVisible(True)
            # self.red_rect.setVisible(False)
            print('Test')
            sleep(1)


class RedRect(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(RedRect, self).__init__(parent)
        self.pen = QtGui.QPen(QtGui.QColor(0, 0, 0))
        self.pen.setWidth(1)
        self.brush = QtGui.QBrush(QtGui.QColor(255, 48, 48))

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        painter.setPen(self.pen)
        painter.setBrush(self.brush)
        painter.drawRect(0, 0, 15, 15)


class GreenRect(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(GreenRect, self).__init__(parent)
        self.pen = QtGui.QPen(QtGui.QColor(0, 0, 0))
        self.pen.setWidth(1)
        self.brush = QtGui.QBrush(QtGui.QColor(124, 252, 0))

    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        painter.setPen(self.pen)
        painter.setBrush(self.brush)
        painter.drawRect(0, 0, 15, 15)


Application = QtWidgets.QApplication(sys.argv)
Application.setStyle('Fusion')
inst_MainApplication = MainApplication()
inst_MainApplication.show()

sys.exit(Application.exec_())

1 个答案:

答案 0 :(得分:0)

首先,您必须在创建self.red_rect之后使用Submit,因为如果您不会看到指出该属性不存在的错误。

class MainApplication(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(MainApplication, self).__init__(parent)

        # configure the main window
        self.setWindowTitle('Msg Tool')
        self.resize(230, 330)

        # RedRect
        self.red_rect = RedRect(self)
        self.red_rect.move(180, 12.5)
        self.red_rect.setVisible(True)

        # GreenRect
        self.green_rect = GreenRect(self)
        self.green_rect.move(180, 12.5)
        self.green_rect.setVisible(False)

        # Check if ethernet is ok
        self.close_connection_test = [0]
        self.e = futures.ThreadPoolExecutor(max_workers=1)
        self.e.submit(self.connection_test)

另一方面,问题是您不应该直接通过pyqtSignal,QMetaObject::invokedMethod(),QEvent或通过将QTimer::singleShot()functools.partial()一起使用的最简单方法直接从另一个GUI更新GUI: / p>

1。 QTimer

# ...
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
# ...
class MainApplication(QtWidgets.QWidget):
    # ...
    def connection_test(self):
        i = 0
        while True:
            i += 1
            if self.close_connection_test == [1]:
                break
            isVisible = i % 2 != 0
            wrapper = partial(self.red_rect.setVisible, isVisible)
            QtCore.QTimer.singleShot(0, wrapper)
            print('Test')
            sleep(1)

2。 pyqtSignal


class MainApplication(QtWidgets.QWidget):
    visibilityChanged = QtCore.pyqtSignal(bool)

    def __init__(self, parent=None):
        # ...


        # RedRect
        self.red_rect = RedRect(self)
        self.red_rect.move(180, 12.5)
        self.red_rect.setVisible(True)
        self.visibilityChanged.connect(self.red_rect.setVisible)

        # ...

    def connection_test(self):
        i = 0
        while True:
            i += 1
            if self.close_connection_test == [1]:
                break
            isVisible = i % 2 != 0
            self.visibilityChanged.emit(isVisible)
            print('Test')
            sleep(1)
# ...

3。 QMetaObject :: invokedMethod

# ...
def connection_test(self):
    i = 0
    while True:
        i += 1
        if self.close_connection_test == [1]:
            break
        isVisible = i % 2 != 0
        QtCore.QMetaObject.invokeMethod(
            self.red_rect,
            "setVisible",
            QtCore.Qt.QueuedConnection,
            QtCore.Q_ARG(bool, isVisible),
        )
        print("Test")
        sleep(1)
# ...

4。 QEvent

class CustomEvent(QtCore.QEvent):
    _type = QtCore.QEvent.User

    def __init__(self, visibility):
        super(CustomEvent, self).__init__(CustomEvent._type)
        self._visibility = visibility

    @property
    def visibility(self):
        return self._visibility

class MainApplication(QtWidgets.QWidget):
    # ...

    def connection_test(self):
        i = 0
        while True:
            i += 1
            if self.close_connection_test == [1]:
                break
            isVisible = i % 2 != 0
            event = CustomEvent(isVisible)
            QtCore.QCoreApplication.postEvent(self, event)
            print("Test")
            sleep(1)

    def event(self, e):
        if e.type() == CustomEvent._type:
            self.red_rect.setVisible(e.visibility)
            return True
        return super(MainApplication, self).event(e)