使用QProcess使用PyQt

时间:2017-02-19 14:55:17

标签: python python-3.x pyqt pyqt5 qprocess

我需要一个非阻塞GUI 解决方案来运行一个未定义数量的系统命令(比如将一些参数作为输入的bash脚本), monitor < / strong>他们的状态。 (例如:跑步/完成)和终止(杀死)该过程。

一个例子可以是:

  1. 从列表中选择一个应用程序(QComboBox)

  2. 设置参数(QLineEdit)

  3. 运行它(QProcess)

  4. 当它运行时,追加:

    • 命令
    • 参数
    • 状态

    作为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()
    

    感谢Avaris在IRC上提供的帮助,我修复了将表中每一行连接到一个单独进程的主要问题。

    在对原始问题进行一些修改后,我已经清理了一些代码,并且我已经能够添加一个按钮来停止/终止进程。

    要完成此示例任务,我需要实施对所有活动流程的监控,并实时更新其状态&#34;&#34;在第4列的表格中(除了打印标准输出第3列)。

    我试着这样做:

    status_item.setText(str(process.ProcessState())))
    

    但是我无法让它发挥作用。

1 个答案:

答案 0 :(得分:3)

您必须使用 <table:TreeTable id="idTreeTable" width="100%" selectionMode="sap.ui.table.SelectionMode.None" enableColumnReordering="false" expandFirstLevel="false" > <table:columns> <table:Column lable="{i18n>columnDescription}" width="20rem"> <!--<Label text="{i18n>columnDescription}"/>--> <table:template> <Text text="{desc}"/> </table:template> </table:Column> <table:Column> <!--<Label text="{i18n>columnRequestId}"/>--> <table:template> <Text text="{nodeId}"/> </table:template> </table:Column> <table:Column> <!--<Label text="{i18n>columnProduct}"/>--> <table:template> <Text text="{product}"/> </table:template> </table:Column> <table:Column> <!--<Label text="{i18n>columnGrossWeight}"/>--> <table:template> <ObjectNumber number="{grossWeight}" unit="{weightUnit}"/> </table:template> </table:Column> <table:Column> <!--<Label text="{i18n>columnConsumedGrossWeight}"/>--> <table:template> <Input id="inputWeight" type="Number" value="{consumedGrossWeight}" enabled="{editEnable}"/> </table:template> </table:Column> </table:columns> </table:TreeTable> 信号:

stateChanged

截图:

enter image description here

enter image description here