通过外部和可交换的 python 脚本持续与 运行 Python Gui 交互

Interact with continuously running Python Gui by external and exchangeable python script

我的长期目标是为实验物理实验构建一个具有连续 运行ning 图形用户界面的图形用户界面。通过按下一个按钮,我希望能够 运行 我选择的 pyhton 脚本,它可以与 运行ning gui 交互。例如,将数字设置为旋转框。 我附上了一个启动项目。一个旋转框和一个按钮。如果按下按钮,则会将一个随机数设置到旋转框,一旦旋转框中的数字发生变化,它就会打印该数字。 有没有办法通过按下按钮来调用脚本(目前使用硬编码路径),然后将 gui 中的数字设置为我的选择。脚本的内容(在本例中为旋转框设置的数字)必须在 gui 的 运行 时间内可编辑。 如果您能为此提供一个示例,我将不胜感激,并且可以自己构建其余部分。

提前致谢!

import sys
import random
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QApplication, QWidget, QDoubleSpinBox, QPushButton

class GuiInteraction(QWidget):

    def __init__(self):
        super().__init__()
        self.initGUI()
        self.CallBackFunctions()

    def initGUI(self):
        self.resize(400, 500)
        self.move(300, 300)
        self.setWindowTitle('Gui Interaction')
        self.doubleSpinBox = QDoubleSpinBox(self)
        self.doubleSpinBox.setGeometry(QtCore.QRect(120, 130, 120, 25))
        self.doubleSpinBox.setDecimals(5)
        self.doubleSpinBox.setMaximum(1000)
        self.doubleSpinBox.setObjectName("doubleSpinBox")
        self.pushButton = QPushButton("Run Script", self)
        self.pushButton.setGeometry(QtCore.QRect(100, 300, 100, 40))
        self.pushButton.setObjectName("pushButton")

    def CallBackFunctions(self):
        self.pushButton.clicked.connect(self.buttonClicked)
        self.doubleSpinBox.valueChanged.connect(self.valueChanged)

    def buttonClicked(self):
        self.doubleSpinBox.setValue(random.uniform(1, 200))

    def valueChanged(self):
        print(self.doubleSpinBox.value())


if __name__ == '__main__':

        app = QApplication(sys.argv)

        MyWindow = GuiInteraction()
        MyWindow.show()

        sys.exit(app.exec_())

我想你可以调用一个 FileDialog,选择一个脚本并使用:

   mod =  __import__(path)

,而不是应该使用某种 "run" 函数充分构建脚本,您可以通过以下方式启动它:

   mod.run()

也检查此 question

一种方法是通过 stdin/stdout

与外部脚本通信

my_script.py

def main():
    print '4.2'

if __name__ == '__main__':
    main()

gui_script.py

import subprocess

...

    def buttonClicked(self):
        try:
            value = float(subprocess.check_output(['python', 'my_script.py']).strip())
        except ValueError:
            value = 1.0
        self.doubleSpinBox.setValue(value)

如果你需要将参数传递给你的函数,你可以将它们作为附加参数传递给 subprocess.check_output 调用,然后它们从 sys.argv 中读取它们(它们都将以字符串形式出现,所以你必须在必要时转换类型,或者使用像 argparse 这样的库,它可以为你做类型转换)在被调用的脚本中。

我选择了@armatita 的解决方案,尽管我做了一些改动。经过简短的研究后,__import__ 似乎已被我现在使用的 libimport 库所取代。添加了以下行:

Header:

import importlib
import threading

在主函数中:

def buttonClicked(self):
    ScriptControlModule = importlib.import_module("ExternalScript")
    ScriptControlModule = importlib.reload(ScriptControlModule)
    ScriptControlThread = threading.Thread(target=ScriptControlModule.execute,args=(self,))
    ScriptControlThread.start()

importlib 行回答了我的问题。我还想在子线程中启动脚本,因此万一它因错字或其他原因而崩溃,整个 gui 不会跟随崩溃。

ExternalScript 在同一个文件夹中并命名为 ExternalScript.py

import random
def execute(self):
    self.doubleSpinBox.setValue(random.uniform(1, 5))

简单的三行代码。我可以在 运行 时更改这些行,并在 SpinBox 中获取不同的值。效果很好!