使用 QProcess 运行 并通过 PyQt 监控系统进程
Use of QProcess to run and monitor system processes with PyQt
我需要一个 非阻塞 GUI 解决方案来解决 运行 未定义数量的系统命令(比如 bash 将一些参数作为输入的脚本),监控它们的状态。 (例如:running/finished)和终止(杀死)进程。
一个例子可以是:
从列表中选择一个应用程序 (QComboBox)
设置一个参数(QLineEdit)
运行它(QProcess)
作为 运行s,追加:
- 命令
- 参数
- 状态
作为 QTableWidget 中的行
..我正在寻找一种解决方案来监视每个命令的状态。
应用程序可以是像这样的简单脚本:
class runcommands(QWidget):
def __init__(self, parent=None):
super(runcommands, self).__init__(parent)
layout = QFormLayout()
self.commandlist = QComboBox()
self.param = QLineEdit()
self.runit = QToolButton()
self.runit.setText('run')
self.runit.clicked.connect(self.runcommand)
self.commandlist.addItems(['simplerun.py', 'simplerun2.py'])
self.table = QTableWidget()
self.table.setColumnCount(5)
self.model = QStandardItemModel()
self.table.setHorizontalHeaderLabels(['Process', 'Parameter', 'STDOut', 'Status', 'Kill'])
self.rowcount = 0
layout.addRow(self.commandlist)
layout.addRow(self.param)
layout.addRow(self.runit)
layout.addRow(self.table)
self.setLayout(layout)
self.setWindowTitle("Run & Monitor")
self.commandrunning=0
self.mylistofprocesses=[]
def runcommand(self):
# add a record in the QTableWidget
# updating its row number at each run
self.rowcount = self.rowcount + 1
self.table.setRowCount(self.rowcount)
# add column 0: command string
self.c1 = QTableWidgetItem()
self.c1.setText("%s" % os.path.join(os.getcwd(), self.commandlist.currentText()))
self.table.setItem(self.rowcount - 1, 0, self.c1)
# add column 1: parameter string
self.c2 = QTableWidgetItem()
self.c2.setText("%s" % self.param.text())
self.table.setItem(self.rowcount - 1, 1, self.c2)
# add column 2 to store the Process StandardOutput
stdout_item = QTableWidgetItem()
self.table.setItem(self.rowcount - 1, 2, stdout_item)
# add column 3: index to store the process status (0: Not Running, 1: Starting, 2: Running)
status_item = QTableWidgetItem()
self.table.setItem(self.rowcount - 1, 3, status_item)
# add column 4: kill button to kill the relative process
killbtn = QPushButton(self.table)
killbtn.setText('Kill')
self.table.setCellWidget(self.rowcount - 1, 4, killbtn)
# Initiate a QProcess running a system command
process = QtCore.QProcess()
command = 'python3' + ' ' + os.getcwd() + '/' + self.commandlist.currentText() + ' ' + self.param.text()
process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
# connect the stdout_item to the Process StandardOutput
# it gets constantly update as the process emit std output
process.readyReadStandardOutput.connect(lambda: stdout_item.setText(str(process.readAllStandardOutput().data().decode('utf-8'))))
# start the process
process.start(command)
# this was supposed to add the process status in the relative column ... BUT it DOESN'T do it
status_item.setText(str(process.ProcessState()))
# connect the kill button to the process.kill method, to stop the process
killbtn.clicked.connect(process.kill)
killbtn.clicked.connect(lambda: killbtn.setText('Killed'))
# this was supposed to 'UPDATE' the process status (from running to stoppted) in the relative column ... BUT it DOESN'T do it
killbtn.clicked.connect(lambda: status_item.setText(str(process.ProcessState())))
# append the process to a list so that it doesn't get destroyed at each run
self.mylistofprocesses.append(process)
def main():
app = QApplication(sys.argv)
ex = runcommands()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
感谢 IRC 上 Avaris 的帮助,我解决了将 table 中的每一行连接到单独进程的主要问题。
在对原始问题进行一些编辑后,我稍微清理了代码,并且能够将 a 按钮添加到 stop/kill 进程。
要完成此示例任务,我需要实施对所有活动进程的监控,并在第 4 次 table 中更新它们的 status "in realtime"列(除了打印标准输出第 3 列)。
我尝试使用:
status_item.setText(str(process.ProcessState())))
但我无法让它工作。
您必须使用 stateChanged
信号:
[...]
self.mylistofprocesses.append(process)
status = {QProcess.NotRunning: "Not Running",
QProcess.Starting: "Starting",
QProcess.Running: "Running"}
process.stateChanged.connect(lambda state: status_item.setText(status[state]))
截图:
我需要一个 非阻塞 GUI 解决方案来解决 运行 未定义数量的系统命令(比如 bash 将一些参数作为输入的脚本),监控它们的状态。 (例如:running/finished)和终止(杀死)进程。
一个例子可以是:
从列表中选择一个应用程序 (QComboBox)
设置一个参数(QLineEdit)
运行它(QProcess)
作为 运行s,追加:
- 命令
- 参数
- 状态
作为 QTableWidget 中的行
..我正在寻找一种解决方案来监视每个命令的状态。
应用程序可以是像这样的简单脚本:
class runcommands(QWidget):
def __init__(self, parent=None):
super(runcommands, self).__init__(parent)
layout = QFormLayout()
self.commandlist = QComboBox()
self.param = QLineEdit()
self.runit = QToolButton()
self.runit.setText('run')
self.runit.clicked.connect(self.runcommand)
self.commandlist.addItems(['simplerun.py', 'simplerun2.py'])
self.table = QTableWidget()
self.table.setColumnCount(5)
self.model = QStandardItemModel()
self.table.setHorizontalHeaderLabels(['Process', 'Parameter', 'STDOut', 'Status', 'Kill'])
self.rowcount = 0
layout.addRow(self.commandlist)
layout.addRow(self.param)
layout.addRow(self.runit)
layout.addRow(self.table)
self.setLayout(layout)
self.setWindowTitle("Run & Monitor")
self.commandrunning=0
self.mylistofprocesses=[]
def runcommand(self):
# add a record in the QTableWidget
# updating its row number at each run
self.rowcount = self.rowcount + 1
self.table.setRowCount(self.rowcount)
# add column 0: command string
self.c1 = QTableWidgetItem()
self.c1.setText("%s" % os.path.join(os.getcwd(), self.commandlist.currentText()))
self.table.setItem(self.rowcount - 1, 0, self.c1)
# add column 1: parameter string
self.c2 = QTableWidgetItem()
self.c2.setText("%s" % self.param.text())
self.table.setItem(self.rowcount - 1, 1, self.c2)
# add column 2 to store the Process StandardOutput
stdout_item = QTableWidgetItem()
self.table.setItem(self.rowcount - 1, 2, stdout_item)
# add column 3: index to store the process status (0: Not Running, 1: Starting, 2: Running)
status_item = QTableWidgetItem()
self.table.setItem(self.rowcount - 1, 3, status_item)
# add column 4: kill button to kill the relative process
killbtn = QPushButton(self.table)
killbtn.setText('Kill')
self.table.setCellWidget(self.rowcount - 1, 4, killbtn)
# Initiate a QProcess running a system command
process = QtCore.QProcess()
command = 'python3' + ' ' + os.getcwd() + '/' + self.commandlist.currentText() + ' ' + self.param.text()
process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
# connect the stdout_item to the Process StandardOutput
# it gets constantly update as the process emit std output
process.readyReadStandardOutput.connect(lambda: stdout_item.setText(str(process.readAllStandardOutput().data().decode('utf-8'))))
# start the process
process.start(command)
# this was supposed to add the process status in the relative column ... BUT it DOESN'T do it
status_item.setText(str(process.ProcessState()))
# connect the kill button to the process.kill method, to stop the process
killbtn.clicked.connect(process.kill)
killbtn.clicked.connect(lambda: killbtn.setText('Killed'))
# this was supposed to 'UPDATE' the process status (from running to stoppted) in the relative column ... BUT it DOESN'T do it
killbtn.clicked.connect(lambda: status_item.setText(str(process.ProcessState())))
# append the process to a list so that it doesn't get destroyed at each run
self.mylistofprocesses.append(process)
def main():
app = QApplication(sys.argv)
ex = runcommands()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
感谢 IRC 上 Avaris 的帮助,我解决了将 table 中的每一行连接到单独进程的主要问题。
在对原始问题进行一些编辑后,我稍微清理了代码,并且能够将 a 按钮添加到 stop/kill 进程。
要完成此示例任务,我需要实施对所有活动进程的监控,并在第 4 次 table 中更新它们的 status "in realtime"列(除了打印标准输出第 3 列)。
我尝试使用:
status_item.setText(str(process.ProcessState())))
但我无法让它工作。
您必须使用 stateChanged
信号:
[...]
self.mylistofprocesses.append(process)
status = {QProcess.NotRunning: "Not Running",
QProcess.Starting: "Starting",
QProcess.Running: "Running"}
process.stateChanged.connect(lambda state: status_item.setText(status[state]))
截图: