Найти - Пользователи
Полная версия: PyQT и многопоточность
Начало » GUI » PyQT и многопоточность
1 2 3 4 5 6 7
admiral
Здравствуйте. Начал изучать PyQT5 и столкнулся с проблемами.
Пишу тестовую программку, которая должна периодически (раз в секунду, к примеру) долбится на сервер и выводить в статусбаре окна состояние (есть связь или нет связи с сервером)
Проблема в том, что отображение окна идет из основного потока, а стучалку на сервер я запихнул в отдельный поток. Для меня оказалось сюрпризом, что окно я не могу изменять из другого потока.
Нашел статью PyQt: простая работа с потоками, но там под PyQT4.
Что делать? Как можно из отдельного потока менять основное окно?
py.user.next
Там есть сигнал у QtCore.QThread() - finished, его подключаешь к нужному слоту, который вносит изменения. Можно и какой-нибудь специальный сигнал сделать в потоке.
admiral
py.user.next
Там есть сигнал у QtCore.QThread() - finished, его подключаешь к нужному слоту, который вносит изменения. Можно и какой-нибудь специальный сигнал сделать в потоке.
Спасибо.
Думаю правильнее всего было бы создавать свои сигналы.
Может я глупый вопрос задам, но как можно с сигналом передать еще и параметр? К примеру текст сообщения, который в статусбар нужно будет поместить.
py.user.next
admiral
как можно с сигналом передать еще и параметр?
class Thread(QtCore.QThread):
 
    message = QtCore.pyqtSignal(str)
 
...
 
        message.emit('text')
admiral
Спасибо, сейчас попробую.
А еще вопрос: состояние чекбокса я могу считывать из другого потока, или опять как-то через сигнал его считывать надо?
py.user.next
admiral
состояние чекбокса я могу считывать из другого потока
У него есть сигнал toggled, который посылает состояние при переключении. Сигнал подключается к слоту родительского виджета, который и делает требуемые действия. Результат этих действий можно проверять снаружи.
Есть так же метод isChecked(), но добираться до чекбокса снаружи - не очень хорошая идея, так как возникает связывание модулей по содержимому.
admiral
Что-то я совсем запутался… никак не могу сообразить как связать сигнал со слотом…
Приведу пример:
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(“АБРАКАДАБРА”)?
py.user.next
QMainWindow на то и главное окно, что оно должно быть на вершине иерархии, чтобы при его закрытии программа завершалась.
У главного окна сделай слот, меняющий его статусную строку.
В потоке сделай сигнал, а в цикле выпусти его.
Присоедини сигнал к слоту там, где создаёшь объект потока.
admiral
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. Но как это реализовать пока никак не пойму.
admiral
Сейчас попробовал
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'
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB