Почему некоторые виджеты не обновляются на Qt5?

Я пытаюсь создать приложение PyQt5, в котором я использовал определенные метки для отображения переменных состояния. Чтобы обновить их, я реализовал пользовательские pyqtSignal вручную. Однако при отладке я обнаружил, что значение GUI QLabel изменилось, но значения не отражаются в главном окне.

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

Вот пример кода (все необходимые библиотеки импортированы, это только проблема создания части, фактический код огромен):

from multiprocessing import Process

def sub(signal):
    i = 0
    while (True):
        if (i % 5 == 0):
            signal.update(i)

class CustomSignal(QObject):
    signal = pyqtSignal(int)
    def update(value):
        self.signal.emit(value)

class MainApp(QWidget):
    def __init__(self):
        super().__init__()
        self.label = QLabel("0");
        self.customSignal = CustomSignal()
        self.subp = Process(target=sub, args=(customSignal,))
        self.subp.start()
        self.customSignal.signal.connect(self.updateValue)

    def updateValue(self, value):
        print("old value", self.label.text())
        self.label.setText(str(value))
        print("new value", self.label.text())

Вывод операторов print соответствует ожидаемому. Однако текст в этикетке не меняется.

Функция update в CustomSignal вызывается некоторым потоком. Я применил тот же метод для обновления индикатора выполнения, который отлично работает.

Есть ли другое решение для этого, кроме processEvents()?

ОС - Ubuntu 16.04.


person Himanshu Shekhar    schedule 25.12.2016    source источник
comment
Покажите свой код, чтобы помочь вам   -  person eyllanesc    schedule 25.12.2016
comment
Добавлен образец кода.   -  person Himanshu Shekhar    schedule 25.12.2016
comment
Пожалуйста, опубликуйте полный код (или, по крайней мере, урезанную версию полного кода), иначе нам будет сложно воспроизвести проблему, просто взглянув на часть кода, и помочь вам.   -  person Eddie    schedule 25.12.2016
comment
Спасибо за вашу помощь. Проблема была с моей реализацией. Я понял это, а также добавил ответ на свой вопрос. Вы можете добавить к нему больше технических деталей.   -  person Himanshu Shekhar    schedule 27.12.2016


Ответы (2)


Ключевая проблема заключается в самой концепции кода.

Процессы имеют свое собственное адресное пространство и не обмениваются данными с другими процессами, если только не используется какой-либо алгоритм межпроцессного взаимодействия. Возможно, модуль multithreading использовался вместо модуля threading, чтобы обеспечить параллелизм, чтобы избежать GIL Python и ускорить программу. Однако подпроцесс не может получить доступ к данным родительского процесса.

Я протестировал два решения для этого случая, и они, кажется, работают.

  • модуль многопоточности: несмотря на то, что многопоточность в Python неэффективна из-за GIL, ее все же в какой-то степени достаточно для базовых требований параллелизма. Обратите внимание на разницу между параллелизмом и ускорением.

  • QThread: поскольку вы используете PyQt, нет никаких проблем с использованием QThread, который является лучшим вариантом, поскольку он требует параллелизма для нескольких ядер, используя системный вызов операционной системы, а не Python в середина.

person Himanshu Shekhar    schedule 27.12.2016

Попробуйте добавить

self.label.repaint()

сразу после обновления текста, вот так:

self.label.setText(str(value))
self.label.repaint()
person Dominic McLoughlin    schedule 03.11.2020