Найти - Пользователи
Полная версия: PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)
Начало » GUI » PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)
1 2
Kyrym
Вот работающий код с двумя потоками:
 import _thread
from datetime import datetime
from time import sleep
def hel():  #описываем функцию, которую собираемся запустить параллельно основному потоку
    d = datetime.today()
    time_x = d.strftime('%H:%M') # часы, минуты сейчас    
    print('Hello,world!')
    y = 0
    while y < 10:
        y += 1
        print(time_x)
        sleep(2)
_thread.start_new_thread(hel,()) #запускаем функцию в качестве параллельного потока 
sleep(5)
print('Done')

Если наша программа имеет графическую оболочку и функцию типа hel() - см. пример - только на бесконечное выполнение, то GUI почему-то не загружается. hel() начинает выводить время в Shell, и на этом всё кончается. В чём же проблема?
_________________
Может из-за того, что _thread - это фиктивная мультипоточность?
PEHDOM
не удалось повторить вашу проблему
 import _thread, sys
from datetime import datetime
from time import sleep
def hel():  #описываем функцию, которую собираемся запустить параллельно основному потоку
    d = datetime.today()
    time_x = d.strftime('%H:%M') # часы, минуты сейчас
    print('Hello,world!')
    y = 0
    while y < 10:
        y += 1
        print(time_x)
        sleep(2)
_thread.start_new_thread(hel,()) #запускаем функцию в качестве параллельного потока
from PyQt4 import QtGui
app = QtGui.QApplication(sys.argv)
Mw = QtGui.QWidget()
Mw.show()
sys.exit(app.exec_())
гуи запускаеться, и в консоли отдельный поток выводит Hello,world! и время
Kyrym
Понял я, в чём была моя ошибка. Я thread пытался запустить из класса гуи.
Kyrym
Эм… А как правильно сослаться из внешней функции на поле GUI?
Т.е. в данном примере выводить время в текстовое поле?
Вот эта строка № 58:
 Window.self.pole_vivod.append(time_x)
 # Python 3. PyQt4
# -*- coding: utf-8 -*-
import sys, _thread
from PyQt4 import QtGui, QtCore
from datetime import datetime
from time import sleep
# ЦВЕТА ПОЛЕЙ
sss_vivod = ("background-color: #456173; color: #f2f2f0; font: 14pt 'Courier New'")
# ГРАФИКА
class Window(QtGui.QWidget): # Класс Window  наследует класс QWidget
    def __init__(self, parent=None): # Создаёт конструктор класса, parent - ссылка на родительский эл-т
        QtGui.QWidget.__init__(self, parent)
        self.resize(200, 300) # шир / выс окна         
# БЛОК РАЗМЕТКИ
        self.vbox = QtGui.QVBoxLayout()
        # ---
        self.pole_vivod = QtGui.QTextEdit('')
        self.pole_vivod.setStyleSheet(sss_vivod)
        self.vbox.addWidget(self.pole_vivod)
        # ---
        self.btn = QtGui.QPushButton('Пуск')
        self.vbox.addWidget(self.btn)
        # ---
        self.setLayout(self.vbox)
        # ---
        Window.on_start(self)
    # ЛОГИКА
    
    def on_start(self):
        def ap(i): # ap(строка)            
            data.append(i)
        def aps(i): # aps(список)
            i = ''.join(map(str, i))
            data.append(str(i))
            
        data = []        
        self.pole_vivod.setText('')
        for i in data:
            self.pole_vivod.append(str(i))
        self.pole_vivod.moveCursor(QtGui.QTextCursor.Start)
# ФУНКЦИЯ ВРЕМЕНИ
def hel():  #описываем функцию, которую собираемся запустить параллельно основному потоку
    d = datetime.today()
    time_x = d.strftime('%H:%M') # часы, минуты сейчас
    print('Hello,world!')
    y = 0
    while y < 6:
        y += 1
        print(time_x)
        Window.self.pole_vivod.append(time_x) # КАК ПРАВИЛЬНО НАПИСАТЬ????
        sleep(2)
# ПОТОКИ
_thread.start_new_thread(hel,())
# КОНЕЦ
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = Window() # создаёт экземпляр окна из класса   
    window.show() # запускает окно
    sys.exit(app.exec_())


vic57
а почему не QTimer?
Kyrym
vic57
а почему не QTimer?
ой, ну что знаю, то и использую
vic57
давно уже все задокументировано
https://github.com/Werkov/PyQt4/blob/master/examples/widgets/digitalclock.py
Kyrym
vic57, спасибо, конечно, но мой вопрос не в том, как время выводить.
vic57
фишка в таймауте
PEHDOM
Kyrym
Эм… А как правильно сослаться из внешней функции на поле GUI?
ну для начала в фукцию можно передать калбек функцию класса GUI, или ссылку на сам элемент GUI.
Но есть несколько НО.
Во первых: _thread достаточно низкоуровневый модуль, лучше использовать threading или multiprocessing.
Во вторых: в вашем конкретном случае логичнее былобы использоваь вместо _thread (threading/multiprocessing) QThread , раз уж вы используете QT, у которого есть система сигналов-слотов. Тогда вы просто сможете соединить сигнал вашего потока с нужным вам слотом ГУИ.
Ну и в третьх, для вашей конкретной задачи, многопоточность вообще не нужна. QTimer дергающий нужный метод через заданый интервал, обновляющий текст, вполне справиться.
Это в общих чертах..
вариант с передчай окна
  # Python 3. PyQt4
# -*- coding: utf-8 -*-
import sys, _thread
from PyQt4 import QtGui, QtCore
from datetime import datetime
from time import sleep
# ЦВЕТА ПОЛЕЙ
sss_vivod = ("background-color: #456173; color: #f2f2f0; font: 14pt 'Courier New'")
# ГРАФИКА
class Window(QtGui.QWidget): # Класс Window  наследует класс QWidget
    def __init__(self, parent=None): # Создаёт конструктор класса, parent - ссылка на родительский эл-т
        QtGui.QWidget.__init__(self, parent)
        self.resize(200, 300) # шир / выс окна
# БЛОК РАЗМЕТКИ
        self.vbox = QtGui.QVBoxLayout()
        # ---
        self.pole_vivod = QtGui.QTextEdit('')
        self.pole_vivod.setStyleSheet(sss_vivod)
        self.vbox.addWidget(self.pole_vivod)
        # ---
        self.btn = QtGui.QPushButton('Пуск')
        self.vbox.addWidget(self.btn)
        # ---
        self.setLayout(self.vbox)
        # ---
        Window.on_start(self)
    # ЛОГИКА
    def on_start(self):
        def ap(i): # ap(строка)
            data.append(i)
        def aps(i): # aps(список)
            i = ''.join(map(str, i))
            data.append(str(i))
        data = []
        self.pole_vivod.setText('')
        for i in data:
            self.pole_vivod.append(str(i))
        self.pole_vivod.moveCursor(QtGui.QTextCursor.Start)
# ФУНКЦИЯ ВРЕМЕНИ
def hel(window):  #описываем функцию, которую собираемся запустить параллельно основному потоку
    d = datetime.today()
    time_x = d.strftime('%H:%M') # часы, минуты сейчас
    print('Hello,world!')
    y = 0
    while y < 6:
        y += 1
        print(time_x)
        window.pole_vivod.append(time_x) 
        sleep(2)
# КОНЕЦ
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = Window() # создаёт экземпляр окна из класса
    # ПОТОКИ
    _thread.start_new_thread(hel,(window,))
    window.show() # запускает окно
    sys.exit(app.exec_())
вариант с калбеком:
  # Python 3. PyQt4
# -*- coding: utf-8 -*-
import sys, _thread
from PyQt4 import QtGui, QtCore
from datetime import datetime
from time import sleep
# ЦВЕТА ПОЛЕЙ
sss_vivod = ("background-color: #456173; color: #f2f2f0; font: 14pt 'Courier New'")
# ГРАФИКА
class Window(QtGui.QWidget): # Класс Window  наследует класс QWidget
    def __init__(self, parent=None): # Создаёт конструктор класса, parent - ссылка на родительский эл-т
        QtGui.QWidget.__init__(self, parent)
        self.resize(200, 300) # шир / выс окна
