通过外部和可交换的 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 中获取不同的值。效果很好!
我的长期目标是为实验物理实验构建一个具有连续 运行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 中获取不同的值。效果很好!