Метка в графическом интерфейсе PyQt4 не обновляется с каждым циклом цикла FOR

У меня возникла проблема, когда я хочу запустить несколько функций командной строки из программы python с использованием графического интерфейса. Я не знаю, относится ли моя проблема к PyQt4 или она связана с моим неправильным использованием кода Python.

Я хочу, чтобы метка в моем графическом интерфейсе изменила свое текстовое значение, чтобы сообщить пользователю, какая команда выполняется. Моя проблема, однако, возникает, когда я запускаю несколько команд, используя цикл for. Я хотел бы, чтобы метка обновлялась при каждом цикле, однако программа не обновляет метку графического интерфейса при каждом цикле, вместо этого она обновляет себя только один раз полностью для цикл завершается и отображает только последнюю выполненную команду.

Я использую PyQt4 для своей среды с графическим интерфейсом. И я установил, что текстовая переменная для метки действительно обновляется с каждым циклом, но на самом деле она не отображается визуально в графическом интерфейсе.

Есть ли способ заставить метку обновляться? Я пробовал методы update() и repaint() внутри цикла, но они не имеют никакого значения.

Буду очень признателен за любую помощь. Спасибо.

Ронни.

Вот код, который я использую:

# -*- coding: utf-8 -*-
import sys, os
from PyQt4 import QtGui, QtCore
Gui = QtGui
Core = QtCore

# ================================================== CREATE WINDOW OBJECT CLASS
class Win(Gui.QWidget):
    def __init__(self, parent = None):
        Gui.QWidget.__init__(self, parent)

        # --------------------------------------------------- SETUP PLAY BUTTON
        self.but1 = Gui.QPushButton("Run Commands",self)
        self.but1.setGeometry(10,10, 200, 100)

        # -------------------------------------------------------- SETUP LABELS
        self.label1 = Gui.QLabel("No Commands running", self)
        self.label1.move(10, 120)

        # ------------------------------------------------------- SETUP ACTIONS
        self.connect(self.but1, Core.SIGNAL("clicked()"), runCommands)


# =======================================================  RUN COMMAND FUNCTION
def runCommands():
    for i in commands:
        win.label1.setText(i)       # Make label display the command being run
        print win.label1.text()     # This shows that the value is actually
                                    # changing with every loop, but its just not
                                    # being reflected in the GUI label
        os.system(i)

# ======================================================================== MAIN

# ------------------------------------------------------  THE TERMINAL COMMANDS
com1 = "espeak 'senntence 1'"
com2 = "espeak 'senntence 2'"
com3 = "espeak 'senntence 3'"
com4 = "espeak 'senntence 4'"
com5 = "espeak 'senntence 5'"
commands = (com1, com2, com3, com4, com5)

# --------------------------------------------------- SETUP THE GUI ENVIRONMENT
app = Gui.QApplication(sys.argv)
win = Win()
win.show()

sys.exit(app.exec_())

person Ronny    schedule 20.03.2010    source источник


Ответы (3)


Метка обновляется нормально, но графический интерфейс не перерисовывается до конца цикла.

Вот что вы можете с этим сделать:

  • Переместите свой длительный цикл во вторичный поток, рисование графического интерфейса происходит в основном потоке.

  • Вызовите app.processEvents() в своем цикле. Это дает Qt возможность обрабатывать события и перерисовывать графический интерфейс.

  • Разбейте свой цикл и запустите его, используя QTimer с тайм-аутом 0.

Использование потока — лучший вариант, но требует немного больше работы, чем просто вызов processEvents. Делать это с помощью таймера — старомодный способ, который больше не рекомендуется. (см. документацию)

person Georg Schölly    schedule 20.03.2010
comment
Большое спасибо! Я обнаружил, что app.processEvents() изменил метку только после того, как каждая команда уже была выполнена, что было слишком поздно, а также вообще пропустил несколько команд. Что действительно сработало, так это создание нового объекта QThread с методом запуска и вызов метода запуска при нажатии кнопки. Это то, что вы имели в виду? Вот код, который я использовал. Я никогда раньше не знал о многопоточности, поэтому, пожалуйста, скажите мне, если я применил ее неразумно. класс RunCommands(Core.QThread): def run(self): для i в командах: win.label1.setText(i) os.system(i) - person Ronny; 20.03.2010
comment
О, господи, комментарий не распечатался с новыми строками и вкладками, которые я ввел :( - person Ronny; 20.03.2010
comment
@Ronny: Это звучит правильно, но вы должны называть start() вместо run(). - person Georg Schölly; 20.03.2010

У вас есть базовое непонимание того, как работает такой графический интерфейс. Графический интерфейс Qt должен работать в собственном цикле событий. Вместо этого запускается ваш цикл, и графический интерфейс не может выполнять свою работу между выполнениями вашего цикла. То есть, пока ваш цикл for работает, код GUI не получает процессорного времени и не будет обновляться.

Вы можете настроить таймер с событием и выполнять свой код в обработчиках этого события заданное количество времени - это решит вашу проблему.

person Eli Bendersky    schedule 20.03.2010
comment
Спасибо за объяснение в 1-м абзаце вашего ответа. Теперь это дает мне немного больше понимания того, что происходит, и помогает мне немного лучше понять причины, лежащие в основе ответа Георга. Однако я не понимаю фактического решения, которое вы предлагаете. Я очень новичок в программировании. Возможно, будет полезен простой набросок кода, который будет задействован. Несмотря на то, что теперь я нашел решение, которое, похоже, работает, мне было бы очень любопытно также узнать о предложенной вами альтернативе. - person Ronny; 20.03.2010
comment
@Ronny: узнай про QTimer и посмотри несколько примеров его использования - думаю тебе станет понятно - person Eli Bendersky; 20.03.2010

Или вы можете просто вызвать repaint(), чтобы мгновенно обновить графический интерфейс.

person infantry    schedule 20.02.2019