Уведомления

Группа в Telegram: @pythonsu
  • Начало
  • » GUI
  • » возможно ли приостановить Tk.mainloop() ? [RSS Feed]

#1 Фев. 1, 2014 18:07:45

Ryoga
Зарегистрирован: 2014-02-01
Сообщения: 20
Репутация: +  1  -
Профиль   Отправить e-mail  

возможно ли приостановить Tk.mainloop() ?

Добрый день! Сразу скажу, что я новичок и с Тkinter практически дела не имел.

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

Необходимо перевести ее на графический интерфейс с простейшей структурой - т.е. некое окошко, в нем несколько Entry для ввода данных и Text для вывода. Т.е. задача, вроде бы, тривиальная - переопределить пользовательскую функцию, отвечающую за ввод, чтобы данные эти она получала из Entry, а соответствующую функцию, отвечающую за вывод, чтобы выводила в Text. Предварительно создав это все, разумеется (еще проще было бы сделать через модальные диалоги, но тогда оно не сильно отличалось бы от консольной версии)

Тем не менее, уперся в очевидную проблему - после запуска mainloop() последний прекращает свою работу только с закрытием всего интерфейса. Т.е. реализовать схему <основная программа>-<вызов фунции ввода/вывода>-<возврат в основную программу> не представляется возможным. Как вошли в цикл обработки графического интерфейса, так в нем и остались, максимум - можем вызвать отдельные подпрограммы обработки событий, не более того.

Сделать из основного цикла программы “сопрограмму”, возвращающую управление в графический интерфейс по yield, невозможно - как уже говорил, там не линейная программа, а множество модулей/функций. Сделать два параллельных потока - во-первых, муторно слишком, во-вторых нерационально с точки зрения ресурсов, т.к. когда вычисления происходят, интерфейс не нужен, и наоборот.

Вот и задумался, а нельзя ли как-нибудь этот самый mainloop() приостановить? т.е. при необходимости использования интерфейса его запускать, а после получения и обработки данных через какой-нибудь Event (нажатие кнопки “продолжить”, например) возвращать управление в основную программу?

Если нет, может, кто подскажет альтернативное решение проблемы? Буду очень благодарен.

Отредактировано Ryoga (Фев. 1, 2014 18:09:12)

Офлайн

#2 Фев. 3, 2014 00:35:15

Ryoga
Зарегистрирован: 2014-02-01
Сообщения: 20
Репутация: +  1  -
Профиль   Отправить e-mail  

возможно ли приостановить Tk.mainloop() ?

В общем, решение нашел. Как поставить Tk.mainloop() “на паузу”, к сожалению, не узнал, но гугль подкинул идейку вообще его не запускать, а воспользоваться Tk.update() в условном цикле. Проверил - работает, не только интерфейс перерисовывает, но и события отлавливаются, так что написание функций ввода-вывода становится делом очевидным.

Офлайн

#3 Фев. 3, 2014 15:24:51

4kpt_II
От: Харьков
Зарегистрирован: 2013-10-24
Сообщения: 999
Репутация: +  58  -
Профиль   Отправить e-mail  

возможно ли приостановить Tk.mainloop() ?

Иногда придется еще использовать .update_idletasks().

P.S. Существует еще множество решений Вашей задачи. Я бы использовал другое. Проще не отображать базовое окно, а отображать Toplevel в нужный момент (для запроса данных, например). После получения данных можно было бы закрывать Toplevel и продолжать дальнейшее выполнение программы. Но это мое личное мнение

Будут вопросы - пишите…

Отредактировано 4kpt_II (Фев. 3, 2014 15:25:34)

Офлайн

#4 Фев. 4, 2014 11:52:10

Ryoga
Зарегистрирован: 2014-02-01
Сообщения: 20
Репутация: +  1  -
Профиль   Отправить e-mail  

возможно ли приостановить Tk.mainloop() ?

Проще не отображать базовое окно, а отображать Toplevel в нужный момент (для запроса данных, например). После получения данных можно было бы закрывать Toplevel и продолжать дальнейшее выполнение программы. Но это мое личное мнение

Но тогда же придется каждый раз перерисовывать все виджеты на Toplevel, а также запоминать перед закрытием и восстанавливать информацию в них (например, в Text хранится лог событий). Не говоря уж о том, что окошко постоянно будет “мигать”. Чисто эстетически постоянное приложения красивее.

Иногда придется еще использовать .update_idletasks().

Насколько я понял из описания:

