2017-12-24 25 views
0

現在、私はWindows 10で動作するtkinterでPython 3.6のボタンを使ってwhileループを停止するのに苦労しています。 私はかなりの読書をして、コードでは(後のメソッドをルートで呼び出し、afterメソッドに時間のintを渡し、関数ではなく関数参照を呼び出す)、それでもまだ私の周りに私の頭を得ることはできません。 追加のコードが原因GUI-ラインにやや長いです、面倒な部分は見出しが付いている:Python 3.6 + tkinter:ボタンを使ってwhileループを停止する

#!/usr/bin/python3 
# GUI for Servotester with Arduino 

from tkinter import * 
from tkinter import ttk 
from tkinter import messagebox 
import serial 
import serial.tools.list_ports 
from time import time 

# Servo Handler Object 
class ServoLine:     
    def __init__(self, ServoNumber, frame_body, COMPort, master): 
     ### Setting up the Technical Components 
     # GUI Basic Components 
     self.master = master 
     self.frame_body = frame_body 
     self.COMPort = COMPort 
     # Technical Components 
     self.PingPongExec = False # Toggle to run Ping Pong Command    
     self.PingPongDirect = False # Direction of Ping Pong Servo Travel 
     self.SleepTime = 1000  # Time to next command 
     self.Min = 1020 
     self.Max = 1980 
     # GUI Components 
     self.Place = ServoNumber 
     self.Mode = StringVar() 
     self.ServoPos = ttk.Entry(self.frame_body, width=15) 
     self.ServoPos.insert(0, '1500') 
     self.ServoMin = ttk.Entry(self.frame_body, width=15) 
     self.ServoMin.insert(0, '1020') 
     self.ServoMax = ttk.Entry(self.frame_body, width=15) 
     self.ServoMax.insert(0, '1980') 
     self.PingPongTime = ttk.Entry(self.frame_body, width=15) 
     self.PingPongTime.insert(0, '1000') 
     self.ComboMode = ttk.Combobox(self.frame_body, textvariable=self.Mode, values=('Go Straight', 'Ping Pong'), width=10) 
     self.Mode.set('Go Straight') 
     self.Start = ttk.Button(self.frame_body, text='Start', command=self.StartButton) 
     self.Stop = ttk.Button(self.frame_body, text='Stop', command=self.StopButton) 
     # Now build the GUI 
     ttk.Label(self.frame_body, text='{}'.format(ServoNumber)).grid(row=ServoNumber, column=0, sticky='w', padx=5) 
     self.ServoPos.grid(row=ServoNumber, column=1, sticky='w', padx=5) 
     self.ServoMin.grid(row=ServoNumber, column=2, sticky='w', padx=5) 
     self.ServoMax.grid(row=ServoNumber, column=3, sticky='w', padx=5) 
     self.PingPongTime.grid(row=ServoNumber, column=4, sticky='w', padx=5) 
     self.ComboMode.grid(row=ServoNumber, column=5, padx=5) 
     self.Start.grid(row=ServoNumber, column=6) 
     self.Stop.grid(row=ServoNumber, column=7) 

    ###### TROUBLESOME PART START ###### 
    def StartButton(self): 
     # GOING STRAIGHT Execution 
     if self.Mode.get() == 'Go Straight': 
      print('Servo {} is going straight to Position {}'.format(self.Place, self.ServoPos.get())) 
      print('The COMPort is: {}'.format(self.COMPort)) 
     # PING PONG Execution 
     else: 
      self.PingPongExec = True 
      self.SleepTime = int(self.PingPongTime.get()) # Most likely not the most elegant, but I dont want to call .get() in while loop... 
      self.Min = self.ServoMin.get() 
      self.Max = self.ServoMax.get() 
      # Looping 
      while self.PingPongExec: self.RunPingPong() 

    def RunPingPong(self): 
     if self.PingPongDirect:  # self.PingPongDirect is either True or False 
      print('Servo {} is going up to Position {}'.format(self.Place, self.Max)) 
      self.PingPongDirect = False 
      self.master.after(self.SleepTime, self.RunPingPong) 
      print(time()) 
     else: 
      print('Servo {} is going down to Position {}'.format(self.Place, self.Min)) 
      self.PingPongDirect = True 
      self.master.after(self.SleepTime, self.RunPingPong) 
      print(time()) 

    def StopButton(self): 
     self.PingPongExec = False 
     print('Setting PingPongExec to 0') 
    ###### TROUBLESOME PART END ###### 


