- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个主要的 pyqt 程序需要运行带有参数的外部程序。我想使用 QDialog 作为一种状态监视器,它可以在外部程序执行时捕获它的标准输出,并将它们显示在 QDialog 内的文本框中。我有以下状态监视器代码:
class ProgressInfo(QtGui.QDialog):
def __init__(self, cmd, args, parent=None):
#super(self).__init__(parent)
QDialog.__init__(self)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.cmd = cmd
self.args = args
self.keepGoing = True
layout = QFormLayout()
layout.setContentsMargins(10, 10, 10, 10)
self.output = QtGui.QTextEdit()
layout.addRow(self.output)
layout.addRow(self.ui.buttonBox)
self.setLayout(layout)
self.ext_process = QtCore.QProcess(self)
#self.ext_process.waitForFinished(-1)
#self.ext_process.waitForStarted()
#self.ext_process.readyRead.connect(self.dataReady)
self.ext_process.started.connect(self.open)
self.ext_process.readyReadStandardOutput.connect(self.dataReady)
self.ext_process.finished.connect(self.onProcessFinished)
self.ext_process.start(self.cmd, self.args)
def dataReady(self):
cursor = self.output.textCursor()
cursor.movePosition(cursor.End)
cursor.insertText(str(self.ext_process.readAll()))
self.output.ensureCursorVisible()
def onProcessFinished(self):
cursor = self.output.textCursor()
cursor.movePosition(cursor.End)
#cursor.insertText(str(self.ext_process.readAll()))
cursor.insertText(str(self.ext_process.readAllStandardOutput()))
self.output.ensureCursorVisible()
然后我将使用以下命令实例化它:
prog='C:/Program Files (x86)/My Program/Execute.exe'
margs=['D:/Data/Input1.txt', 'D:/Data/Input2.txt']
status = ProgressInfo(prog, margs, self)
到目前为止,这还没有奏效。
问题 1:只有在我取消对 waitForFinished(-1) 行的注释后,外部程序才会运行。
问题2.QDialog框只是一闪而过,然后就消失了。
问题3.很明显,运行的程序没有突出显示。
最后,我整理的代码吸取了很多人的想法和教训,但我看了一下,好像只能在程序结束后才能打印出所有的standout,但我希望它能逐行显示程序在运行时将它们写出。
我的工具链:Python 64 位版本 2.7.5,我在 Windows 7 box 上开发
('Qt version:', '4.8.5')
('SIP version:', '4.14.7')
('PyQt version:', '4.10.2')
感谢您的帮助。
最佳答案
这里是一个例子,你可以如何做到这一点(我使用 QWidget
但你也可以使用 QDialog
或其他)。我不使用单独的线程,因为 UI 不需要交互。如果您想添加按钮等,那么您应该考虑使用 Qt 提供的运行 QObject
模型的旧式 QThread
。
#!/usr/bin/python
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class MyQProcess(QWidget):
def __init__(self):
super(QWidget, self).__init__()
# Add the UI components (here we use a QTextEdit to display the stdout from the process)
layout = QVBoxLayout()
self.edit = QTextEdit()
self.edit.setWindowTitle("QTextEdit Standard Output Redirection")
layout.addWidget(self.edit)
self.setLayout(layout)
# Add the process and start it
self.process = QProcess()
self.setupProcess()
# Show the widget
self.show()
def setupProcess(self):
# Set the channels
self.process.setProcessChannelMode(QProcess.MergedChannels)
# Connect the signal readyReadStandardOutput to the slot of the widget
self.process.readyReadStandardOutput.connect(self.readStdOutput)
# Run the process with a given command
self.process.start("df -h")
def __del__(self):
# If QApplication is closed attempt to kill the process
self.process.terminate()
# Wait for Xms and then elevate the situation to terminate
if not self.process.waitForFinished(10000):
self.process.kill()
@pyqtSlot()
def readStdOutput(self):
# Every time the process has something to output we attach it to the QTextEdit
self.edit.append(QString(self.process.readAllStandardOutput()))
def main():
app = QApplication(sys.argv)
w = MyQProcess()
return app.exec_()
if __name__ == '__main__':
main()
请注意,我正在使用的命令 (df -h
) 运行一次(这是一个 Linux 命令,显示硬盘驱动器上的磁盘使用情况)然后就结束了。您也可以将其替换为可以无限期运行的 Execute.exe
。我已经使用 htop
(基于终端的高级任务管理器)对其进行了测试,它一旦启动就不会停止,除非用户希望它停止或系统停止(崩溃、关机等)。
请注意,您必须确保以干净的方式停止外部进程。这可以在 __del__
(析构函数)或在给定小部件生命周期结束时调用的另一个函数中完成。我所做的基本上是向外部进程发送一个 SIGTERM
(terminate
),一旦经过了给定的时间但进程仍在运行,我会提升情况到 SIGKILL
(kill
)。
代码显然需要更多的工作,但它应该足以让您了解事情是如何工作的。
这里是上面代码的相同版本,但有一个额外的线程。请注意,我将外部进程的输出重定向到我的工作程序中的一个插槽。除非您想处理该输出,否则您不必这样做。所以你可以跳过这个并将你的过程信号连接到你的小部件中接收它并输出其内容的插槽。输出的处理将在单独的线程中再次完成,因此您可以继续进行而不是卡住您的 UI(如果您遵循
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class Worker(QObject):
sendOutput = pyqtSignal(QString)
def __init__(self):
super(Worker, self).__init__()
self.process = QProcess()
self.setupProcess()
def __del__(self):
self.process.terminate()
if not self.process.waitForFinished(10000):
self.process.kill()
def setupProcess(self):
self.process.setProcessChannelMode(QProcess.MergedChannels)
self.process.readyReadStandardOutput.connect(self.readStdOutput)
self.process.start("htop")
@pyqtSlot()
def readStdOutput(self):
output = QString(self.process.readAllStandardOutput())
# Do some extra processing of the output here if required
# ...
self.sendOutput.emit(output)
class MyQProcess(QWidget):
def __init__(self):
super(QWidget, self).__init__()
layout = QVBoxLayout()
self.edit = QTextEdit()
self.thread = QThread()
self.setupConnections()
self.edit.setWindowTitle("QTextEdit Standard Output Redirection")
layout.addWidget(self.edit)
self.setLayout(layout)
self.show()
def setupConnections(self):
self.worker = Worker()
self.thread.finished.connect(self.worker.deleteLater)
self.worker.sendOutput.connect(self.showOutput)
self.worker.moveToThread(self.thread)
self.thread.start()
def __del__(self):
if self.thread.isRunning():
self.thread.quit()
# Do some extra checking if thread has finished or not here if you want to
#Define Slot Here
@pyqtSlot(QString)
def showOutput(self, output):
#self.edit.clear()
self.edit.append(output)
def main():
app = QApplication(sys.argv)
w = MyQProcess()
return app.exec_()
if __name__ == '__main__':
main()
进一步说明:正如我在他的回答的评论部分告诉@BrendanAbel 的那样,将插槽与 QThread
一起使用的问题是插槽具有与 相同的线程亲和性(=它们所属的线程) QThread
实例本身,它与创建 QThread
的线程相同。唯一 - 我重复 唯一 - 当涉及到 QThread
时,它在单独的线程中运行的是它的事件循环,由 QThread.run()
。如果你在 Internet 上查看,你会发现这种做事方式是不鼓励的(除非你真的、真的知道你必须子类化 QThread
)因为自 Qt 4 的早期版本以来run()
是抽象的,您必须继承 QThread
才能使用 QThread
。后来抽象 run()
得到了一个具体的实现,因此子类化 QThread
的需要被移除了。关于线程安全和信号,@BrendanAbel 所写的只是部分正确。它归结为连接类型(默认为 AutoConnection
)。如果您手动指定连接类型,您实际上可能会使信号成为线程不安全的。在 Qt documentation 中阅读更多相关信息.
关于python - 从用作进度监视器的 QDialog 中启动 QProcess,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35494083/
第一次在stackoverflow上提问。而且我是一个中国女孩,如果我对这个问题的描述有太多的语法错误,以至于你不能轻易理解,我很抱歉。下面是我的问题:头文件: class AdbDriver : p
我正在使用 QProcess 来运行其他程序。但是当我在调用 QProcess.start() 后退出我的应用程序时,它在调试控制台中说: QProcess: Destroyed while proc
我想运行一个 qprocess(程序 adb),当该过程完成时将结果返回给调用函数。但是,adb 很有可能会发现自己陷入循环,将诸如“ADB 服务器未确认”之类的错误消息打印到标准输出,而永远不会完成
我有一个 PyQt5 GUI 应用程序,想要执行外部程序并在 QTextEdit 小部件上显示外部程序的 stdout、stderr 和 stdin。我已经设法对标准输出和标准错误执行此操作。我需要有
Qt 文档给出了这样的解释: QProcess::开始: Starts the given program in a new process, if none is already running,
我阅读了一些文档,但对我来说还不够清楚。我知道“结束”进程和 kill() 都是为了强制它结束,但是 terminate() 应该做什么呢? 最佳答案 不知道你有没有写清楚: void QProces
我正在尝试将序列化图像传递到我在 Qt 程序中启动的进程。但是,这样做时我收到此错误消息: QObject::connect: Cannot queue arguments of type 'QPro
平台:Windows10我使用 QProcess::start 执行 Python 文件(在同一个目录中),但是我 无法从 readAllStandardOutput 函数获取结果。 Python文件
我有以下代码: proc = new QProcess(); proc->startDetached("C:\\ffmpeg.exe", QStringList() <<"-i"<< "C:\\pic
平台:Qt 4.8.2,Win 7 请考虑以下逻辑流程: 1. App started 2. functionA() triggered 3. the app periodically capture
A 在尝试阻止我的 QProcess 时遇到问题在它的父析构函数中。这是我的代码: AbstractProcess::~AbstractProcess() { if((m_process->s
我有一个必须暂停和恢复的 QProcess。我用 kill(pid_t(process->pid()), SIGSTOP); 和 kill(pid_t(process->pid()), SIGCONT
我尝试实现 subprocess Popen blocking PyQt GUI 的建议但似乎 onFinished 函数永远不会被调用。 class MyApp(QtWidgets.QMainWin
我有以下使用 QProcess 运行可执行文件的代码。代码运行良好,新的可执行文件运行正常。 QString fileName = ui.textBrowser_csvFile->toPlainTex
我想创建一个 QProcess 并在后台运行它。我有一个调度程序,它维护要作为 QProcesses 启动的作业队列。这些 QProcess 具有在 lsf 机器中运行的命令。要求是,一旦 QProc
我只是想通过以下源代码用 QProcess 创建一个文件: void Processmethod() { QDialog *ProcessMessage = new QDialog;
我正尝试在 QProcess 下的 Raspberry Pi (Raspbian) 中启动 CEC 命令。 如果我在我的 shell 中执行这个: echo 'standby 0' | cec-cli
一段时间以来,我一直在努力解决这个基本问题。我正在尝试从一个线程启动一个 QProcess。启动进程工作正常并且进程运行正常,但我的问题是 finished() 信号永远不会发出。 这是我的例子: 我
在我的 Qt C++ 程序中,我创建了一个进程,如下所示: myProcess = new QProcess(); myProcess->start(programpath, arguments);
出于某种原因,我无法在 Ubuntu 上使用 QProcess 启动进程,我不明白为什么... int main(int argc, char *argv[]) { //Run the pro
我是一名优秀的程序员,十分优秀!