Уведомления

Группа в Telegram: @pythonsu
  • Начало
  • » GUI
  • » PyQt4 | Запуск GUI и функции в отдельном потоке (_thread) [RSS Feed]

#1 Июль 19, 2017 22:32:43

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)

Вот работающий код с двумя потоками:

 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 - это фиктивная мультипоточность?

Отредактировано Kyrym (Июль 19, 2017 22:44:15)

Офлайн

#2 Июль 20, 2017 09:45:40

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)

не удалось повторить вашу проблему

 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! и время



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Офлайн

#3 Июль 20, 2017 19:36:48

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)

Понял я, в чём была моя ошибка. Я thread пытался запустить из класса гуи.

Офлайн

#4 Июль 20, 2017 20:18:23

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)

Эм… А как правильно сослаться из внешней функции на поле 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_())


Офлайн

#5 Июль 20, 2017 20:44:40

vic57
Зарегистрирован: 2015-07-07
Сообщения: 893
Репутация: +  126  -
Профиль   Отправить e-mail  

PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)

а почему не QTimer?

Офлайн

#6 Июль 20, 2017 20:48:46

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)

vic57
а почему не QTimer?
ой, ну что знаю, то и использую

Офлайн

#7 Июль 20, 2017 21:05:46

vic57
Зарегистрирован: 2015-07-07
Сообщения: 893
Репутация: +  126  -
Профиль   Отправить e-mail  

PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)

давно уже все задокументировано
https://github.com/Werkov/PyQt4/blob/master/examples/widgets/digitalclock.py

Отредактировано vic57 (Июль 20, 2017 21:07:10)

Офлайн

#8 Июль 20, 2017 22:23:16

Kyrym
Зарегистрирован: 2016-12-28
Сообщения: 225
Репутация: +  3  -
Профиль   Отправить e-mail  

PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)

vic57, спасибо, конечно, но мой вопрос не в том, как время выводить.

Офлайн

#9 Июль 20, 2017 22:25:15

vic57
Зарегистрирован: 2015-07-07
Сообщения: 893
Репутация: +  126  -
Профиль   Отправить e-mail  

PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)

фишка в таймауте

Офлайн

#10 Июль 21, 2017 10:22:48

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 2196
Репутация: +  294  -
Профиль   Отправить e-mail  

PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)

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 пытался запустить из класса гуи.
Да ХЗ , оно также запускается из класса ГУИ.



==============================
Помещайте код в теги:
[code python][/code]
Бериегите свое и чужое время.

Отредактировано PEHDOM (Июль 21, 2017 10:30:31)

Офлайн

  • Начало
  • » GUI
  • » PyQt4 | Запуск GUI и функции в отдельном потоке (_thread)[RSS Feed]

Board footer

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

Powered by DjangoBB

Lo-Fi Version