class ServoGUI: 
    def __init__(self, master): 
     self.master = master 
     self.master.resizable('false', 'false') 
     self.master.title('nanoServo-Driver') 

     # COM-Port Handling and Auto-Connecting 
     self.COMPortList = list() 
     self.COMPort = 'COM1' 
     self.COMPortsList = list(serial.tools.list_ports.comports()) # Get names of all COMPorts 

     # Try except block to be able to test programm without a Arduino attached 
     try: 
      for p in self.COMPortsList: 
       if "CH340" in p[1]: # Looking for a Arduino Clone 
        self.COMPort = p[0] 
        print(self.COMPort) 
        break   
       else: 
        pass 
      self.Ser = serial.Serial(self.COMPort, 57600) 
      self.Ser.write(2000) 
     except: print('Connection setup failed!') 

     ### Frame with choice of COM-Port 
     frame_header=ttk.Frame(self.master) 
     frame_header.pack(anchor='w') 
     message = 'Arduino found on {}. '.format(self.COMPort) 
     ttk.Label(frame_header, text=message).grid(row=0, column=0, sticky='w') 
     ttk.Button(frame_header, text='Disconnect', command=self.Disconnect).grid(row=0, column=2, sticky='w') 
     # Giving connection status to the user 


     ### Frame with Servo configuration 
     # Table Header 
     frame_body=ttk.Frame(self.master) 
     frame_body.pack(anchor='w') 
     ttk.Label(frame_body, text='Servo').grid(row=0, column=0, sticky='w', padx=5, pady=10) # Column 'Servo' 
     ttk.Label(frame_body, text='Servoposition [mu_s]'). grid(row=0, column=1, padx=5)  # Column 'Servoposition' 
     ttk.Label(frame_body, text='Lower Position [mu_s]').grid(row=0, column=2, padx=5)  # Column 'Lower Position' 
     ttk.Label(frame_body, text='Upper Position [mu_s]').grid(row=0, column=3, padx=5)  # Column 'Lower Position' 
     ttk.Label(frame_body, text='Ping Pong Time [ms]').grid(row=0, column=4, padx=5)   # Column 'Time Ping Pong' 
     ttk.Label(frame_body, text='Mode').grid(row=0, column=5, padx=5, sticky='w')   # Column 'Lower Position' 
     # Calling the Objects for the Servos. Per Servo one line. 
     self.Servo1 = ServoLine(1, frame_body, self.COMPort, self.master)  

    # Disconnect Method 
    def Disconnect(self): 
     self.Ser.close() 


### MAIN-Function  
def main():    
    root = Tk() 
    Servo = ServoGUI(root) 
    root.mainloop() 

if __name__ == "__main__": main() 

私はクリックしてStopButton-方法を実行して、スタートボタン-方法でwhileループを終了します停止ボタン。 StopButtonメソッドは、プロパティself.PingPongExecをFALSEに設定しますが、ループによって、停止ボタンをクリックすることはできません。

基本的な質問は申し訳ありませんが、私は結び目を持っています。

敬具、

セバスチャン

+1

'RunPingPong'を実行するために' while'の代わりに 'tkiner.after(milliseconds、function_name)'を使い、tkinterのすべての仕事をする 'mainloop()'を止めません - マウス/ウィジェットを更新したり、ウィジェットを再描画したり、ボタンに割り当てられた関数を実行したり、after()などで割り当てられた関数を実行したりすることができます。 – furas

答えて

0

あなたべきStartButtonのようなイベントハンドラメソッドや関数でループを実行しない

イベントハンドラは、特定のイベントが発生したときにメインループから呼び出されています。イベントハンドラが実行されている間、それ以上のイベント処理は発生しません。

イベントハンドラStartButtonでは、afterメソッドを使用してRunPingPongをスケジュールするだけです。

+0

そのアドバイスをいただきありがとうございます!私は基本的なことを理解していなかったように見えます。メソッドStartButtonは、一度root.after()(または私の場合はroot = master)で自分自身を呼び出すとRunPingPongメソッドを呼び出します。 –

+0

ようこそ。 :-)あなたはすでにほとんどそこにいました。これは、コードが基本的にメインイベントループのゲストであるGUIツールキットの基本的なプロパティの1つです。だから、長時間の作業を小さなものに分割しなければならない。 –

関連する問題