2015-06-18 119 views
0

我对Python非常陌生(并且大部分是编程),我正在开发一个项目来指示信标莫尔斯码,并监听信标之间的莫尔斯码。Python虽然在Tkinter循环?

我有灯塔工作,可能不是最好的代码,但它确实工作,但是当循环开始时,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() 
+1

难以重现您的问题,但问题似乎是UI线程被阻止。把'getinput'中的东西放到一个线程中,或者使用'root.after'而不是'sleep'来重写''msg'循环中的char' –

回答

1

“我想无限运行信标,只是使用的停止灯塔按钮停止”

在一个单独的进程中运行的“灯塔”的代码,当你想要做的两件事同时,[1]灯塔代码和[2]检查按钮按下(虽然也许可以找到一种创造性的方式来使用“之后”来检查按钮按下,恕我直言,这是更明显和更少麻烦做到这一点办法)。退出按钮将取消该过程。为了简单起见,本示例使用计数器而不是信标代码。

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() 

如果你不想破坏顶层,那么你可以使用一个变量,在下列情况下,这些2个funtions改变,点击率> 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() 
+0

嗯,我真的想在同一帧中包含这个,老实说我需要同时做几件事情,我还没有开发其他的侦听,解码和打印解码的文本函数,但我的意图是听不到实际的信标,如果听解码预期的呼号,然后我们会将解码后的信息打印到我们用来输入和启动信标的同一帧。这是可能的Python或我超越Python功能试图做到这一点? – Daniac

+0

您当然可以将Toplevel更改为Frame,并仍然使用上述两种方法之一。如果同时需要多个实例,那么stop_process()函数以及可能添加的其他任何内容都应该在同一个类中,如果您想单独停止它们。然后为每个类实例启动一个单独的进程。 –