如何向QProcess path环境变量添加路径?(python3.7上的PyQt5)

2024-09-19 23:42:55 发布

您现在位置:Python中文网/ 问答频道 /正文

1。问题已解释

我在应用程序显示主窗口之前实例化了一个QProcess()-对象。QProcess()-实例存储在self.__myProcess变量中,只要能看到主窗口,它就会一直保持活动状态。在

主窗口如下所示:

enter image description here

单击按钮时,将执行以下代码:

def __btn_clicked(self):
    self.__add_openocd_to_env()
    command = "openocd.exe" + '\r\n'
    self.__myProcess.start(command)

最后两行非常清楚:命令openocd.exe被传递到self.__myProcess并执行。 这个可执行文件的实际功能在这里并不重要。事实上,我可以使用任何随机可执行文件。关键是:如果可执行文件在我的Windows PATH环境变量中,它就会被找到并执行。在

假设可执行文件不在PATH环境变量中。那么函数self.__add_openocd_to_env()应该可以解决这个问题:

^{pr2}$

不过,我注意到它一点效果都没有。我在这个函数中尝试了很多不同的方法,但都没有任何效果。在


您可以在这里找到完整的代码:
如果PyQt5安装了Python3,只需将代码复制粘贴到.py模块中并运行它。你应该看到那个有按钮的小窗口。“你的计算机上的有效路径应该改为”你的计算机“。您可以为此测试选择任何可执行文件。

import sys
import os
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class CustomMainWindow(QMainWindow):
    def __init__(self):
        super(CustomMainWindow, self).__init__()
        # -------------------------------- #
        #          QProcess() setup        #
        # -------------------------------- #
        self.__myProcess = QProcess()
        self.__myProcess.setProcessChannelMode(QProcess.MergedChannels)
        self.__myProcess.readyRead.connect(self.__on_output)
        self.__myProcess.errorOccurred.connect(self.__on_error)
        self.__myProcess.finished.connect(self.__on_exit)

        # -------------------------------- #
        #           Window setup           #
        # -------------------------------- #
        self.setGeometry(100, 100, 800, 200)
        self.setWindowTitle("QProcess test")

        self.__frm = QFrame(self)
        self.__frm.setStyleSheet("QWidget { background-color: #ffffff }")
        self.__lyt = QVBoxLayout()
        self.__lyt.setAlignment(Qt.AlignTop)
        self.__frm.setLayout(self.__lyt)
        self.setCentralWidget(self.__frm)

        self.__myBtn = QPushButton("START QPROCESS()")
        self.__myBtn.clicked.connect(self.__btn_clicked)
        self.__myBtn.setFixedHeight(70)
        self.__myBtn.setFixedWidth(200)
        self.__lyt.addWidget(self.__myBtn)
        self.show()

    def __add_openocd_to_env(self):
        env = self.__myProcess.processEnvironment()
        env.insert("PATH", "C:\\Users\\Kristof\\programs\\openocd_0.10.0\\bin;" + env.value("PATH"))
        self.__myProcess.setProcessEnvironment(env)

    def __btn_clicked(self):
        self.__add_openocd_to_env()
        command = "openocd.exe" + '\r\n'
        self.__myProcess.start(command)

    def __on_output(self):
        data = bytes(self.__myProcess.readAll()).decode().replace('\r\n', '\n')
        print(data)

    def __on_error(self, error):
        print("")
        print("Process error: {0}".format(str(error)))
        print("")


    def __on_exit(self, exitCode, exitStatus):
        print("")
        print("ExitCode = {0}".format(str(exitCode)))
        print("ExitStatus = {0}".format(str(exitStatus)))
        print("")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    QApplication.setStyle(QStyleFactory.create('Fusion'))
    myGUI = CustomMainWindow()
    sys.exit(app.exec_())


2。我的问题

