【问题标题】:How to run two non-terminating scripts in parallel in a GUI?如何在 GUI 中并行运行两个非终止脚本?
【发布时间】:2015-11-30 01:29:42
【问题描述】:

我知道我可以通过打开两个终端窗口轻松地手动执行此操作。我试图通过创建一个带有两个按钮的 GUI 来尽可能地自动化这个过程。一种用于连接和运行监听器,另一种用于运行通话器。

这是我的代码:

#python 3
#from tkinter import *
#from tkinter import ttk

#python 2
from Tkinter import *
import ttk

import time
import subprocess
import paramiko

def calculate(*args):
    try:
        value = float(feet.get())
        meters.set((0.3048 * value * 10000.0 + 0.5)/10000.0)
    except ValueError:
        pass


def connect():
  ssh = paramiko.SSHClient()
  ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  ssh.connect('192.168.1.2', username='pi', password='raspberry')
  stdin, stdout, stderr = ssh.exec_command('cd')
  stdin, stdout, stderr = ssh.exec_command('roscore &')
  time.sleep(20)
  stdin, stdout, stderr = ssh.exec_command('\n')
  stdin, stdout, stderr = ssh.exec_command('cd scripts')
  stdin, stdout, stderr = ssh.exec_command('python /home/pi/scripts/listener2.py')
  return

def run():
  stdin, stdout, stderr = ssh.exec_command('python ES96_Vivaldi/talker2.py')


root = Tk()

mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)

ttk.Button(mainframe, text="Connect", command=connect).grid(column=1, row=3, sticky=S)
ttk.Button(mainframe, text="Run", command=run).grid(column=3, row=3, sticky=S)

ttk.Label(mainframe, text="Click 'Connect' to establish link.").grid(column=1, row=1, sticky=W)
ttk.Label(mainframe, text="Click 'Run' to control using the arrow keys").grid(column=1, row=2, sticky=W)

for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5)


root.mainloop()

它会打开一个带有连接按钮和运行按钮的小 GUI。 Connect 工作正常,但由于 listener2.py 脚本没有终止,GUI 冻结,我无法按下 Run 按钮(以相反的顺序尝试时同样的问题)。

有没有办法启动一个脚本并让它在后台运行,这样 GUI 就不会冻结,我可以启动下一个脚本?

谢谢!

【问题讨论】:

    标签: python ssh tkinter raspberry-pi ubuntu-14.04


    【解决方案1】:

    您可以在后台线程中运行处理程序。在您当前的设置中,处理程序不会向 gui 提供任何反馈,因此实际上只需将按钮命令切换到启动线程的函数即可。

    我添加了一些代码来禁用按钮,因此处理程序只能启动一次。诀窍是您需要一些地方来存储按钮小部件,以便以后可以再次访问它们。

    #python 3
    #from tkinter import *
    #from tkinter import ttk
    
    #python 2
    from Tkinter import *
    import ttk
    
    import time
    import subprocess
    import paramiko
    
    import threading
    
    # keep track of widgets for event handlers
    widget_track = {}
    
    # event handler creates connect thread
    def connect_evt():
        t = threading.Thread(target=connect)
        t.daemon = True
        t.start()
        widget_track['connect'].config(text="Connected", state="disabled", command=None)
    
    def connect():
      time.sleep(5)   # todo: temporary for test
      return
      ssh = paramiko.SSHClient()
      ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
      ssh.connect('192.168.1.2', username='pi', password='raspberry')
      stdin, stdout, stderr = ssh.exec_command('cd')
      stdin, stdout, stderr = ssh.exec_command('roscore &')
      time.sleep(20)
      stdin, stdout, stderr = ssh.exec_command('\n')
      stdin, stdout, stderr = ssh.exec_command('cd scripts')
      stdin, stdout, stderr = ssh.exec_command('python /home/pi/scripts/listener2.py')
      return
    
    # event handler creates run thread
    def run_evt():
        t = threading.Thread(target=run)
        t.daemon = True
        t.start()
        widget_track['run'].config(text="Running", state="disabled", command=None)
    
    def run():
      time.sleep(5)     # todo: temporary for test
      return
      stdin, stdout, stderr = ssh.exec_command('python ES96_Vivaldi/talker2.py')
    
    
    root = Tk()
    
    mainframe = ttk.Frame(root, padding="3 3 12 12")
    mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
    mainframe.columnconfigure(0, weight=1)
    mainframe.rowconfigure(0, weight=1)
    
    # connect button starts connect background thread
    btn = ttk.Button(mainframe, text="Connect", command=connect_evt)
    btn.grid(column=1, row=3, sticky=S)
    widget_track['connect'] = btn
    
    # run button start run background thread
    btn = ttk.Button(mainframe, text="Run", command=run_evt)
    btn.grid(column=3, row=3, sticky=S)
    widget_track['run'] = btn
    
    ttk.Label(mainframe, text="Click 'Connect' to establish link.").grid(column=1, row=1, sticky=W)
    ttk.Label(mainframe, text="Click 'Run' to control using the arrow keys").grid(column=1, row=2, sticky=W)
    
    for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5)
    
    
    root.mainloop()
    

    【讨论】:

      猜你喜欢
      • 2019-05-04
      • 2010-10-10
      • 2013-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-20
      • 1970-01-01
      • 2014-09-26
      相关资源
      最近更新 更多