2016-05-02 2 views
1

Я работаю над очень длинным фрагментом кода и тем, который я хотел бы использовать для ввода GUI более одного раза в нескольких окнах.Задача Tkinter с несколькими функциями обратного вызова и использование after()

код слишком длинный и не имеет особого смысла, если я положил его здесь, но вот расположение моего кода:


callback1(): 
    do something

tkinter stuff, using callback1()  
... 
lots of other code (none to do with tkinter) 
... 

callback2():  
    do something else 

tkinter stuff using callback2() 

some more code (none to do with tkinter) 

mainloop() 

Извините за туманной структуры , но это более или менее макет моего кода. Проблема в том, что mainloop() никогда не кажется достигнутым, а мой другой код между обратными вызовами зависит от ввода из графического интерфейса пользователя и поэтому он сбой.

Я пробовал:


callback1(): 
    do something 
    after(500, callback1)

tkinter stuff, using callback1()  
... 
lots of other code (none to do with tkinter) 
... 

callback2():  
    do something else 
    after(500, callback1) 

tkinter stuff using callback2() 

some more code (none to do with tkinter) 

after(0, callback1) 
after(0, callback2) 
mainloop() 

Но не везло. Может ли кто-нибудь помочь мне с правильным использованием after() (или любой другой функции), чтобы я мог просто отобразить графический интерфейс?

ответ

1

Вы не можете упорядочить свой код. Предположительно, у вас есть что-то похожее на это:

import tkinter as tk 

mainwindow = tk.Tk() 
mainwindow.geometry("300x200") 
mainwindow.title("MyWindow") 

label = tk.Label(mainwindow, text="Enter stuff, then click the button.") 
label.pack() 

var = tk.StringVar() 
entry = tk.Entry(mainwindow, textvariable=var) 
entry.pack() 

#callback1(): 
def onclick(): 
    #do something with var.get() ? 
    pass 

button = tk.Button(mainwindow, text="click me", command=onclick) 
button.pack() 

#lots of other code (none to do with tkinter): 
print("The value I need is: {}".format(var.get())) 

mainwindow.mainloop() 

Выход этой программы является:

Значение мне нужно:

Вы должны поместить свой код либо в функция обратного вызова или другая функция, вызываемая функцией обратного вызова:

def my_func(): 
    print("The value I need: {}".format(var.get())) 

def onclick(): 
    #do something with var.get() 
    my_func() 

button = tk.Button(mainwindow, text="click me", command=onclick) 

Теперь, выход что-то вроде:

Значение мне нужно: 10

tkinter является основой GUI, и он реагирует на события, которые происходят в вашем окне. Способ, которым вы отвечаете на событие, - это обернуть свой код в функцию обратного вызова и передать функцию tkinter, которая затем вызовет функцию в нужное время. Вы не пишете произвольный код в середине программы tkinter.

Метод after() не представляется целесообразным, так как он, по существу, говорит:

После запуска MainLoop, выполнить эту функцию.

Вы можете отсрочить выполнение на сколько угодно секунд, но это не значит, что пользователь введет нужные вам данные. То, что вы хотите сделать, - это выполнить свой код после того, как пользователь вводит свои данные, и обычно вы делаете это, отвечая на нажатие кнопки, где кнопка говорит: Submit или какое-то другое событие.

+0

Действительно, я понял свою ошибку. После некоторой перетасовки моих функций обратного вызова (сбрасывая всю программу по существу в одну из функций обратного вызова), она работала как шарм, и я включил кнопку инициации. Спасибо за ваш ответ! – nanoman

1

GUI-фреймворки, такие как tkinter event-driven.Они начинают работать, когда начинают mainloop(). Все до этого в основном настроено и обслуживается.

После запуска MainLoop, то только куски кода, что они выполняются в функции обратного вызова, которые вы прикреплены к элементам интерфейса, как кнопки или для таймеров с after.

Эти обратные вызовы должны быть относительно коротким и не должно занять много времени. Инструментарий GUI вызывает функцию, которую вы предоставили для обработки события в mainloop. Таким образом, пока ваш обратный вызов работает, никакие дальнейшие события не обрабатываются и графический интерфейс эффективно заморожен. Если это займет немного времени (скажем, 50 миллисекунд), никто не заметит. Но если вы хотите, чтобы запустить вычисление, которое занимает несколько секунд, чтобы закончить, вы не можете сделать это в функции обратного вызова без замораживания GUI.

Вы могли бы рассмотреть возможность делать затянувшуюся работу во втором потоке. Но в CPython только один поток за раз может выполнять байт-код Python по техническим причинам. Однако (особенно в Python 3) потоки вынуждены регулярно отказываться от ЦП, поэтому это может быть приемлемым решением.

Другим решением является фермером длительными рабочих мест в отдельный процесс с использованием multiprocessing. В этом случае вам необходимо настроить связь между процессами через, например, a Queue.

+0

Благодарим вас за помощь! – nanoman