Какая магия предотвращает блокировку программ Tkinter в интерактивной оболочке?

Примечание. Это несколько следующий вопрос по вопросу: Tkinter – когда мне нужно позвонить mainloop?

Обычно при использовании Tkinter вы вызываете Tk.mainloop для запуска цикла событий и убедитесь, что события правильно обработаны, а окна остаются интерактивными без блокировки.

При использовании Tkinter изнутри интерактивной оболочки запуск основного цикла не представляется необходимым. Возьмем следующий пример:

>>> import tkinter >>> t = tkinter.Tk() 

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

Итак, что-то в интерактивной оболочке, похоже, признает, что было создано окно и запускает цикл событий в фоновом режиме.

Теперь за интересную вещь. Возьмите пример сверху, но затем в следующем приглашении (без закрытия окна) введите что угодно – без его фактического выполнения (т. Е. Не нажимайте enter). Например:

 >>> t = tkinter.Tk() >>> print('Not pressing enter now.') # not executing this 

Если вы теперь попытаетесь взаимодействовать с окном Tk, вы увидите, что он полностью блокируется . Таким образом, цикл событий, который, как мы думали, будет работать в фоновом режиме, остановился, когда мы вводили команду в интерактивную оболочку. Если мы отправим введенную команду, вы увидите, что цикл событий продолжается, и все, что мы делали во время блокировки, будет продолжать обрабатываться.

Поэтому большой вопрос: что это за магия, которая происходит в интерактивной оболочке? Что работает основной цикл, когда мы не делаем это явно? И почему это нужно останавливать, когда мы вводим команды (вместо остановки при их выполнении)?

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

One Solution collect form web for “Какая магия предотвращает блокировку программ Tkinter в интерактивной оболочке?”

На самом деле это не является интерактивным интерпретатором, который имеет значение здесь, но ждет ввода в TTY. Вы можете получить такое же поведение из сценария, как это:

 import tkinter t = tkinter.Tk() input() 

(В Windows вам, возможно, придется запускать скрипт в pythonw.exe вместо python.exe, но в противном случае вам не нужно ничего делать особо.)


Итак, как это работает? В конечном счете, трюк сводится к PyOS_InputHook – так же, как работает модуль readline .

Если stdin является TTY, то каждый раз, когда он пытается получить строку с input() , различными битами модуля code , встроенным REPL и т. Д., Python вызывает любой установленный PyOS_InputHook вместо простого чтения из stdin.

Вероятно, легче понять, что делает readline : он пытается select stdin или аналогичный цикл для каждого нового символа ввода или каждые 0,1 секунды или каждый сигнал.

То, что делает Tkinter , похоже. Это сложнее, потому что он имеет дело с Windows, но на * nix он делает что-то очень похожее на readline . За исключением того, что он вызывает Tcl_DoOneEvent каждый раз через цикл.

И это ключ. Tcl_DoOneEvent вызов Tcl_DoOneEvent – это то же самое, что и mainloop .

(Конечно, нитки делают все более сложным, но предположим, что вы не создали никаких фоновых потоков. В вашем реальном коде, если вы хотите создать фоновые потоки, у вас будет только поток для всего материала Tkinter который блокирует mainloop любом случае, верно?)


Итак, если ваш код Python больше времени блокирует вход TTY (как обычно это делает интерактивный интерпретатор), интерпретатор Tcl прерывается, и ваш графический интерфейс отвечает. Если вы сделаете блок интерпретатора Python чем-то другим, кроме ввода TTY, интерпретатор Tcl не будет запущен и ваш графический интерфейс не будет отвечать.


Что делать, если вы хотите сделать то же самое вручную в чистом коде Python? Вам нужно будет сделать это, если хотите, например, интегрировать графический интерфейс Tkinter и сетевой клиент на основе select в однопоточное приложение, верно?

Это легко: проехать один цикл от другого.

Вы можете select с тайм-аутом 0.02s (тот же самый тайм-аут, который используется для использования по умолчанию для ввода), и вызывать t.dooneevent(Tkinter.DONT_WAIT) каждый раз через цикл.

Или, альтернативно, вы можете позволить Tk-накопителю вызвать mainloop , но использовать after и друзей, чтобы убедиться, что вы вызываете select достаточно часто.

  • Как остановить таймер в Python (tkinter)?
  • Полноэкранное приложение Tkinter
  • Как отключить управление мышью в списке Tkinter?
  • Возможно ли запустить только один шаг цикла событий asyncio
  • Функция обратного вызова tkinter с переменным параметром
  • Python Tkinter Label перерисовка каждые 10 секунд
  • Разница между импортированием tkinter как tk и из импорта tkinter
  • Tkinter IntVar возвращает PY_VAR0 вместо значения
  • Использование расширений TCL для установки стиля родного окна в Tkinter
  • Как подключить StringVar к текстовому виджету в Python / Tkinter?
  • Навигация между несколькими графическими интерфейсами Tkinter
  •  
    Interesting Posts for Van-Lav

    Хороший учебник PyQt необходим

    Python Преобразование температуры MVC: почему я получаю «TypeError: buttonPressed () отсутствует 1 обязательный позиционный аргумент:« self »

    Результат по модулю Python отличается от wolfram alpha?

    Django ImageField "Загрузите действительное изображение. Загруженный вами файл был либо не изображением, либо поврежденным изображением ».

    Год за год matplotlib с легендой

    Малина pi Python shebang с сервером cgi

    Не удается отправить электронную почту через python с помощью gmail – smtplib.SMTPException: расширение SMTP AUTH не поддерживается сервером

    Обнаружение вывода консоли javascript с помощью python

    Ничего не сохраняется в django non-rel для движка Google

    Использование MultilabelBinarizer в тестовых данных с метками, не входящими в набор тренировок

    Файл.open (readme) в setup.py не найден

    Всесторонний учебник для начинающих?

    Ошибка запроса Python / MySQL: `Неизвестный столбец`

    Могу ли я автоматически изменить свой PYTHONPATH при активации / деактивации virtualenv?

    Попытка подсчета слов в строке

    Python - лучший язык программирования в мире.