K_DOT
@K_DOT
DevOps инженер

Зависает GUI при выполнении цикла в отдельном потоке. Как исправить?

Здравствуйте. Только начал изучать PyQt и у меня возникла проблема с потоками. Дело в том, что мне нужно, чтобы в отдельном потоке выполнялся цикл, который получает данные и отображает в окне. Я написал такой код:
class ConfThread(QtCore.QThread):
    def __init__(self, ex=None, parent=None):
        super(ConfThread, self).__init__(parent)
        self.test = ex

    def __del__(self):
        self.wait()

    def conf(self):
        while self.test.player.playing:
            title = [self.test.player.source.info.title[:20]+'...' if len(self.test.player.source.info.title)>=9 else self.test.player.source.info.title, "Unknown"][self.test.player.source.info.title == '']
            author = [self.test.player.source.info.author[:20], "Unknown"][self.test.player.source.info.author == '']
            album =  [self.test.player.source.info.album[:20], "Unknown"][self.test.player.source.info.album == '']
            genre = [self.test.player.source.info.genre[:20], "Unknown"][self.test.player.source.info.genre == '']
            tg.labTitle.setText(title) 
            tg.labArtist.setText(author) 
            tg.labArtist.setText(album) 
            tg.labYear.setText(genre) 
            tg.lab.setText(str(datetime.datetime.fromtimestamp(test.player.time).strftime('%M:%S')))    
            time.sleep(1)  

    def run(self):
        self.conf()

Но при запуске потока графический интерфейс зависает.
Если заменить while self.test.player.playing: на if self.test.player.playing: то графический интерфейс не зависает, но мне нужно, чтобы метод conf вызывался каждую секунду, а не один раз при запуске потока. Попробовал сделать так:
def run(self):
    timer = QtCore.QTimer()
    timer.timeout.connect(self.conf)
    timer.start(1000)
Но так conf вообще не вызывается.
Помогите пожалуйста. С PyQt и созданием граф. интерфейса раньше дело не имел.

UPD:
Поток запускается при нажатии на кнопку
def start():
    th = ConfThread(ex=player)
    th.start()

gui.connect(gui.butPlay, QtCore.SIGNAL('clicked()'), start)
  • Вопрос задан
  • 5267 просмотров
Решения вопроса 1
K_DOT
@K_DOT Автор вопроса
DevOps инженер
Наконец-то я нашел ответ. Оказалось, я неправильно запускал поток. Насколько я понял, это было из-за того, что запускал поток вне класса PlayerGui. Примерно такой код запуска потока у меня получился.
class PlayerGui(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, None)

        self.th = ConfThread(ex='player')

        self.lmain = QtGui.QGridLayout(self)
        self.layout = QtGui.QGridLayout()
        self.setGeometry(600, 300, 600, 500)
        self.setMinimumSize(400, 450)
        self.butPlay = QtGui.QPushButton("start", self)
        self.layout.addWidget(self.butPlay,3, 0)

        self.connect(self.butPlay, QtCore.SIGNAL("clicked()"), self.start)
        
        self.lmain.addLayout(self.layout, 0,0)


    def start(self):
        self.th.start()
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
sheknitrtch
@sheknitrtch
У интерпретатора Python есть одна особенность: GIL. В интернете вы найдёте очень много статей о том, что это такое, и как GIL помогает/мешает писать многопоточные приложения.
В случае использования QTimer, переменная timer локальная. Значит, после завершения метода run(self) эта переменная будет уничтожена и таймер никогда не сработает. Попробуйте написать:
def run(self):
    timer = QtCore.QTimer()
    timer.timeout.connect(self.conf)
    timer.start(1000)
    self.timer = timer
Ответ написан
risik
@risik
Программист
А покажите как именно Вы запускаете поток
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы