tkinter mainloop что это
Введение в Tkinter
Всем доброго времени суток!
Tkinter – это кроссплатформенная библиотека для разработки графического интерфейса на языке Python (начиная с Python 3.0 переименована в tkinter). Tkinter расшифровывается как Tk interface, и является интерфейсом к Tcl/Tk.
Tkinter входит в стандартный дистрибутив Python.
Весь код в этой статье написан для Python 2.x.
Чтобы убедиться, что Tkinter установлен и работает, воспользуемся стандартной функцией Tkinter _test():
После выполнения данного кода должно появиться следующее окно:
Отлично, теперь можно приступать к написанию нескольких простых программ для демонстрации основных принципов Tkinter.
Hello world
Конечно, куда же без него. Первым делом нам нужно создать главное окно, написав
Да-да, всего одна строка, это вам не WinAPI (=. Теперь создадим кнопку, при нажатии на которую будет выводиться текст в консоль:
Всё просто, не так ли? Создаём экземпляр класса Button, указываем родителя и при желании список параметров. Есть еще немало параметров, таких как шрифт, толщина рамки и т.д.
Затем привязываем к нажатию на кнопку событие (можно привязать несколько разных событий в зависимости, например, от того, какой кнопкой мыши был нажат наш btn.
mainloop() запускает цикл обработки событий; пока мы не вызовем эту функцию, наше окно не будет реагировать на внешние раздражители.
Упаковщики
Функция pack() — это так называемый упаковщик, или менеджер расположения. Он отвечает за то, как виджеты будут располагаться на главном окне. Для каждого виджета нужно вызвать метод упаковщика, иначе он не будет отображён. Всего упаковщиков три:
pack(). Автоматически размещает виджеты в родительском окне. Имеет параметры side, fill, expand. Пример:
grid(). Размещает виджеты на сетке. Основные параметры: row/column – строка/столбец в сетке, rowspan/columnspan – сколько строк/столбцов занимает виджет. Пример:
place(). Позволяет размещать виджеты в указанных координатах с указанными размерами.
Основные параметры: x, y, width, height. Пример:
Теперь для демонстрации других возможностей Tkinter, напишем простейший
Текстовый редактор
Без лишних слов приведу код:
Здесь есть несколько новых моментов.
Во-первых, мы подключили модуль tkFileDialog для диалогов открытия/закрытия файла. Использовать их просто: нужно создать объект типа Open или SaveAs, при желании задав параметр filetypes, и вызвать его метод show(). Метод вернёт строку с именем файла или пустую строку, если пользователь просто закрыл диалог.
Во-вторых, мы создали два фрейма. Фрейм предназначен для группировки других виджетов. Один содержит управляющие кнопки, а другой — поле для ввода текста и полосу прокрутки.
Это сделано, чтобы textbox не налезал на кнопки и всегда был максимального размера.
В-третьих, появился виджет Text. Мы его создали с параметром wrap=’word’, чтобы текст переносился по словам. Основные методы Text: get, insert, delete. Get и delete принимают начальный и конечный индексы. Индекс — это строка вида ‘x.y’, где x — номер символа в строке, а y — номер строки, причём символы нумеруются с 1, а строки — с 0. То есть на самое начала текста указывает индекс ‘1.0’. Для обозначения конца текста есть индекс ‘end’. Также допустимы конструкции вида ‘1.end’.
B в-четвёртых, мы создали полосу прокрутки (Scrollbar). После создания её нужно связать с нужным виджетом, в данном случае, с textbox. Связывание двустороннее:
Вот и всё. Tkinter – это, безусловно, мощная и удобная библиотека. Мы осветили не все её возможности, остальные — тема дальнейших статей.
Python Tkinter Mainloop with Examples
In this Python Tkinter tutorial, we will learn everything about Python Tkinter Mainloop. Also, we will cover these topics.
Python Tkinter Mainloop
Mainloop in Python Tkinter is an infinite loop of the application window which runs forever so that we can see the still screen.
Here is the code to implement the mainloop in Python Tkinter. mainloop() is always applied at the last line of the code.
Python Tkinter Mainloop Thread
Thread is the process that goes parallel with the program as a separate entity. In other words, by using thread we can run multiple things in the same program at the same time.
Python Tkinter Mainloop exit
Python Tkinter provides destroy() function using which we can exit the mainloop in Python Tkinter. destroy() function can be applied on parent window, frames, canvas, etc.
Here is the code to demonstrate Python Tkinter Mainloop Exit
In this code, we have created an Exit button that will close the window when clicked.
Here is the output of the above code to demonstrate Python Tkinter Mainloop Exit
In this output, mainloop exits when the exit button is clicked.
Python Tkinter Mainloop Blocking
The Mainloop() method plays a major role in Python Tkinter as it updates the Graphical User Interface(GUI) of the application every time an event occurs.
Here is the code to demonstrate the Python Tkinter Mainloop Blocking
In this code, we have created GUI (Tkinter) and terminal based application.
Output:
Python Tkinter Mainloop Non Blocking
In the previous section, we have seen Python Tkinter Mainloop Blocking. Now we will learn how to create a Python Tkinter Mainloop Non Blocking.
Here is the code to demonstrate the Python Tkinter Mainloop Non Blocking
In this code, we have created function that holds the code for terminal based application and this function is called using after function on line 18.
In this output, both terminal-based and GUI-based applications are running simultaneously. In this way, the mainloop is non-blocking the other applications.
Python Tkinter Mainloop Update
Update() method in mainloop in Python Tkinter is used to show the updated screen. It reflects the changes when an event occurs. In the below example we have demonstrated update() function in Python Tkinter.
Source code of Python Tkinter Mainloop Update Example
In this code, date, day and time is being displayed. This information is fetched from the system and the Tkinter window keeps on updating to display latest information.
Output of Python Tkinter Mainloop Update Example
In this output, Time is keep on changing and the updates are visible because we have applied update function on main window.
Python Tkinter Mainloop Event
In this section, we will learn about event in mainloop in Python Tkinter. Also, we see an example for the same.
Source code of Python Tkinter Mainloop Event Example
In this code, we have created 2 programs, one is gui-based and other is terminal-based. Out of these Terminal based triggers an event in every 2 seconds where as gui based application triggers when user clicks on the button. The thing to notice here is both are running parallel with out blocking the code.
Output for Python Tkinter Mainloop Event example
In this output, two events are occurring but mainloop is not blocking the code. You can see both Gui based and terminal based applications are running parallel.
Python Tkinter Mainloop Timer
Mainloop plays an important role in Python Tkinter as it displays updated information on the screen.
Python Tkinter Mainloop Background
In this section, we will learn how to run an application in the background using the mainloop in Python Tkinter.
You may like the following Python tkinter tutorials:
In this tutorial, we will learn everything about Python Tkinter Mainloop. Also, we will cover these topics.
Entrepreneur, Founder, Author, Blogger, Trainer, and more. Check out my profile.
Что такое Tkinter
Tkinter – это пакет для Python, предназначенный для работы с библиотекой Tk. Библиотека Tk содержит компоненты графического интерфейса пользователя (graphical user interface – GUI). Эта библиотека написана на языке программирования Tcl.
Под графическим интерфейсом пользователя (GUI) подразумеваются все те окна, кнопки, текстовые поля для ввода, скроллеры, списки, радиокнопки, флажки и др., которые вы видите на экране, открывая то или иное приложение. Через них вы взаимодействуете с программой и управляете ею. Все эти элементы интерфейса будем называть виджетами (widgets).
В настоящее время почти все приложения, которые создаются для конечного пользователя, имеют GUI. Редкие программы, подразумевающие взаимодействие с человеком, остаются консольными. В предыдущих двух курсах мы писали только консольные программы.
Существует множество библиотек GUI, среди которых Tk не самый популярный инструмент, хотя с его помощью написано немало проектов. Он был выбран для Python по-умолчанию. Установочный файл интерпретатора Питона обычно уже включает пакет tkinter в составе стандартной библиотеки.
Tkinter можно представить как переводчик с языка Python на язык Tcl. Вы пишете программу на Python, а код модуля tkinter переводит ваши инструкции на язык Tcl, который понимает библиотека Tk.
Программы с графическим интерфейсом пользователя событийно-ориентированные. Вы уже должны иметь представление о структурном и желательно объектно-ориентированном программировании. Событийно-ориентированное ориентировано на события. То есть та или иная часть программного кода начинает выполняться лишь тогда, когда случается то или иное событие.
Событийно-ориентированное программирование базируется на объектно-ориентированном и структурном. Даже если мы не создаем собственных классов и объектов, то все-равно ими пользуемся. Все виджеты – объекты, порожденные встроенными классами.
Tkinter импортируется стандартно для модуля Python любым из способов:
Если необходимо, узнать установленную версию Tk можно через константу TkVersion:
Чтобы написать GUI-программу, надо выполнить приблизительно следующее:
Создать главное окно.
Создать виджеты и выполнить конфигурацию их свойств (опций).
Определить события, то есть то, на что будет реагировать программа.
Описать обработчики событий, то есть то, как будет реагировать программа.
Расположить виджеты в главном окне.
Запустить цикл обработки событий.
Последовательность не обязательно такая, но первый и последний пункты всегда остаются на своих местах. Посмотрим все это в действии.
Устанавливать свойства объектов не обязательно при их создании. Существуют еще пара способов, с помощью которых это можно сделать после.
Первым аргументом в конструктор виджета передается виджет-хозяин, то есть тот, на котором будет располагаться создаваемый. В случае, когда элементы GUI помещаются непосредственно на главное окно, родителя можно не указывать. То есть в нашем примере мы можем убрать root :
Однако виджеты не обязательно располагаются на root ‘е. Они могут находиться на других виджетах, и тогда указывать «мастера» необходимо.
Пусть в программе текст, введенный человеком в поле, при нажатии на кнопку разбивается на список слов, слова сортируются по алфавиту и выводятся в метке. Выполняющий все это код надо поместить в функцию:
Теперь необходимо связать вызов функции с событием:
В любом приложении виджеты не разбросаны по окну как попало, а организованы, интерфейс продуман до мелочей и обычно подчинен определенным стандартам. Пока расположим элементы друг под другом с помощью наиболее простого менеджера геометрии tkinter – метода pack :
Метод mainloop экземпляра Tk запускает главный цикл обработки событий, что в том числе приводит к отображению главного окна со всеми «упакованными» на нем виджетами:
Полный код программы:
В результате выполнения данного скрипта появляется окно, в текстовое поле которого можно ввести список слов, нажать кнопку и получить его отсортированный вариант:
Теперь напишем сам класс Block:
Однако, если код будет выглядеть так, то необходимости в классе нет. Смысл появится, если нам потребуется несколько или множество похожих объектов-блоков. Допустим, нам нужно несколько блоков, состоящих из метки, кнопки, поля. Причем у кнопки каждой группы будет своя функция-обработчик клика.
Тогда можно передавать значения для свойства command в конструктор. Значение будет представлять собой привязываемую к кнопке функцию-обработчик события. Полный код программы:
При выполнения этого кода в окне будут выведены два однотипных блока, кнопки которых выполняют разные действия.
Класс можно сделать более гибким, если жестко не задавать свойства виджетов, а передавать значения как аргументы в конструктор, после чего присваивать их соответствующим опциям при создании объектов.
Практическая работа
Напишите простейший калькулятор, состоящий из двух текстовых полей, куда пользователь вводит числа, и четырех кнопок «+», «-«, «*», «/». Результат вычисления должен отображаться в метке. Если арифметическое действие выполнить невозможно (например, если были введены буквы, а не числа), то в метке должно появляться слово «ошибка».
Курс с примерами решений практических работ: android-приложение, pdf-версия.
Tkinter понимание mainloop
Однако, когда попытался сделать следующий шаг в этой программе (заставить шарик двигаться по времени), книга, из которой я читаю, говорит сделать следующее. Измените функцию рисования на:
И добавьте следующий код в мою программу:
В этот момент я должен упомянуть, что в моей книге никогда не говорится о tk.mainloop() (возможно, потому что он использует Python 3), но я узнал об этом при поиске в Интернете, поскольку мои программы не работали, копируя код книги!
3 ответа
Вы никогда не увидите вывод из оператора печати. Поскольку петли нет, мяч не двигается.
С другой стороны, методы update_idletasks() и update() здесь:
. не блокируй; выполнение продолжается после завершения этих методов, поэтому цикл while выполняется снова и снова, что заставляет мяч двигаться.
Тем не менее, tk.mainloop() не заменяет только строки:
Скорее, tk.mainloop() является заменой всего цикла while:
Ответ на комментарий:
Эта подкоманда update сбрасывает все запланированные в настоящий момент незанятые события из очереди событий Tcl. Неактивные события используются для того, чтобы отложить обработку до тех пор, пока «больше ничего не нужно делать», причем типичным вариантом использования для них являются перерисовка и пересчет геометрии Tk. Откладывая их до простоя Tk, дорогостоящие операции перерисовки не выполняются до тех пор, пока все на уровне кластера событий (например, отпускание кнопки, изменение текущего окна и т. Д.) Не будет обработано на уровне сценария. Это заставляет Tk казаться намного быстрее, но если вы находитесь в процессе выполнения длительной обработки, это также может означать, что неактивные события не обрабатываются в течение длительного времени. При вызове обновлений idletas, перерисовки из-за внутренних изменений состояния обрабатываются немедленно. (Перерисовки из-за системных событий, например, деиконифицированные пользователем, требуют полного обновления для обработки.)
APN Как описано в Обновлении, которое считается вредным, использование обновления для обработки перерисовок, не обрабатываемых задачами обновления, имеет много проблем. Джо Инглиш в сообщении comp.lang.tcl описывает альтернативу:
Поэтому update_idletasks() вызывает обработку некоторого подмножества событий, которое update() вызывает обработку.
Команда обновления используется, чтобы обновить приложение, вводя его в цикл событий Tcl до тех пор, пока не будут обработаны все ожидающие события (включая обратные вызовы в режиме ожидания).
Если в качестве аргумента команды указано ключевое слово idletasks, новые события или ошибки не обрабатываются; только пустые обратные вызовы вызываются. Это приводит к немедленному выполнению операций, которые обычно откладываются, таких как обновления отображения и вычисления макета окна.
Наиболее распространенные цели, для которых я рекомендовал [обновление], это: 1) Поддержание графического интерфейса пользователя во время выполнения некоторых длительных вычислений. Смотрите программу обратного отсчета для альтернативы. 2) Ожидание настройки окна, прежде чем выполнять такие операции, как управление геометрией. Альтернативой является привязка таких событий, как уведомление о процессе геометрии окна. См. Центрирование окна для альтернативы.
Что не так с обновлением? Есть несколько ответов. Во-первых, это усложняет код окружающего GUI. Если вы будете выполнять упражнения в программе обратного отсчета, вы почувствуете, насколько проще, когда каждое событие обрабатывается по своему собственному обратному вызову. Во-вторых, это источник коварных ошибок. Общая проблема заключается в том, что выполнение [update] имеет почти неограниченные побочные эффекты; по возвращении из [update] скрипт может легко обнаружить, что коврик был извлечен из-под него. Дальнейшее обсуждение этого явления в обновлении считается вредным.
Есть ли шанс, что я смогу заставить мою программу работать без цикла while?
Да, но все становится немного сложнее. Вы можете подумать, что будет работать что-то вроде следующего:
Проблема в том, что ball.draw () заставит выполнение войти в бесконечный цикл в методе draw (), поэтому tk.mainloop () никогда не будет выполняться, и ваши виджеты никогда не будут отображаться. В программировании графического интерфейса необходимо избегать бесконечных циклов любой ценой, чтобы виджеты реагировали на ввод данных пользователем, например щелчки мыши.
Итак, вопрос: как вы выполняете что-то снова и снова, фактически не создавая бесконечный цикл? У Tkinter есть ответ на эту проблему: метод after() виджета:
. (очень!) примерно похож на:
. который, как вы можете видеть, не сильно отличается от вашего собственного цикла while. Итак, зачем создавать свой собственный бесконечный цикл, когда у tkinter уже есть тот, который вы можете использовать?
Чтобы сделать это, конструктор объекта представления должен быть завершен до создания объекта окна. После создания и отображения окна я хотел автоматически выполнить некоторые начальные задачи с представлением. Сначала я попытался сделать их после mainloop (), но это не сработало, потому что mainloop () заблокирован!
Tkinter understanding mainloop
However, when tried the next step in this program (making the ball move by time), the book am reading from, says to do the following. So I changed the draw function to:
and add the following code to my program:
But I noticed that adding this block of code, made the use of tk.mainloop() useless, since everything would show up even without it.
At this moment I should mention that my book never talks about tk.mainloop() (maybe because it uses Python 3) but I learned about it searching the web since my programs didn’t work by copying book’s code!
So I tried doing the following that would not work.
3 Answers 3
tk.mainloop() blocks. It means that execution of your Python commands halts there. You can see that by writing:
You will never see the output from the print statement. Because there is no loop, the ball doesn’t move.
On the other hand, the methods update_idletasks() and update() here:
. do not block; after those methods finish, execution will continue, so the while loop will execute over and over, which makes the ball move.
However, tk.mainloop() is not a substitute for just the lines:
Rather, tk.mainloop() is a substitute for the whole while loop:
Response to comment:
Here is what the tcl docs say:
This subcommand of update flushes all currently-scheduled idle events from Tcl’s event queue. Idle events are used to postpone processing until “there is nothing else to do”, with the typical use case for them being Tk’s redrawing and geometry recalculations. By postponing these until Tk is idle, expensive redraw operations are not done until everything from a cluster of events (e.g., button release, change of current window, etc.) are processed at the script level. This makes Tk seem much faster, but if you’re in the middle of doing some long running processing, it can also mean that no idle events are processed for a long time. By calling update idletasks, redraws due to internal changes of state are processed immediately. (Redraws due to system events, e.g., being deiconified by the user, need a full update to be processed.)
APN As described in Update considered harmful, use of update to handle redraws not handled by update idletasks has many issues. Joe English in a comp.lang.tcl posting describes an alternative:
So update_idletasks() causes some subset of events to be processed that update() causes to be processed.
The update command is used to bring the application “up to date” by entering the Tcl event loop repeatedly until all pending events (including idle callbacks) have been processed.
If the idletasks keyword is specified as an argument to the command, then no new events or errors are processed; only idle callbacks are invoked. This causes operations that are normally deferred, such as display updates and window layout calculations, to be performed immediately.
The commonest purposes for which I’ve seen [update] recommended are:
What’s wrong with update? There are several answers. First, it tends to complicate the code of the surrounding GUI. If you work the exercises in the Countdown program, you’ll get a feel for how much easier it can be when each event is processed on its own callback. Second, it’s a source of insidious bugs. The general problem is that executing [update] has nearly unconstrained side effects; on return from [update], a script can easily discover that the rug has been pulled out from under it. There’s further discussion of this phenomenon over at Update considered harmful.
Is there any chance I can make my program work without the while loop?
Yes, but things get a little tricky. You might think something like the following would work:
The problem is that ball.draw() will cause execution to enter an infinite loop in the draw() method, so tk.mainloop() will never execute, and your widgets will never display. In gui programming, infinite loops have to be avoided at all costs in order to keep the widgets responsive to user input, e.g. mouse clicks.
So, the question is: how do you execute something over and over again without actually creating an infinite loop? Tkinter has an answer for that problem: a widget’s after() method: