Уведомления

Группа в Telegram: @pythonsu

#1 Май 10, 2015 18:40:35

admiral
Зарегистрирован: 2013-12-23
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

PyQT и многопоточность

Здравствуйте. Начал изучать PyQT5 и столкнулся с проблемами.
Пишу тестовую программку, которая должна периодически (раз в секунду, к примеру) долбится на сервер и выводить в статусбаре окна состояние (есть связь или нет связи с сервером)
Проблема в том, что отображение окна идет из основного потока, а стучалку на сервер я запихнул в отдельный поток. Для меня оказалось сюрпризом, что окно я не могу изменять из другого потока.
Нашел статью PyQt: простая работа с потоками, но там под PyQT4.
Что делать? Как можно из отдельного потока менять основное окно?



Win7 + Python3.3 + PyScripter

Офлайн

#2 Май 10, 2015 19:00:02

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9873
Репутация: +  853  -
Профиль   Отправить e-mail  

PyQT и многопоточность

Там есть сигнал у QtCore.QThread() - finished, его подключаешь к нужному слоту, который вносит изменения. Можно и какой-нибудь специальный сигнал сделать в потоке.



Офлайн

#3 Май 10, 2015 19:11:05

admiral
Зарегистрирован: 2013-12-23
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

PyQT и многопоточность

py.user.next
Там есть сигнал у QtCore.QThread() - finished, его подключаешь к нужному слоту, который вносит изменения. Можно и какой-нибудь специальный сигнал сделать в потоке.
Спасибо.
Думаю правильнее всего было бы создавать свои сигналы.
Может я глупый вопрос задам, но как можно с сигналом передать еще и параметр? К примеру текст сообщения, который в статусбар нужно будет поместить.



Win7 + Python3.3 + PyScripter

Отредактировано admiral (Май 10, 2015 19:12:05)

Офлайн

#4 Май 10, 2015 19:13:13

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9873
Репутация: +  853  -
Профиль   Отправить e-mail  

PyQT и многопоточность

admiral
как можно с сигналом передать еще и параметр?
class Thread(QtCore.QThread):
 
    message = QtCore.pyqtSignal(str)
 
...
 
        message.emit('text')



Офлайн

#5 Май 10, 2015 21:02:07

admiral
Зарегистрирован: 2013-12-23
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

PyQT и многопоточность

Спасибо, сейчас попробую.
А еще вопрос: состояние чекбокса я могу считывать из другого потока, или опять как-то через сигнал его считывать надо?



Win7 + Python3.3 + PyScripter

Офлайн

#6 Май 11, 2015 01:45:19

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9873
Репутация: +  853  -
Профиль   Отправить e-mail  

PyQT и многопоточность

admiral
состояние чекбокса я могу считывать из другого потока
У него есть сигнал toggled, который посылает состояние при переключении. Сигнал подключается к слоту родительского виджета, который и делает требуемые действия. Результат этих действий можно проверять снаружи.
Есть так же метод isChecked(), но добираться до чекбокса снаружи - не очень хорошая идея, так как возникает связывание модулей по содержимому.



Отредактировано py.user.next (Май 11, 2015 01:45:49)

Офлайн

#7 Май 11, 2015 12:07:09

admiral
Зарегистрирован: 2013-12-23
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

PyQT и многопоточность

Что-то я совсем запутался… никак не могу сообразить как связать сигнал со слотом…
Приведу пример:

class Main_Window(QMainWindow):
    def __init__(self):
        super(Main_Window,self).__init__()
        self.initUI()
    def initUI(self):
        self.statusBar().showMessage('Ready')
class Main_Widget(QWidget):
    def __init__(self):
        super(Main_Widget,self).__init__()
        self.window = Main_Window()
        #self.initUI()
        self.window.setCentralWidget(self)
        self.window.show()
    #Отображаем текст в статусбаре
    def setStatusBar(self,text):
        self.window.statusBar().showMessage(str(text))
class MyThread(Thread):
    def __init__(self):
         Thread.__init__(self)
 
    def run(self):
        time.sleep(5)
        while True:
            #Тут надо как-то вызвать смену текста статусбара
            time.sleep(2)
