Python Запуск внешних приложений с отображением ProgressBar
Помогите новичку. Уже долго мучаюсь, не могу найти решение...
Суть моего приложения, при выборе определенного Checkbox запускать выбранную программу, если выбираю несколько Checkbox, то запускается установка поочередно нескольких программ. Это у меня вроде бы получилось.
Вопрос: Как реализовать, чтобы при нажатии кнопки Установить, предварительно выбрав определенный Checkbox, открывалось новое дочернее окно с отслеживаемым процессом установки с помощью ProgressBar и отображением какая программа была установлена. Заранее спасибо!
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QAction, QMessageBox, QWidget, QMainWindow, QApplication
import subprocess
import threading
import time
import sys
class window_2(QWidget):
def __init__(self, parent=None):
super(window_2, self).__init__(parent)
self.w2 = window_2()
self.w2.resize(250, 300) #работает
self.w2.setWindowTitle('Прогресс бар')
self.w2.progressBar = QProgressBar(self)
self.w2.progressBar.setGeometry(0, 0, 300, 25)
self.w2.progressBar.setProperty("value", 0)
self.w2.progressBar.setMaximum(100)
self.w2.show()
class window(QMainWindow):
def __init__(self):
super().__init__()
def setupUi(self):
window.resize(330, 259)
quit = QAction("Quit", None )
quit.triggered.connect(self.closeEvent)
self.centralwidget = QtWidgets.QWidget(window)
self.centralwidget.setObjectName("centralwidget")
#Кнопка Установить
self.Btn1 = QtWidgets.QPushButton(self.centralwidget)
self.Btn1.setCheckable(False)
self.Btn1.toggle()
self.Btn1.setEnabled(False)
self.Btn1.clicked.connect(self.run)
self.Btn1.setGeometry(QtCore.QRect(60, 160, 121, 41))
self.Btn1.setObjectName("Btn1")
#Кнопка 1
self.checkBox1 = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox1.setGeometry(QtCore.QRect(70, 70, 101, 31))
self.checkBox1.setObjectName("checkBox1")
self.checkBox1.stateChanged.connect( self.btnstate)
#Кнопка 2
self.checkBox2 = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox2.setGeometry(QtCore.QRect(70, 110, 101, 31))
self.checkBox2.setObjectName("checkBox2")
self.checkBox2.stateChanged.connect( self.btnstate)
window.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(window)
self.statusbar.setObjectName("statusbar")
window.setStatusBar(self.statusbar)
self.retranslateUi(window)
QtCore.QMetaObject.connectSlotsByName(window)
def closeEvent(self, event):
close = QMessageBox()
close.setText("Вы уверены что хотите выйти из программы?")
close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
close.setWindowTitle("Завершение программы")
close = close.exec()
if close == QMessageBox.Yes:
event.accept()
else:
event.ignore()
self.setWindowTitle("Сборник программ")
def retranslateUi(self, window):
_translate = QtCore.QCoreApplication.translate
window.setWindowTitle(_translate("MainWindow", "Сборник программ офицера ОБИ"))
self.Btn1.setText(_translate("MainWindow", "Установить"))
self.checkBox1.setText(_translate("MainWindow", "Калькулятор"))
self.checkBox2.setText(_translate("MainWindow", "Paint"))
def btnstate(self):
if self.checkBox1.isChecked():
self.Btn1.setEnabled(True)
print("Выбран элемент для установки - Калькулятор")
if self.checkBox2.isChecked():
self.Btn1.setEnabled(True)
print("Выбран элемент для установки - Paint")
def start_in_thread(self, program):
Popen(program)
#time.sleep(10) # это для имитации долгой работы программы
print(f'Запуск программы {program} завершен')
def run(self, Btn):
self.w2 = window_2()
self.w2.setupUi()
startlist = []
if self.checkBox1.isChecked():
startlist = subprocess.Popen("C:/Windows/system32/calc.exe".split(),
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.stdout, self.stderr = startlist.communicate() #возврат
if self.checkBox2.isChecked():
startlist = subprocess.Popen("C:/Windows/system32/mspaint.exe".split(),
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.stdout, self.stderr = startlist.communicate()
for program in startlist:
t = threading.Thread(target=self.start_in_thread, args=[program])
t.start() # запуск программы в отдельном потоке
t.join() # ожидание окончания потока
main = QApplication(sys.argv)
window = window()
window.setupUi()
window.show()
sys.exit(main.exec_())
Ответы (1 шт):
Первое, что вы должны запомнить - НИКОГДА НЕ изменяйте модуль созданный в QT Designer. Создайте класс и наполните его тем что вы создали в QT Designer.
Вместо использования
subprocess.Popen()лучше использоватьQProcess, который является дружественным для графического интерфейса, поэтому нет необходимости использовать новый поток.
import sys
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtWidgets import QAction, QMessageBox, QWidget, QMainWindow, \
QApplication, QProgressBar, QVBoxLayout, QLabel
class Window_2(QWidget):
def __init__(self):
super().__init__()
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.setWindowTitle('Прогресс бар')
self.progressBar = QProgressBar(self)
self.progressBar.setProperty("value", 0)
self.progressBar.setMaximum(100)
self.label = QLabel()
layout = QVBoxLayout(self)
layout.addWidget(self.progressBar)
layout.addWidget(self.label)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.resize(330, 259)
quit = QAction("Quit", None )
quit.triggered.connect(self.closeEvent)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
#Кнопка Установить
self.Btn1 = QtWidgets.QPushButton(self.centralwidget)
self.Btn1.setCheckable(False)
self.Btn1.toggle()
self.Btn1.setEnabled(False)
self.Btn1.clicked.connect(self.run)
self.Btn1.setGeometry(QtCore.QRect(60, 160, 121, 41))
self.Btn1.setObjectName("Btn1")
#Кнопка 1
self.checkBox1 = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox1.setGeometry(QtCore.QRect(70, 70, 101, 31))
self.checkBox1.setObjectName("checkBox1")
self.checkBox1.stateChanged.connect( self.btnstate)
#Кнопка 2
self.checkBox2 = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox2.setGeometry(QtCore.QRect(70, 110, 101, 31))
self.checkBox2.setObjectName("checkBox2")
self.checkBox2.stateChanged.connect( self.btnstate)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Сборник программ офицера ОБИ"))
self.Btn1.setText(_translate("MainWindow", "Установить"))
self.checkBox1.setText(_translate("MainWindow", "Калькулятор"))
self.checkBox2.setText(_translate("MainWindow", "Paint"))
class Window(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.w2 = Window_2()
self._process_1 = QtCore.QProcess(self)
self._process_1.stateChanged.connect(self.new_State_1)
self._process_2 = QtCore.QProcess(self)
self._process_2.stateChanged.connect(self.new_State_2)
self.step = 0
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.update_values)
def update_values(self):
self.step += 1
self.w2.progressBar.setValue(self.step)
if self.checkBox1.isChecked() and \
not self.checkBox1.isChecked() and \
self._process_1.isOpen():
self.timer.stop()
elif not self.checkBox1.isChecked() and \
self.checkBox1.isChecked() and \
self._process_2.isOpen():
self.timer.stop()
else: self.timer.stop()
def new_State_1(self, newState):
if newState == 1:
text = f"Процесс запускается, но программа 'calc.exe' еще не запущена.\n"
elif newState == 2:
text = f"Процесс запущен и программа 'calc.exe' готова к работе.\n"
elif newState == 0:
text = f"Процесс 'calc.exe' не запущен.\n"
self.w2.label.setText(self.w2.label.text() + text)
def new_State_2(self, newState): # notepad
if newState == 1:
text = f"Процесс запускается, но программа 'notepad.exe' еще не запущена.\n"
elif newState == 2:
text = f"Процесс запущен и программа 'notepad.exe' готова к работе.\n"
elif newState == 0:
text = f"Процесс 'notepad.exe' не запущен.\n"
self.w2.label.setText(self.w2.label.text() + text)
def btnstate(self):
if not self.checkBox1.isChecked() and not self.checkBox2.isChecked():
self.Btn1.setEnabled(False)
return
if self.checkBox1.isChecked():
self.Btn1.setEnabled(True)
print("Выбран элемент для установки - Калькулятор")
if self.checkBox2.isChecked():
self.Btn1.setEnabled(True)
print("Выбран элемент для установки - Paint")
def run(self):
self.w2.label.clear()
self.step = 0
self.w2.progressBar.setValue(self.step)
self.w2.show()
self.timer.start(10)
if self.checkBox1.isChecked():
if self._process_1.state():
self.w2.label.setText(self.w2.label.text() + "Процесс 'calc.exe' уже запущен\n")
else:
self._process_1.start('calc.exe')
if self.checkBox2.isChecked():
if self._process_2.state():
self.w2.label.setText(self.w2.label.text() + "Процесс 'notepad.exe' уже запущен\n")
else:
self._process_2.start('notepad.exe')
def closeEvent(self, event):
close = QMessageBox()
close.setText("Вы уверены что хотите выйти из программы?")
close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
close.setWindowTitle("Завершение программы")
close = close.exec_()
if close == QMessageBox.Yes:
self._process_1.kill()
self._process_2.kill()
self.w2.close()
event.accept()
else:
event.ignore()
self.setWindowTitle("Сборник программ")
if __name__ == "__main__":
main = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(main.exec_())