# БЛОК РАЗМЕТКИ
        self.vbox = QtGui.QVBoxLayout()
        # ---
        self.pole_vivod = QtGui.QTextEdit('')
        self.pole_vivod.setStyleSheet(sss_vivod)
        self.vbox.addWidget(self.pole_vivod)
        # ---
        self.btn = QtGui.QPushButton('Пуск')
        self.vbox.addWidget(self.btn)
        # ---
        self.setLayout(self.vbox)
        # ---
        Window.on_start(self)
    # ЛОГИКА
    def printTime(self, time_x):
        self.pole_vivod.append(time_x)
    def on_start(self):
        def ap(i): # ap(строка)
            data.append(i)
        def aps(i): # aps(список)
            i = ''.join(map(str, i))
            data.append(str(i))
        data = []
        self.pole_vivod.setText('')
        for i in data:
            self.pole_vivod.append(str(i))
        self.pole_vivod.moveCursor(QtGui.QTextCursor.Start)
# ФУНКЦИЯ ВРЕМЕНИ
def hel(callback):  #описываем функцию, которую собираемся запустить параллельно основному потоку
    d = datetime.today()
    time_x = d.strftime('%H:%M') # часы, минуты сейчас
    print('Hello,world!')
    y = 0
    while y < 6:
        y += 1
        print(time_x)
        callback(time_x) 
        sleep(2)
# КОНЕЦ
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = Window() # создаёт экземпляр окна из класса
    # ПОТОКИ
    _thread.start_new_thread(hel,(window.printTime,))
    window.show() # запускает окно
    sys.exit(app.exec_())
Пример с QThread
  # Python 3. PyQt4
# -*- coding: utf-8 -*-
import sys, _thread
from PyQt4 import QtGui, QtCore
from datetime import datetime
from time import sleep
# ПОТОКИ
class MyThread(QtCore.QThread):
    currentTime = QtCore.pyqtSignal(str) # сигнал который мы будем передавать 
    def __init__(self):
        super().__init__()
    def run(self): # наша функция(полезная работа), 
        d = datetime.today()
        time_x = d.strftime('%H:%M') # часы, минуты сейчас
        print('Hello,world!')
        y = 0
        while y < 6:
            y += 1
            print(time_x)
            self.currentTime.emit(time_x)  # генерируем сигнал
            sleep(2)
# ЦВЕТА ПОЛЕЙ
sss_vivod = ("background-color: #456173; color: #f2f2f0; font: 14pt 'Courier New'")
# ГРАФИКА
class Window(QtGui.QWidget): # Класс Window  наследует класс QWidget
    def __init__(self, parent=None): # Создаёт конструктор класса, parent - ссылка на родительский эл-т
        QtGui.QWidget.__init__(self, parent)
        self.resize(200, 300) # шир / выс окна
# БЛОК РАЗМЕТКИ
        self.vbox = QtGui.QVBoxLayout()
        # ---
        self.pole_vivod = QtGui.QTextEdit('')
        self.pole_vivod.setStyleSheet(sss_vivod)
        self.vbox.addWidget(self.pole_vivod)
        # ---
        self.btn = QtGui.QPushButton('Пуск')
        self.vbox.addWidget(self.btn)
        # ---
        self.setLayout(self.vbox)
        # ---
        Window.on_start(self)
        # потоки и конекты
        self.timeFunc = MyThread()          # создаем инстанс потока
        self.timeFunc.currentTime.connect(self.printTime)  # соединяем сигнал из потока с методом printTime
        self.timeFunc.start()               # запускаем поток
    # ЛОГИКА
    def printTime(self, time_x):
        self.pole_vivod.append(time_x)
    def on_start(self):
        def ap(i): # ap(строка)
            data.append(i)
        def aps(i): # aps(список)
            i = ''.join(map(str, i))
            data.append(str(i))
        data = []
        self.pole_vivod.setText('')
        for i in data:
            self.pole_vivod.append(str(i))
        self.pole_vivod.moveCursor(QtGui.QTextCursor.Start)
# КОНЕЦ
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = Window() # создаёт экземпляр окна из класса
    window.show() # запускает окно
    sys.exit(app.exec_())

Kyrym
Понял я, в чём была моя ошибка. Я thread пытался запустить из класса гуи.
Да ХЗ , оно также запускается из класса ГУИ.
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