我知道在实例化QProcess()之前,我可以简单地将“C:\Users\Kristof\programs\openocd_.10.0\bin”添加到我的Windows PATH环境变量中。但这不是重点。{{cd6>想知道如何添加环境变量。如果可能,它不应该影响我的软件中的任何其他QProcess()-实例,也不应该影响我以后创建的任何QProcess()-实例。在

3。系统设置

我在Windows10上使用Python3.7中的PyQt5框架。在


注意:
我刚刚尝试通过以下方式改进QProcess()设置:

        # -------------------------------- #
        #          QProcess() setup        #
        # -------------------------------- #
        self.__myProcess = QProcess()
        self.__myProcess.setProcessChannelMode(QProcess.MergedChannels)
        self.__myProcess.readyRead.connect(self.__on_output)
        self.__myProcess.errorOccurred.connect(self.__on_error)
        self.__myProcess.finished.connect(self.__on_exit)

        # NEW: initialize the environment variables for self.__myProcess:
        env = QProcessEnvironment.systemEnvironment()
        self.__myProcess.setProcessEnvironment(env)

我很有希望。。。但它仍然行不通:-(


Tags: path实例importselfenv可执行文件ondef
2条回答

有一个使用python的解决方案子流程.运行()而不是QProcess。在

在子流程.运行(),可以使用env参数指定一组环境变量(实际上是字典)。其思想是获取原始环境的副本,修改PATH变量,并将修改后的环境传递给子流程.运行,如下所示:

env = os.environ.copy()
env['PATH'] = "C:\\Users\\Kristof\\programs\\openocd_0.10.0\\bin" \
   + os.pathsep + env['PATH']
subprocess.run("openocd", env=env)

这仍然不起作用:剩下的问题是环境(包括修改后的PATH变量)将在子进程中可用,但不用于搜索openocd命令。但这很容易解决:子流程.运行还有一个boolean shell参数(默认为False),它告诉它在shell中运行命令。由于shell将在子进程中运行,它将使用修改后的路径来搜索openocd。所以工作代码是:

^{pr2}$

shell=True的另一种方法是使用舒蒂尔,哪个(在Python>;=3.3中可用)来解析该命令。当命令以字符串列表而不是单个字符串的形式给出时,这也将可靠地工作。在

env = os.environ.copy()
env['PATH'] = "C:\\Users\\Kristof\\programs\\openocd_0.10.0\\bin" \
   + os.pathsep + env['PATH']
command = shutil.which("openocd", path = self.env.get('PATH', None))
subprocess.run([ command ], env=env)

根据@JonBrave先生的评论,我写了以下解决方法:

import sys
import os
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class CustomMainWindow(QMainWindow):
    def __init__(self):
        super(CustomMainWindow, self).__init__()
        #                  #
        #          QProcess() setup        #
        #                  #
        self.__myProcess = QProcess()
        self.__myProcess.setProcessChannelMode(QProcess.MergedChannels)
        self.__myProcess.readyRead.connect(self.__on_output)
        self.__myProcess.errorOccurred.connect(self.__on_error)
        self.__myProcess.finished.connect(self.__on_exit)

        #                  #
        #           Window setup           #
        #                  #
        self.setGeometry(100, 100, 800, 200)
        self.setWindowTitle("QProcess test")

        self.__frm = QFrame(self)
        self.__frm.setStyleSheet("QWidget { background-color: #ffffff }")
        self.__lyt = QVBoxLayout()
        self.__lyt.setAlignment(Qt.AlignTop)
        self.__frm.setLayout(self.__lyt)
        self.setCentralWidget(self.__frm)

        self.__myBtn = QPushButton("START QPROCESS()")
        self.__myBtn.clicked.connect(self.__btn_clicked)
        self.__myBtn.setFixedHeight(70)
        self.__myBtn.setFixedWidth(200)
        self.__lyt.addWidget(self.__myBtn)
        self.show()

    def __add_openocd_to_env(self):
        self.__oldEnv = os.environ["PATH"]
        os.environ["PATH"] = "C:\\Users\\Kristof\\Dropbox (Personal)\\EMBEDOFFICE\\embedoffice\\resources\\programs\\openocd_0.10.0_dev00459\\bin;" + self.__oldEnv

    def __remove_openocd_from_env(self):
        os.environ["PATH"] = self.__oldEnv

    def __btn_clicked(self):
        self.__add_openocd_to_env()
        command = "openocd.exe" + '\r\n'
        self.__myProcess.start(command)
        self.__myProcess.waitForStarted(-1)
        self.__remove_openocd_from_env()

    def __on_output(self):
        data = bytes(self.__myProcess.readAll()).decode().replace('\r\n', '\n')
        print(data)

    def __on_error(self, error):
        print("")
        print("Process error: {0}".format(str(error)))
        print("")

    def __on_exit(self, exitCode, exitStatus):
        print("")
        print("ExitCode = {0}".format(str(exitCode)))
        print("ExitStatus = {0}".format(str(exitStatus)))
        print("")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    QApplication.setStyle(QStyleFactory.create('Fusion'))
    myGUI = CustomMainWindow()
    sys.exit(app.exec_())

基本上我要做的是:在命令QProcess()-实例启动命令之前,我将可执行路径添加到属于整个Python会话的PATH环境变量。一旦命令启动,我可以再次删除它,这样它就不会对将来创建的其他QProcess()-实例产生影响。在

它可以工作,但是如果我要在我的软件中应用这种方法,它肯定需要大量的“簿记”(我的软件中有许多QProcess()-实例)。如果你找到一个更好的方法,请不要犹豫分享!在

相关问题 更多 >