Python 3.6 + tkinter:使用Button停止while循环

时间:2017-12-24 10:26:35

标签: python tkinter while-loop

目前我正在努力停止使用Python 3.6中的按钮停止while循环,我在Windows 10上运行tkinter。 我做了一些阅读并尝试将所有内容放在代码中(在root上调用after方法;在时间方法中为after方法提供一个int;调用函数引用,而不是函数),但我仍然无法做到让我的头围绕它。 附加的代码由于GUI线而有些冗长,麻烦的部分标有标题:

#!/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()

我想通过单击Stop-Button运行StopButton方法退出StartButton方法中的while循环。 StopButton方法将属性self.PingPongExec设置为FALSE,但由于循环,它不会让我点击停止按钮。

对不起基本问题,但我脑袋里有个结。

亲切的问候,

塞巴斯蒂安

1 个答案:

答案 0 :(得分:0)

你应该在事件处理程序方法或函数StartButton中运行循环!

当某些事件发生时,正在从主循环调用事件处理程序。当您的事件处理程序正在运行时,不会再进行任何事件处理。

在事件处理程序StartButton中,只需使用after方法来安排RunPingPong