if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    w = Main_Widget()
    t = MyThread()
    t.start()
    sys.exit(app.exec_())

И вот теперь как мне из потока t можно вызвать w.setStatusBar(“АБРАКАДАБРА”)?



Win7 + Python3.3 + PyScripter

Отредактировано admiral (Май 11, 2015 12:07:43)

Офлайн

#8 Май 11, 2015 12:55:05

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9873
Репутация: +  853  -
Профиль   Отправить e-mail  

PyQT и многопоточность

QMainWindow на то и главное окно, что оно должно быть на вершине иерархии, чтобы при его закрытии программа завершалась.
У главного окна сделай слот, меняющий его статусную строку.
В потоке сделай сигнал, а в цикле выпусти его.
Присоедини сигнал к слоту там, где создаёшь объект потока.



Офлайн

#9 Май 11, 2015 14:10:33

admiral
Зарегистрирован: 2013-12-23
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

PyQT и многопоточность

import time
from PyQt5 import QtCore
from PyQt5.QtCore import Qt,QObject
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QMessageBox, QDesktopWidget
from PyQt5.QtWidgets import QMainWindow, QLabel, QLineEdit, QGridLayout, QCheckBox
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtGui import QPixmap,QImage
from threading import Thread #Потоки
class Main_Window(QMainWindow):
    def __init__(self):
        super(Main_Window,self).__init__()
        self.initUI()
    def initUI(self):
        self.statusBar().showMessage('Ready')
    #Отображаем текст в статусбаре
    def setStatusBar(self,text):
        self.statusBar().showMessage(str(text))
class Main_Widget(QWidget):
    def __init__(self):
        super(Main_Widget,self).__init__()
class MyThread(Thread):
    message = QtCore.pyqtSignal(str)
    def __init__(self):
         Thread.__init__(self)
    def run(self):
        time.sleep(2)
        i = 0
        while True:
            text = str(i)
            i = i+1
            #Тут надо как-то вызвать смену текста статусбара
            self.message.emit(text)
            time.sleep(2)
if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    window = Main_Window()
    widget = Main_Widget()
    window.setCentralWidget(widget)
    window.show()
    #window.connect(QtCore.pyqtSignal("message()"),window.setStatusBar)
    t = MyThread()
    t.start()
    sys.exit(app.exec_())

Переписал. Теперь стало ругаться так:
Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:\Python33\lib\threading.py", line 637, in _bootstrap_inner
    self.run()
  File "D:\MyFiles\tests\1.py", line 50, in run
    self.message.emit(text)
TypeError: pyqtSignal must be bound to a QObject, not 'MyThread'

Я не очень еще разобрался как сконнектить слот и сигнал… но если раскомментировать вот эту строку
#window.connect(QtCore.pyqtSignal("message()"),window.setStatusBar)
То выдается такая ошибка:
Traceback (most recent call last):
  File "<string>", line 420, in run_nodebug
  File "D:\MyFiles\tests\1.py", line 60, in <module>
    window.connect(QtCore.pyqtSignal("message()"),window.setStatusBar)
AttributeError: 'Main_Window' object has no attribute 'connect'

Порывшись в инете понял только то, что объект может генерить сигнал, если он унаследован от QObject. Но как это реализовать пока никак не пойму.



Win7 + Python3.3 + PyScripter

Отредактировано admiral (Май 11, 2015 14:21:22)

Офлайн

#10 Май 11, 2015 14:20:23

admiral
Зарегистрирован: 2013-12-23
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

PyQT и многопоточность

Сейчас попробовал

message = QtCore.pyqtSignal(str)
запихнуть в run(self) - получил такую ошибку:
Traceback (most recent call last):
  File "C:\Python33\lib\threading.py", line 637, in _bootstrap_inner
    self.run()
  File "D:\MyFiles\tests\1.py", line 49, in run
    message.emit(text)
AttributeError: 'PyQt5.QtCore.pyqtSignal' object has no attribute 'emit'



Win7 + Python3.3 + PyScripter

Отредактировано admiral (Май 11, 2015 14:21:37)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version