Остановка потоков QThread, передача текста в QTextEdit и работа QProgressBar
Снова прошу помощи с потоками. Есть несколько проблем.
- Нужно инициализировать кнопку "СТОП", при клике на которую потоки должны фактически останавливаться (т.е. thread_1 и thread_2), предварительно выдавать диалоговое окно (Вы уверены, что хотите прервать выполнение программы? ОК - прерываем, Отмена - продолжаем), без блокирования основного окна и всех работающих потоков, т.е. сканирование должно продолжаться вплоть до нажатия кнопки ОК)
- При передаче сообщений из scanclass в функцию обработки message_handler, должны эти самые сообщения печататься .append("text") в QTextEdit каждого из потоков (для 1 потока это textEdit_plate_1, для второго это textEdit_plate_2 соответственно). Фактически функция "message_handler" не работает.
- При передаче сообщения, пользователь должен видеть как заполняет QStatusBar каждого из потоков (примерно 33 сообщения должно высыпаться т.е. для каждого сообщения шаг СтатусБара должен быть равен ~3,03)
- После того, как оба потока получили в переменной date_command - STOP, т.е. фактически отправка команд для работы с портом закончена, должно высыпаться окно dialog_adress, в котором пользователь вводит своё местоположение и местоположение должно передаваться в другой py файл, после нажатия кнопки ОК, должен запускаться py файл, в который ушла переменная со значением местоположения.
main.py
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QMainWindow
from reo_main_window import Ui_MainWindow
from dialog_adress import Ui_Form_dialog_adress
import scanclass
import serial
import serial.tools.list_ports
class Thread(QThread):
updateSignal = QtCore.pyqtSignal(object, str, str)
def __init__(self, plate, name_thread):
super().__init__()
self.number_port = plate
self.name_thread = name_thread
print(f'number_port = {self.number_port}; {self.name_thread}')
def run(self):
scan = scanclass.ScanningReo(
"serial_port", "date_from_cmd",
"date_command", "name_freq", "name_dev")
opn_srl_prt = scan.open_serial_port(self.number_port)
opn_srl_prt.close()
opn_srl_prt = scan.open_serial_port(self.number_port)
id_dev = scan.device_identification(opn_srl_prt)
print(id_dev)
if "120" in id_dev:
self.updateSignal.emit(id_dev, '120', self.name_thread)
date_command = [f'"AT^SYSCFGEX="03",1\r"',
f'"AT^SYSCFGEX="01",2\r"', "AT^NETSCAN=0\r",
f'"AT^SYSCFGEX="01",3\r"', "AT^NETSCAN=0\r",
f'"AT^SYSCFGEX="02",4\r"', "AT^NETSCAN=1\r",
f'"AT^SYSCFGEX="03",5\r"', "AT^NETSCAN=3\r",
"STOP"
]
elif "821" in id_dev:
self.updateSignal.emit(id_dev, '821', self.name_thread)
ddate_command = [f'"AT^SYSCFGEX="03",1\r"',
f'"AT^SYSCFGEX="01",2\r"', "AT^NETSCAN=0\r",
f'"AT^SYSCFGEX="01",3\r"', "AT^NETSCAN=0\r",
f'"AT^SYSCFGEX="02",4\r"', "AT^NETSCAN=1\r",
f'"AT^SYSCFGEX="03",5\r"', "AT^NETSCAN=3\r",
"STOP"
]
for i in date_command:
if "SYSCFGEX" in i:
i = i.strip('"')
self.msleep(1000 * 2) # 2 сек.
while scan.send_comm(opn_srl_prt, i) == "STOP":
Thread.message_handler(self, id_dev, msg=date_command)
self.msleep(1000 * 2) # 2 сек.
if scan.send_comm(opn_srl_prt, i) == "STOP":
Thread.message_handler(self, id_dev, msg="Сканирование завершено")
def message_handler(self, id_dev, msg):
""" Функция "message_handler" обрабатывает поступающие сообщения
и выводит их в ui.textEdit
"""
if "120" in id_dev:
if "AT^NETSCAN=20,-110,0" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 2!", self.name_thread)
if "AT^NETSCAN=20,-110,1" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 3!", self.name_thread)
if "AT^NETSCAN=20,-110,3" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 4!", self.name_thread)
if "Начат" or "Закончен" in msg:
self.updateSignal.emit(
id_dev, f"{msg}", self.name_thread)
if "821" in id_dev:
if "AT^NETSCAN=20,-110,0" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 2!", self.name_thread)
if "AT^NETSCAN=20,-110,1" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 3!", self.name_thread)
if "AT^NETSCAN=20,-110,3" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 4!", self.name_thread)
if "Начат" or "Закончен" in msg:
self.updateSignal.emit(
id_dev, f"{msg}", self.name_thread)
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.pushButton_start.clicked.connect(self.run_th)
self.pushButton_stop.clicked.connect(self.stop_th)
def run_th(self):
""" Функция "run_th" запускает потоки с экземплярами класса """
device_port = self.scan_ttyusb()
plate1 = device_port[0] # scan_ttyusb()[0]
plate2 = device_port[1] # scan_ttyusb()[1]
self.thread_1 = Thread(plate1, 'Plate 1')
self.thread_1.updateSignal.connect(self.update_thread)
self.thread_1.start()
self.thread_2 = Thread(plate2, 'Plate 2')
self.thread_2.updateSignal.connect(self.update_thread)
self.thread_2.start()
def stop_th(self):
self.thread_1.finished
self.thread_2.finished
def update_thread(self, id_dev, plate, name_thread):
if name_thread == 'Plate 1':
if '821' in plate:
self.label_plate_1.setText(f"{id_dev}")
else:
self.label_plate_1.setText(f"{id_dev}")
if name_thread == 'Plate 2':
if '120' in plate:
self.label_plate_2.setText(f"{id_dev}")
else:
self.label_plate_2.setText(f"{id_dev}")
def scan_ttyusb(self):
""" Функция "scan_ttyusb" сканирует порты и возвращает номера портов
к которым подключены нужные устройства
"""
ports = list(serial.tools.list_ports.comports())
result = ""
for text in ports:
if 'Pcui' in text[1]:
txt = text[0]
result = result + txt + ','
device_port = result
return device_port.split(",")
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
main_window = MainWindow()
main_window.setFixedSize(680, 572)
# main_window.resize(680, 572)
main_window.show()
# # Создание формы диалога внесения адреса и инициализация uid dialog_adress
# dialog = QtWidgets.QWidget()
# uid = Ui_Form_dialog_adress()
# uid.setupUi(dialog)
# dialog.show()
# dialog.setFixedSize(440, 161)
sys.exit(app.exec_())
Вот часть кода scanclass.py:
class ScanningReo:
def __init__(self, serial_port, date_from_cmd, date_command, name_freq, name_dev):
self.serial_port = serial_port
self.date_from_cmd = date_from_cmd
self.date_command = date_command
self.name_freq = name_freq
self.name_dev = name_dev
def send_comm(self, serial_port, date_command):
print(date_command)
if "NETSCAN" in str(date_command):
time.sleep(2)
result = ""
for i in range(3): # количество проходов от 0 до 2
serial_port.write(date_command.encode())
state_cycle = True
print(f"Начат круг № '{i+1}'") #Эти сообщения дожны сыпаться в QtextEdit каждого из потоков.
prev_comm = ''
start_cycle = time.time()
while state_cycle:
# main3.Thread.message_handler(id_dev=self.name_dev, msg=f"Начат круг № '{i + 1}'")
....
....
....
print(f"Закончен проход № '{i+1}'")
# main2.message_handler(msg=f"Закончен круг № '{i + 1}'", id_dev=self.name_dev)
С предыдущими проблемами, мне помог пользовать @S. Nick, за что ему выражаю отдельную огромную благодарность.
Ответы (1 шт):
Автор решения: S. Nick
→ Ссылка
Ваш вопрос должен касаться ОДНОЙ проблемы.
Я попробую предложить вам один из возможных вариантов, который должен вам помочь в решении ПЕРВОЙ вашей проблемы. Помните, что я не могу проверить работу вашего приложения.
main.py
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.Qt import *
from reo_main_window import Ui_MainWindow
from dialog_adress import Ui_Form_dialog_adress
# !
from scanclass import ScanningReo # !
import serial
import serial.tools.list_ports
class Thread(QThread):
updateSignal = QtCore.pyqtSignal(object, str, str)
def __init__(self, plate, name_thread):
super().__init__()
self.number_port = plate
self.name_thread = name_thread
print(f'number_port = {self.number_port}; {self.name_thread}')
def run(self):
# !
scan = ScanningReo( # !
"serial_port", "date_from_cmd",
"date_command", "name_freq", "name_dev")
opn_srl_prt = scan.open_serial_port(self.number_port)
opn_srl_prt.close()
opn_srl_prt = scan.open_serial_port(self.number_port)
id_dev = scan.device_identification(opn_srl_prt)
print(id_dev)
if "120" in id_dev:
self.updateSignal.emit(id_dev, '120', self.name_thread)
date_command = [f'"AT^SYSCFGEX="03",1\r"',
f'"AT^SYSCFGEX="01",2\r"', "AT^NETSCAN=0\r",
f'"AT^SYSCFGEX="01",3\r"', "AT^NETSCAN=0\r",
f'"AT^SYSCFGEX="02",4\r"', "AT^NETSCAN=1\r",
f'"AT^SYSCFGEX="03",5\r"', "AT^NETSCAN=3\r",
"STOP"
]
elif "821" in id_dev:
self.updateSignal.emit(id_dev, '821', self.name_thread)
ddate_command = [f'"AT^SYSCFGEX="03",1\r"',
f'"AT^SYSCFGEX="01",2\r"', "AT^NETSCAN=0\r",
f'"AT^SYSCFGEX="01",3\r"', "AT^NETSCAN=0\r",
f'"AT^SYSCFGEX="02",4\r"', "AT^NETSCAN=1\r",
f'"AT^SYSCFGEX="03",5\r"', "AT^NETSCAN=3\r",
"STOP"
]
for i in date_command:
if "SYSCFGEX" in i:
i = i.strip('"')
self.msleep(1000 * 2) # 2 сек.
while scan.send_comm(opn_srl_prt, i) == "STOP":
Thread.message_handler(self, id_dev, msg=date_command)
self.msleep(1000 * 2) # 2 сек.
if scan.send_comm(opn_srl_prt, i) == "STOP":
Thread.message_handler(self, id_dev, msg="Сканирование завершено")
def message_handler(self, id_dev, msg):
""" Функция "message_handler" обрабатывает поступающие сообщения
и выводит их в ui.textEdit
"""
if "120" in id_dev:
if "AT^NETSCAN=20,-110,0" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 2G", self.name_thread)
if "AT^NETSCAN=20,-110,1" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 3G", self.name_thread)
if "AT^NETSCAN=20,-110,3" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 4G", self.name_thread)
if "Начат" or "Закончен" in msg:
self.updateSignal.emit(
id_dev, f"{msg}", self.name_thread)
if "821" in id_dev:
if "AT^NETSCAN=20,-110,0" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 2G", self.name_thread)
if "AT^NETSCAN=20,-110,1" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 3G", self.name_thread)
if "AT^NETSCAN=20,-110,3" in msg:
self.updateSignal.emit(
id_dev, "Начинаю сканирование 4G", self.name_thread)
if "Начат" or "Закончен" in msg:
self.updateSignal.emit(
id_dev, f"{msg}", self.name_thread)
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
# +++
self.thread_1 = None # +++
self.thread_2 = None # +++
self.pushButton_start.clicked.connect(self.run_th)
#- self.pushButton_stop.clicked.connect(self.stop_th)
def run_th(self):
""" Функция "run_th" запускает потоки с экземплярами класса """
device_port = self.scan_ttyusb()
plate1 = device_port[0]
plate2 = device_port[1]
# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
if self.thread_1 is None and self.thread_2 is None:
self.thread_1 = Thread(plate1, 'Plate 1')
self.thread_1.updateSignal.connect(self.update_thread)
self.thread_1.start()
self.thread_2 = Thread(plate2, 'Plate 2')
self.thread_2.updateSignal.connect(self.update_thread)
self.thread_2.start()
self.pushButton_start.setText("Stop Thread`s")
else:
reply = QMessageBox.question(
self,
'ВНИМАНИЕ !',
"Вы уверены, что хотите прервать выполнение программы?",
QMessageBox.Yes, QMessageBox.No
)
if reply == QMessageBox.Yes:
self.thread_1.terminate()
self.thread_1 = None
self.thread_2.terminate()
self.thread_2 = None
self.pushButton_start.setText("Start Thread`s")
#
# def stop_th(self):
# self.thread_1.finished
# self.thread_2.finished
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
def update_thread(self, id_dev, plate, name_thread):
if name_thread == 'Plate 1':
if '821' in plate:
self.label_plate_1.setText(f"{id_dev}")
else:
self.label_plate_1.setText(f"{id_dev}")
if name_thread == 'Plate 2':
if '120' in plate:
self.label_plate_2.setText(f"{id_dev}")
else:
self.label_plate_2.setText(f"{id_dev}")
def scan_ttyusb(self):
""" Функция "scan_ttyusb" сканирует порты и возвращает номера портов
к которым подключены нужные устройства
"""
ports = list(serial.tools.list_ports.comports())
result = ""
for text in ports:
if 'Pcui' in text[1]:
txt = text[0]
result = result + txt + ','
device_port = result
return device_port.split(",")
# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
def closeEvent(self, event):
reply = QMessageBox.question(
self,
'Информация',
"Вы уверены, что хотите закрыть приложение?",
QMessageBox.Yes, QMessageBox.No
)
if reply == QMessageBox.Yes:
if self.thread_1:
self.thread_1.quit()
del self.thread_1
if self.thread_2:
self.thread_2.quit()
del self.thread_2
super(MainWindow, self).closeEvent(event)
else:
event.ignore()
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
main_window = MainWindow()
main_window.setFixedSize(680, 572)
main_window.show()
sys.exit(app.exec_())
Если у вас есть другие проблемы - задайте НОВЫЙ вопрос.