2017-12-24 9 views
0

저는 Windows 10에서 실행되는 tkinter를 사용하여 파이썬 3.6의 버튼으로 while 루프를 멈추는 데 어려움을 겪고 있습니다. 나는 꽤 많은 독서를했으며 모든 것을 넣으려고했습니다. 코드에서 (루트에서 after 메소드를 호출하고, after 메소드에 시간에 대한 int를 제공하고, 함수가 아닌 함수 참조를 호출한다.) 그러나 여전히 나는 그 머리를 아직 둘러 볼 수 없다. 추가 코드 인해 GUI 라인에 다소 긴입니다, 성가신 부분은 헤드 라인으로 표시됩니다 :파이썬 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이라는 메소드를 실행하여 StartButton-방법의 동안 루프를 종료 할 정지 버튼. StopButton 메서드는 self.PingPongExec 속성을 FALSE로 설정하지만 루프 때문에 중지 버튼을 클릭 할 수 없습니다.

미안하지만 기본 질문에 대해서는 매듭이 들었다.

종류와 관련,

세바스찬

+1

'RunPingPong'을 실행하기 위해'while' 대신'tkiner.after (milliseconds, function_name)'를 사용하면 tkinter의 모든 작업을 수행하는'mainloop()'을 멈추지 않습니다 - 마우스/키 이벤트를 가져오고, 위젯을 업데이트, 위젯을 다시 그리기, 위젯을 다시 그리기, 버튼에 지정된 기능 실행, after() 등으로 지정된 함수를 실행합니다. – furas

답변

0

당신이해야 StartButton 같은 이벤트 핸들러 메서드 또는 함수에서 루프를 실행하지!

이벤트 핸들러는 특정 이벤트가 발생할 때 mainloop에서 호출됩니다. 이벤트 핸들러가 실행 중일 때 이벤트 처리가 더 이상 수행 될 수 없습니다.

StartButton 이벤트 처리기에서 after 메서드를 사용하여 RunPingPong을 예약하면됩니다.

+0

그 충고에 감사드립니다! 내가 기본적인 것을 이해하지 못했던 것 같아. 이제 StartButton 메서드는 root.after() (또는 내 경우에는 root = master)로 자신을 호출 한 RunPingPong 메서드를 호출합니다. –

+0

당신을 진심으로 환영합니다. :-) 당신은 대부분 이미 거기에있었습니다. 이것은 여러분의 코드가 기본적으로 메인 이벤트 루프의 게스트 인 GUI 도구 키트의 기본 속성 중 하나입니다. 따라서 장기간의 작업을 작은 조각으로 나눠야합니다. –

관련 문제