Python 在 Tkinter 中循环?

Python While loop in Tkinter?

我是 Python 的新手(主要是编程),我正在从事一个项目,以输出信标莫尔斯电码并在信标之间收听莫尔斯电码。

我有信标工作,可能不是最好的代码,但它确实有效,但是当循环开始时,Tkinter 屏幕冻结并且停止信标按钮在所有信标完成之前不起作用。

我想无限地 运行 信标,只需使用停止信标按钮来停止它,但到目前为止我似乎无法弄清楚如何停止循环。

#!usr/bin/env python

import sys
import re
import tkMessageBox
from Tkinter import *
import pygame
import time


CODE = {'A': '.-',     'B': '-...',   'C': '-.-.', 
    'D': '-..',    'E': '.',      'F': '..-.',
    'G': '--.',    'H': '....',   'I': '..',
    'J': '.---',   'K': '-.-',    'L': '.-..',
    'M': '--',     'N': '-.',     'O': '---',
    'P': '.--.',   'Q': '--.-',   'R': '.-.',
    'S': '...',    'T': '-',      'U': '..-',
    'V': '...-',   'W': '.--',    'X': '-..-',
    'Y': '-.--',   'Z': '--..',

    '0': '-----',  '1': '.----',  '2': '..---',
    '3': '...--',  '4': '....-',  '5': '.....',
    '6': '-....',  '7': '--...',  '8': '---..',
    '9': '----.' 
    }

ONE_UNIT = 0.5
THREE_UNITS = 3 * ONE_UNIT
SEVEN_UNITS = 7 * ONE_UNIT
PATH = 'morse_sound_files/'

def verify(string):
keys = CODE.keys()
for char in string:
    if char.upper() not in keys and char != ' ':
        sys.exit('Error the charcter ' + char + ' cannot be translated    to Morse Code')




beaconout = ''
beaconTEXT = 'this is text that is default'
def ask_quit():
if tkMessageBox.askokcancel("Quit", "are you sure you want to quit?"):
    root.destroy()

def getinput():
incomingTEXT = incoming.get()
outboundTEXT = outbound.get()
beaconTEXT = beaconmessage.get(1.0,"end")
beaconout = outboundTEXT+" "+outboundTEXT+" "+outboundTEXT+" "+beaconTEXT+""+incomingTEXT
print beaconout
beaconout = beaconout.replace('\n', ' ')
print beaconout
print 'Welcome to Alphabet to Morse Code Translator v.01'
msg = beaconout
#verify(msg)
print
pygame.init()

for char in msg:
    if char == ' ':
        print ' '*7,
        time.sleep(SEVEN_UNITS)
    else:
              print CODE[char.upper()],
              pygame.mixer.music.load(PATH + char.upper() + '_morse_code.ogg')
              pygame.mixer.music.play()
              time.sleep(THREE_UNITS)




root = Tk()
root.geometry("800x600+300+300")
frame = Frame(root, width=1000, height=600)
label1 = Label(root, text="To: Call Sign:")
label2 = Label(root, text="Your Call Sign:")
label3 = Label(root, text="Enter your message:")

outbound = StringVar()
outboundcallsign  = Entry(root, textvariable=outbound)

incoming = StringVar()
inboundcallsign = Entry(root, textvariable=incoming)

beacon = StringVar()
beaconmessage = Text(root, height=1, width=30)

label1.grid(row=1, sticky=E)
label2.grid(row=2, sticky=E)
label3.grid(row=3, sticky=E)

outboundcallsign.grid(row=1, column=1)
inboundcallsign.grid(row=2, column=1)
beaconmessage.grid(row=4, columnspan=4)

cbox = Checkbutton(root, text="message is ready to beacon?")
cbox.grid(columnspan=2)
submitbut = Button(root,text="Start Beacon", command = getinput)
submitbut.grid(row=14,column=1)
submitbut.bind("<Button-1>")

cancelbut = Button(root,text="Stop Beacon", command=ask_quit)
cancelbut.grid(row=14, column=3)

root.mainloop()

"I would like to run the beacon infinitely and just use the stop beacon button to stop"

运行 "Beacon" 代码在一个单独的进程中,因为你想同时做两件事,[1] 信标代码和 [2] 检查按钮按下(尽管它可能会找到一种创造性的方法来使用 "after" 检查按钮是否按下,恕我直言,这样做更明显也更省事)。退出按钮将取消该过程。为简单起见,此示例使用计数器而不是信标代码。

from multiprocessing import Process
from functools import partial

try:
    import Tkinter as tk    ## Python 2.x
except:
    import tkinter as tk    ## Python 3.x

class ProgressBar():
    def __init__(self, root):
        self.root=root
        self.root.geometry("75x50+900+100")
        self.ctr=1

    def counter(self):
        """ a separate process in a separate GUI
        """
        self.top_count=tk.Toplevel(self.root)
        self.top_count.geometry("75x50+750+50")
        self.label_ctr = tk.IntVar()
        self.label_ctr.set(self.ctr)
        label = tk.Label(self.top_count, textvariable=self.label_ctr)
        label.pack()
        self.change_counter()

    def change_counter(self):
        self.ctr += 1
        self.label_ctr.set(self.ctr)
        self.top_count.after(750, self.change_counter)


def stop_process(process_id, PB):
    process_id.terminate()
    PB.top_count.destroy()  ## destroy Toplevel to stop "after"

    ## shut down Tkinter
    ##root.quit()

root = tk.Tk()

PB=ProgressBar(root)
pr1=Process(target=PB.counter(), args=())
pr1.start()

tk.Button(root, text="Exit", bg="orange",
          command=partial(stop_process, pr1, PB)).pack()
root.mainloop()

如果你不想破坏 Toplevel 那么你可以使用一个变量,在下面这两个函数被改变的情况下,ctr > 0 但是要在两个进程之间进行通信需要一个管理器字典或列表。

def change_counter(self):
    self.ctr += 1
    self.label_ctr.set(self.ctr)
    if self.ctr > 0:
        self.top_count.after(750, self.change_counter)


def stop_process(pr1, PB):
    PB.ctr = -10
    pr1.terminate()
##    PB.top_count.destroy()