update()
Processes all pending events, calls event callbacks, completes any pending geometry management, redraws widgets as necessary, and calls all pending idle tasks. This method should be used with care, since it may lead to really nasty race conditions if called from the wrong place (from within an event callback, for example, or from a function that can in any way be called from an event callback, etc.). When in doubt, use update_idletasks instead.

основные проблемы при использовании метода update() возникают при вызове его тем или иным способом из обработчиков событий (подозреваю рекурсию в результате). В моей же ситуации он не будет вызываться нигде, кроме как из основной программы.

К слову, при замене update() на update_idletasks() в нижеприведенном случае:

# -*- coding: utf-8 -*-
import Tkinter
from Tkinter import *
def end():
    root.flag = False
    root.destroy()
root = Tk()
root.protocol('WM_DELETE_WINDOW', end)
root.flag = True
textbox = Text(root, font='Verdana 14',wrap=WORD, width=50, height=10)
textbox.pack(side='left')
b_yes = Button(root, text = u'Проверка',
                            command=lambda: textbox.insert(END, u'Работает! '))
b_yes.pack()
while root.flag:
    root.update()

последний не только не обрабатывает события, но даже не перерисовывает виджеты, хотя нужда в том явно есть - их же вообще еще никто не отобразил. Так и висит белое окно Tk

Отредактировано Ryoga (Фев. 4, 2014 11:54:11)

Офлайн

#5 Фев. 4, 2014 12:05:33

4kpt_II
От: Харьков
Зарегистрирован: 2013-10-24
Сообщения: 999
Репутация: +  58  -
Профиль   Отправить e-mail  

возможно ли приостановить Tk.mainloop() ?

Этот метод не для этого…
Я не писал, что они взаимозаменяемые.

Вы поставили совершенно другую задачу. Ни о каком логе речь не шла.

Ryoga
Т.е. реализовать схему <основная программа>-<вызов фунции ввода/вывода>-<возврат в основную программу> не представляется возможным. Как вошли в цикл обработки графического интерфейса, так в нем и остались, максимум - можем вызвать отдельные подпрограммы обработки событий, не более того.Сделать из основного цикла программы “сопрограмму”, возвращающую управление в графический интерфейс по yield, невозможно - как уже говорил, там не линейная программа, а множество модулей/функций. Сделать два параллельных потока - во-первых, муторно слишком, во-вторых нерационально с точки зрения ресурсов, т.к. когда вычисления происходят, интерфейс не нужен, и наоборот.Вот и задумался, а нельзя ли как-нибудь этот самый mainloop() приостановить? т.е. при необходимости использования интерфейса его запускать, а после получения и обработки данных через какой-нибудь Event (нажатие кнопки “продолжить”, например) возвращать управление в основную программу? Если нет, может, кто подскажет альтернативное решение проблемы? Буду очень благодарен.

Где тут речь про лог?
Вы поставили одну задачу, а решили другую
Неспортивно

Задача поставлена по другому:
1. Есть основной цикл обработки событий (там проводятся все рассчеты и т.п.)
2. После определенных рассчетов необходимо вывести их результат на экран в виде окон.
3. Пользователь может корректировать результат или вносить поправки и рассчет продолжается.

Отредактировано 4kpt_II (Фев. 4, 2014 12:07:43)

Офлайн

#6 Фев. 4, 2014 16:36:50

Ryoga
Зарегистрирован: 2014-02-01
Сообщения: 20
Репутация: +  1  -
Профиль   Отправить e-mail  

возможно ли приостановить Tk.mainloop() ?

Ну это да, как-то упустил из виду В Text сохраняется история ввода-вывода,а в Label'ах промежуточные результаты отображаются, до кучи.

Офлайн

#7 Фев. 13, 2014 09:16:59

Xyanide
Зарегистрирован: 2014-02-11
Сообщения: 26
Репутация: +  0  -
Профиль   Отправить e-mail  

возможно ли приостановить Tk.mainloop() ?

Что-то вы путаете. Ничего функция mainloop не тормозит - создали кнопку, забиндили на окошко с Entry, вызвали его нажатием кнопки, ввели данные, вернули с помощью get().



Это просто какой-то Python!

Офлайн

#8 Фев. 13, 2014 10:11:28

4kpt_II
От: Харьков
Зарегистрирован: 2013-10-24
Сообщения: 999
Репутация: +  58  -
Профиль   Отправить e-mail  

возможно ли приостановить Tk.mainloop() ?

Вы не поняли вопроса. Имелось ввиду: "можно ли затормозить работу mainloop".

Офлайн

  • Начало
  • » GUI
  • » возможно ли приостановить Tk.mainloop() ?[RSS Feed]

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version