如何使用子进程或 QProcess 启动独立的 gnuplot 进程?
How to start an independent gnuplot process with either subprocess or QProcess?
已经有很多关于 subprocess
和 QProcess
的问题和答案,但我还没有找到我的问题的答案。所以,如果我在这一堆部分令人困惑或过时的答案中没有找到答案,请原谅。
这听起来像是一项简单的任务:在 PyQt GUI 应用程序中,我想启动一个独立的(子)进程。
在我的例子中:gnuplot,一个绘图工具,带有选项“-p”(持久性,即在绘图完成后保持 window 打开)。一旦启动,它应该继续 运行 作为一个独立的(交互式)应用程序。
的文档
QProcess
and subprocess
没有进一步帮助我。
代码:(我的精简最小示例,没有按预期工作)
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QPushButton, QVBoxLayout
from PyQt5.QtCore import pyqtSlot, QProcess
import sys, subprocess
class App(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(0,0,700,500)
self.layout = QVBoxLayout()
self.pb_plot_1 = QPushButton("Plot via subprocess")
self.pb_plot_1.clicked.connect(self.on_click_pb_plot_1)
self.layout.addWidget(self.pb_plot_1)
self.pb_plot_2 = QPushButton("Plot via QProcess")
self.pb_plot_2.clicked.connect(self.on_click_pb_plot_2)
self.layout.addWidget(self.pb_plot_2)
self.pb_plot_3 = QPushButton("Plot via QProcess and loading a file")
self.pb_plot_3.clicked.connect(self.on_click_pb_plot_3)
self.layout.addWidget(self.pb_plot_3)
self.setLayout(self.layout)
self.show()
@pyqtSlot()
def get_plot_code(self):
return '''
# some gnuplot code, in reality much longer
set term wxt
plot sin(x)
'''
def on_click_pb_plot_1(self):
gnuplotPath = r'gnuplot\bin\gnuplot'
gnuplotCode = self.get_plot_code()
proc = subprocess.Popen([gnuplotPath, '-p'], stdin=subprocess.PIPE)
proc.communicate(gnuplotCode.encode())
def on_click_pb_plot_2(self):
gnuplotPath = r'gnuplot\bin\gnuplot'
gnuplotCode = self.get_plot_code()
proc = QProcess(self)
proc.start(gnuplotPath, ["-p"])
proc.write(gnuplotCode.encode())
def on_click_pb_plot_3(self):
gnuplotPath = r'gnuplot\bin\gnuplot'
gnuplotFile = 'gnuplotFile.gp'
proc = QProcess(self)
proc.start(gnuplotPath, ["-p", gnuplotFile])
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
结果:
如果我按下按钮,每次都会打开 gnuplot 并显示图表。到目前为止,好的。
然而,
通过子进程: gnuplot 将作为交互式工作 window,但我的 PyQt 应用程序将冻结(不响应)直到我关闭 gnuplot。
subprocess.Popen
似乎有选项 close_fds=True
,它应该可以做我想做的,但在 Windows 中,这似乎不能与通过 stdin=subprocess.PIPE
发送命令一起工作。
Note that on Windows, you cannot set close_fds to true and also
redirect the standard handles by setting stdin, stdout or stderr
那么,我还能用 subprocess
怎么做呢?添加 proc.terminate()
将无济于事。
通过 QProcess: gnuplot 将冻结并且不会作为交互式工作 window(无响应)。如果我杀死 gnuplot,我可以重新开始,但 gnuplot 再次会冻结。
我也尝试过 startDetached()
之类的...但没有成功...
我可以想象这个问题可以通过对代码进行微小的更改来解决。但我不知道如何改变。
所以,我确定这是我对文档的有限理解,而且我缺少合适的示例。
我的配置:Win10,Python3.6.3,PyQt 5.11.3
更新:(上面的代码已更改,添加了第三个变体)
通过 QProcess 并读取文件(而不是将代码写入 gnuplot)
a) gnuplot 将创建绘图,b) 不会冻结任何内容,c) gnuplot 保持交互,d) 我可以独立关闭我的应用程序或 gnuplot。
但是,我不想从磁盘读取 gnuplot 文件,但我想将代码发送到 gnuplot(我假设是 stdin
)。
更新二:
也许这可能是对可以解释这一点的人的提示。这似乎取决于 gnuplot 版本。以下结果:
5.2.0 QWindowsPipeWriter::write failed. (The handle is invalid.)
5.2.2 QWindowsPipeWriter::write failed. (The handle is invalid.)
5.2.3 QWindowsPipeWriter::write failed. (The handle is invalid.)
5.2.4 QWindowsPipeWriter::write failed. (The handle is invalid.)
5.2.5 QWindowsPipeWriter::write failed. (The handle is invalid.)
5.2.6 works
5.2.7 works
5.2.8 works
5.4.0 freezing
5.4.1 freezing
好的,@eyllanesc 是对的...我将 PyQt5 从 5.11.3 更新到 5.15.4,问题似乎不再出现了。无论这是什么错误或不兼容......
已经有很多关于 subprocess
和 QProcess
的问题和答案,但我还没有找到我的问题的答案。所以,如果我在这一堆部分令人困惑或过时的答案中没有找到答案,请原谅。
这听起来像是一项简单的任务:在 PyQt GUI 应用程序中,我想启动一个独立的(子)进程。 在我的例子中:gnuplot,一个绘图工具,带有选项“-p”(持久性,即在绘图完成后保持 window 打开)。一旦启动,它应该继续 运行 作为一个独立的(交互式)应用程序。
的文档
QProcess
and subprocess
没有进一步帮助我。
代码:(我的精简最小示例,没有按预期工作)
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QPushButton, QVBoxLayout
from PyQt5.QtCore import pyqtSlot, QProcess
import sys, subprocess
class App(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(0,0,700,500)
self.layout = QVBoxLayout()
self.pb_plot_1 = QPushButton("Plot via subprocess")
self.pb_plot_1.clicked.connect(self.on_click_pb_plot_1)
self.layout.addWidget(self.pb_plot_1)
self.pb_plot_2 = QPushButton("Plot via QProcess")
self.pb_plot_2.clicked.connect(self.on_click_pb_plot_2)
self.layout.addWidget(self.pb_plot_2)
self.pb_plot_3 = QPushButton("Plot via QProcess and loading a file")
self.pb_plot_3.clicked.connect(self.on_click_pb_plot_3)
self.layout.addWidget(self.pb_plot_3)
self.setLayout(self.layout)
self.show()
@pyqtSlot()
def get_plot_code(self):
return '''
# some gnuplot code, in reality much longer
set term wxt
plot sin(x)
'''
def on_click_pb_plot_1(self):
gnuplotPath = r'gnuplot\bin\gnuplot'
gnuplotCode = self.get_plot_code()
proc = subprocess.Popen([gnuplotPath, '-p'], stdin=subprocess.PIPE)
proc.communicate(gnuplotCode.encode())
def on_click_pb_plot_2(self):
gnuplotPath = r'gnuplot\bin\gnuplot'
gnuplotCode = self.get_plot_code()
proc = QProcess(self)
proc.start(gnuplotPath, ["-p"])
proc.write(gnuplotCode.encode())
def on_click_pb_plot_3(self):
gnuplotPath = r'gnuplot\bin\gnuplot'
gnuplotFile = 'gnuplotFile.gp'
proc = QProcess(self)
proc.start(gnuplotPath, ["-p", gnuplotFile])
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
结果:
如果我按下按钮,每次都会打开 gnuplot 并显示图表。到目前为止,好的。 然而,
通过子进程: gnuplot 将作为交互式工作 window,但我的 PyQt 应用程序将冻结(不响应)直到我关闭 gnuplot。
subprocess.Popen
似乎有选项 close_fds=True
,它应该可以做我想做的,但在 Windows 中,这似乎不能与通过 stdin=subprocess.PIPE
发送命令一起工作。
Note that on Windows, you cannot set close_fds to true and also redirect the standard handles by setting stdin, stdout or stderr
那么,我还能用 subprocess
怎么做呢?添加 proc.terminate()
将无济于事。
通过 QProcess: gnuplot 将冻结并且不会作为交互式工作 window(无响应)。如果我杀死 gnuplot,我可以重新开始,但 gnuplot 再次会冻结。
我也尝试过 startDetached()
之类的...但没有成功...
我可以想象这个问题可以通过对代码进行微小的更改来解决。但我不知道如何改变。 所以,我确定这是我对文档的有限理解,而且我缺少合适的示例。 我的配置:Win10,Python3.6.3,PyQt 5.11.3
更新:(上面的代码已更改,添加了第三个变体)
通过 QProcess 并读取文件(而不是将代码写入 gnuplot)
a) gnuplot 将创建绘图,b) 不会冻结任何内容,c) gnuplot 保持交互,d) 我可以独立关闭我的应用程序或 gnuplot。
但是,我不想从磁盘读取 gnuplot 文件,但我想将代码发送到 gnuplot(我假设是 stdin
)。
更新二:
也许这可能是对可以解释这一点的人的提示。这似乎取决于 gnuplot 版本。以下结果:
5.2.0 QWindowsPipeWriter::write failed. (The handle is invalid.)
5.2.2 QWindowsPipeWriter::write failed. (The handle is invalid.)
5.2.3 QWindowsPipeWriter::write failed. (The handle is invalid.)
5.2.4 QWindowsPipeWriter::write failed. (The handle is invalid.)
5.2.5 QWindowsPipeWriter::write failed. (The handle is invalid.)
5.2.6 works
5.2.7 works
5.2.8 works
5.4.0 freezing
5.4.1 freezing
好的,@eyllanesc 是对的...我将 PyQt5 从 5.11.3 更新到 5.15.4,问题似乎不再出现了。无论这是什么错误或不兼容......