2014-11-20 2 views
3

그래서 Tkinter GUI에는 두 가지 간단한 옵션 인 시작 및 중지 버튼이 있습니다. 나는 GUI 레이아웃 정의 : 여기Tkinter GUI 중지 버튼을 만들어 무한 루프를 깨는 방법은 무엇입니까?

from Tkinter import * 

def scanning(): 
    while True: 
     print "hello" 

root = Tk() 
root.title("Title") 
root.geometry("500x500") 

app = Frame(root) 
app.grid() 

시작 버튼이 무한 루프 스캔을 실행을하고, 중지 버튼을 눌러에 휴식해야합니다

start = Button(app, text="Start Scan",command=scanning) 
stop = Button(app, text="Stop",command="break") 

start.grid() 
stop.grid() 

그러나, 나는 시작 단추를 명중 할 때, 그것을 항상 푸시 다운됩니다 (무한 루프 때문에 가정). 그러나 은 중지 버튼을 클릭하여 while 루프를 벗어날 수 없습니다.

답변

8

Tkinter 이벤트 루프가 작동하는 동일한 스레드에서 while True: 루프를 시작할 수 없습니다. 그렇게하면 Tkinter의 루프가 차단되어 프로그램이 중단됩니다.

간단한 솔루션으로는 Tk.after을 사용하여 1 초마다 백그라운드에서 프로세스를 실행할 수 있습니다. 다음은 스크립트가 증명하는 것입니다

물론
from Tkinter import * 

running = True # Global flag 

def scanning(): 
    if running: # Only do this if the Stop button has not been clicked 
     print "hello" 

    # After 1 second, call scanning again (create a recursive loop) 
    root.after(1000, scanning) 

def start(): 
    """Enable scanning by setting the global flag to True.""" 
    global running 
    running = True 

def stop(): 
    """Stop scanning by setting the global flag to False.""" 
    global running 
    running = False 

root = Tk() 
root.title("Title") 
root.geometry("500x500") 

app = Frame(root) 
app.grid() 

start = Button(app, text="Start Scan", command=start) 
stop = Button(app, text="Stop", command=stop) 

start.grid() 
stop.grid() 

root.after(1000, scanning) # After 1 second, call scanning 
root.mainloop() 

, 당신은 클래스에이 코드를 리팩토링과 running 그것의 속성 수 있어야 할 수 있습니다. 또한 프로그램이 복잡해지면 파이썬의 threading module을 조사하여 scanning 함수가 별도의 스레드에서 실행될 수 있도록하는 것이 좋습니다.

+0

나는 블루투스 RSSI 신호를 지속적으로 스캔하기 때문에 while 루프가 필요하다는 것을 추가해야한다. 따라서,이 프로그램은 나를 위해 작동하지 않습니다. while 루프를 사용하여 다른 방법이 있습니까? @iCodez –

+0

@ JonathanDavies - 글쎄, 당신은 항상'root.after (1000, scanning)'을'root.after (1, scanning)'로 바꿔 코드가 매초마다'scanning '을 실행하도록 할 수 있습니다. 이것은 연속 while 루프와 거의 같은 효과를 갖습니다. 그렇지 않으면 루프를 별도의 스레드에 넣어야합니다. 위에서 준 링크에는 더 많은 정보가 있지만 기본적으로 루프를 함수에 넣은 다음 함수를 threading.Thread에 제공합니다. – iCodez

+0

그래서 내가 수집 한 것에서 시작 = 버튼 (app, text = "스캔 시작", command = threading.Thread (name = "bluetooth", target = scanning))입니다. 이것은 작동하지 않으며 Thread() 뒤에 .start()를 추가하면 클릭하지 않고 바로 함수를 시작합니다. @iCodez –

0

여기에 다른 솔루션은 다음과 같은 장점이다 :

  1. Tk.after 전화를 사용하지 않는 별도의 스레드

  2. 를 만드는 수동으로 필요하지 않습니다. 대신 연속 루프가있는 원래 스타일의 코드가 보존됩니다. 이 기능의 가장 큰 장점은 루프 내의 코드가 실행되는 빈도를 결정하는 밀리 초 수를 수동으로 지정하지 않아도되므로 하드웨어가 허용하는 한 자주 실행되도록 설정된다는 것입니다.

참고 : 난 단지 파이썬 2와 나는 같은 너무 파이썬 2에서 작동합니다 그냥 확실히 100 %를 모르는 생각하지, 파이썬 3로 이것을 시도했습니다.

UI 코드와 시작/중지 논리에 대해서는 iCodez의 대답과 거의 동일한 코드를 사용합니다. 우리가 root.mainloop()를 호출하지 않는

from tkinter import * 

running = True # Global flag 
idx = 0 # loop index 

def start(): 
    """Enable scanning by setting the global flag to True.""" 
    global running 
    running = True 

def stop(): 
    """Stop scanning by setting the global flag to False.""" 
    global running 
    running = False 

root = Tk() 
root.title("Title") 
root.geometry("500x500") 

app = Frame(root) 
app.grid() 

start = Button(app, text="Start Scan", command=start) 
stop = Button(app, text="Stop", command=stop) 

start.grid() 
stop.grid() 

while True: 
    if idx % 500 == 0: 
     root.update() 

    if running: 
     print("hello") 
     idx += 1 

이 코드에서 : 중요한 차이가 나는 우리가 항상 루프 실행을 가지고 있지만 버튼 최근 누르면되고있는 근거가 무엇을해야 하는지를 그 루프 내에서 결정됩니다 가정이다 tkinter GUI를 계속해서 업데이트하십시오. 대신 우리는 수시로 수동으로 업데이트합니다 (이 경우 500 회 반복마다).

이론적으로 이는 중지 버튼을 누르 자마자 즉시 루프를 멈추지 않을 수 있음을 의미합니다. 예를 들어, Stop 버튼을 눌렀을 때의 바로 그 순간에 우리는 반복 501에 있으며이 코드는 반복 1000에 도달 할 때까지 계속 반복됩니다. 따라서이 코드의 단점은 이론적으로 덜 민감한 GUI를 제공한다는 것입니다 (그러나 루프 내의 코드가 빠르면 눈에 띄지 않습니다).그 대신 루프 내부의 코드를 가능한 한 빨리 실행하고 (GUI update() 호출로 인한 오버 헤드가있을 때만) 주 스레드 내부에서 실행되도록합니다.

관련 문제