Шуман Х. - Python для детей - 2019. # Startwerte festlegen Red (255,0,0)
Скачать 5.95 Mb.
|
Глава Введение в tkinter 7 138 Ниже представлен исходный код этой версии программы (⇒ window2.py): from tkinter import * Window = Tk() Display = Label(Window, text="Привет, как дела?") Display.pack() Button1 = Button(Window, text="Хорошо") Button2 = Button(Window, text="Плохо") Button1.pack() Button2.pack() Window.mainloop() ¾ Введи код и запусти программу. Получилось ли у тебя окно, которое ты видел на рисунке выше? Здесь добавлены два экземпляра нового для тебя компонен- та Button, созданных и вставленных так же, как объект Label. Примечательно, что при использовании tkinter параметры име- ют одну «цель», которая характеризует их значение. Обычная функция или метод в Python выглядит, к примеру, так: print("Привет, как дела?") Параметр в tkinter передается функции print следующим об- разом: print(text=" Привет, как дела?") Порядок перечисления параметров соблюдать необязательно. В исходном коде есть еще пара изменений: в верхней его части я изменил инструкцию импорта. Строка from tkinter import * позволяет избежать постоянного указывания модуля tkinter при создании объектов. А внизу я добавил еще кое-что: mainloop() – это бесконеч- ный цикл, который предоставляет модуль tkinter. Почему именно такой цикл? Операционная система, такая как Windows, ориентирована на события. Это означает, что все, что происходит (будь то действия мыши, нажатия клавиш, открытие, закрытие или перемещение окон), считается событием (на англ. языке – Event). Что же происходит? 139 Цикл mainloop() аккумулирует все события, что важно для работы окна tkinter и его компонентов. Цикл бесконечен, поскольку не является условным, и он не останавливается, пока программа не завершит работу. Что же происходит? После запуска программы ты быстро разочаруешься, когда поймешь, что нажатие кнопки не приводит к какому-либо результату. Было бы неплохо, если бы, как в наших преды- дущих программах, появилось сообщение типа «Это ра- дует!» или «Это огорчает!» – в зависимости от того, какую кнопку ты нажал. Но как это сделать с двумя компонентами? Как ты видишь, они реагируют на щелчки мыши при нажатии кнопок. Нам нужны две функции или два метода, которые выполняются при таком щелчке мыши. В первую очередь на ум приходит конструкция if: if Button1.pressed : print("Это радует!") if Button2.pressed : print("Это огорчает!") К сожалению, нет такого события, как pressed, но есть воз- можность связать кнопку с функцией в самом начале (разуме ется, в одной строке): Button1 = Button(Window, text="Хорошо", command = buttonClick1()) Button2 = Button(Window, text="Плохо", command = buttonClick2()) Параметр command связывает кнопку с функцией, выполня- ющейся, как только с кнопкой «что-то происходит», в част- ности ее нажатие. Поэтому нам нужно запрограммировать две функции: def button1Click() : print("Это радует!") def button2Click() : print("Это огорчает!") Как только событие иниицируется щелчком мыши по одной из кнопок, выполняется функция, связанная с по мощью ключевого слова command (рис. 7.4). Введение в tkinter 7 140 Хорошо Плохо «Это радует!» «Это огорчает!» buttonClick1() buttonClick2() command = command = Рис. 7.4.Схема работы кода программы Давай соберем все это вместе. Ниже представлен полный код программы (⇒ window3.py). # Окно с событиями from tkinter import * # Функция для события def button1Click() : print("Это радует!") def button2Click() : print("Это огорчает!") # Основная программа Window = Tk() Display = Label(Window, text="Привет, как дела?") Display.pack() Button1 = Button(Window, text="Хорошо", command=button1Click) Button2 = Button(Window, text="Плохо", command=button2Click) Button1.pack() Button2.pack() Window.mainloop() ¾ Измени исходный код, помня, что оба события должны быть в одной строке со словом command. ¾ Запусти программу и нажми по очереди каждую кноп- ку (если хочешь, нажми несколько раз) (рис. 7.5). Рис. 7.5.Результат работы программы Что же происходит? 141 Результат отобразится в окне среды Python. А я бы пред- почел видеть все в нашем окне tkinter. Давай посмотрим, как это сделать. Например, мы могли бы взять компонент Label с текстом «Привет, как дела?». Как только нажимается кнопка, содержимое метки Label можно заменить на дру- гой подходящий текст. Так мы получим следующую версию программы (⇒ window4.py): # Окно с событиями from tkinter import * # Функция для события def button1Click() : Display.config(text="Это радует!") def button2Click() : Display.config(text="Это огорчает!") # Основная программа Window = Tk() Display = Label(Window, text="Привет, как дела?") Display.pack() Button1 = Button(Window, text="Хорошо", command=button1Click) Button2 = Button(Window, text="Плохо", command=button2Click) Button1.pack() Button2.pack() Window.mainloop() Метод config() может использоваться для изменения свойств компонента, например текста, отображаемого меткой Label : Display.config(text="Это радует!") Display.config(text="Это огорчает!") ¾ Обнови код программы и запусти ее. Несколько раз на- жми каждую кнопку (рис. 7.6). Рис. 7.6.Доработанная версия программы Глава Введение в tkinter 7 142 Разметка интерфейса программы Все неплохо, но и не хорошо. Мне не нравится расположе- ние компонентов, они слишком сильно сжаты в окне. Мы должны сейчас это проработать. Причина в том, что раз- метка интерфейса контролируется методом pack(). Модуль tkinter предлагает три разные разметки интерфейса: pack() Компоненты автоматически размещаются как можно более компактно place() Компоненты могут быть расположены точно, их размер можно настроить grid() Компоненты распределяются по невидимой сетке в окне Вариант pack() – наиболее удобное решение, но, к сожале- нию, не самое красивое. Ты также можешь передать пара- метры этому методу, чтобы изменить разметку. К примеру, так можно разместить кнопки далеко друг от друга, а не ря- дом: Button1.pack(side="left") Button2.pack(side="right") Теперь окно выглядит так, как показано на рис. 7.7. Рис. 7.7.Кнопки выровнены по левому и правому краям Неплохое улучшение, но не слишком значимое. Посмот- рим, как работает метод place(). В этом случае мы должны указывать определенные числовые значения. Попробуй прямо сейчас с новой версией программы (⇒ window5.py). from tkinter import * def button1Click() : Display.config(text="Это радует!") def button2Click() : Display.config(text="Это огорчает!") Window = Tk() Разметка интерфейса программы 143 Window.config(width=260, height=120) Display = Label(Window, text="Привет, как дела?") Display.place(x=50, y=20, width=160, height=30) Button1 = Button(Window, text="Хорошо", command=button1Click) Button2 = Button(Window, text="Плохо", command=button2Click) Button1.place(x=20, y=70, width=100, height=30) Button2.place(x=140, y=70, width=100, height=30) Window.mainloop() ¾ Если ты введешь это и запустишь программу, результат будет выглядеть так, как показано на рис. 7.8. Рис. 7.8.Дизайн программы стал намного лучше Совершенно точно лучше, чем предыдущие варианты. Да- вай подробнее рассмотрим изменения. Во-первых, я уста- новил размер окна с помощью инструкции config: Window.config(width=260, height=120) С помощью модуля tkinter размеры окна можно определить двумя способами: Window.config(width=400, height=300) или Window.config(height=300, width=400) Такой подход недоступен в классической версии Python. После создания компонентов и кнопок в интерфейсе я ис- пользую три инструкции place для определения местополо- жения и размера элементов: Display.place(x=50, y=20, width=160, height=30) Button1.place(x=20, y=70, width=100, height=30) Button2.place(x=140, y=70, width=100, height=30) Глава Введение в tkinter 7 144 С помощью значений переменных x и y я определяю по- зицию верхнего левого угла каждого компонента, а осталь- ные параметры настраивают их ширину и высоту. Отличный пример, как в tkinter используются параметры. Вы- глядит необычно, так как порядок произволен, а в классическом коде Python должен соблюдаться определенный порядок. Таким образом, ты можешь оформлять функцию place() как угодно, на- пример так: Button1.place(height=30, width=100, x=20, y=70) Честно говоря, аналогичного результата с помощью мето- да grid достичь сложнее. Взгляни на исходный код (⇒ win dow6.py): Window = Tk() Display = Label(Window, text="Привет, как дела?") Display.grid(row=0, column=1) Button1 = Button(Window, text="Хорошо", command=button1Click) Button2 = Button(Window, text="Плохо", command=button2Click) Button1.grid(row=2, column=0, padx=10, pady=10) Button2.grid(row=2, column=2, padx=10, pady=10) Window.mainloop() На область окна накладывается невидимая сетка, ячей- ки которой необязательно должны быть одного размера (рис. 7.9). Привет, как дела? Хорошо Плохо row=0 row=1 column=0 column=1 column=2 Рис. 7.9.Компоновка на основе сетки С помощью параметра row ты определяешь строки, а с по- мощью column – столбцы (нумерация начинается с 0). С по- мощью параметров padx и pady определяется, какое расстоя- ние будет слева направо (x) и сверху вниз (y). Существует еще параметр sticky: в случае его использования компонент может быть выровнен по указанному краю ячейки: например, sticky=E выравнивает кнопку в крайнем правом углу Диалоговые окна и заголовки 145 ячейки, sticky=W – в крайнем левом углу. Используются первые буквы четырех направлений света (на английском языке, т. е. W (запад), N (север), E (восток) и S (юг)). Кроме того, с помощью кода Display.grid(row=0, column=0, columnspan=2) один компонент может занимать две ячейки. ¾ Для закрепления материала поэкспериментируй со значениями, чтобы понять тонкости разметки интер- фейса. Диалоговые окна и заголовки Я также хотел бы рассмотреть в этой главе еще один способ отображения ответов программы. Для этого строки import недостаточно, нам нужно отдельно импортировать класс, который мы будем использовать: from tkinter import * from tkinter import messagebox Под диалоговым окном понимается небольшое окно, в кото- ром отображаются сообщения. Также это может быть диа- логовое окно предупреждения или ошибки и, конечно же, содержащее сообщение об успешном результате. В определении двух функций для событий я теперь заме- няю код для отображения текста в виде сообщения, а не метки (⇒ window7.py): def button1Click() : messagebox.showinfo("Ответ", "Это радует!") def button2Click() : messagebox.showinfo("Ответ", "Это огорчает!") Метод showinfo() позволяет вывести на экран указанный текст. Первый параметр определяет строку заголовка, а второй – текст в диалоговом окне. ¾ Если ты поместишь этот код в свою программу и за- пустишь ее, то увидишь сообщение в дополнитель- ном окне, которое закрывается нажатием кнопки ОК (рис. 7.10). Глава Введение в tkinter 7 146 Рис. 7.10.Дополнительные диалоговые окна В этом случае следует также рассказать, как задать глав- ному окну заголовок (который до сих пор содержал буквы «tk»). Все, что тебе нужно сделать, – это добавить следую- щую строку кода: Window.title("Привет") Window.config(width=260, height=120) Я также указал здесь строку, в которой определены разме- ры окна. Если ты не определишь их, окно может быть слиш- ком маленькое, и ты увидишь лишь часть заголовка. Для длинного заголовка окно должно быть шире (рис. 7.11). Рис. 7.11.Окно с заголовком Поскольку слово «Привет» теперь находится в строке заго- ловка, высоту окна можно уменьшить. А теперь с классами Освоив классы в предыдущей главе, ты, возможно, задался вопросом: а где классы в этой главе? Возможно, ты даже захочешь узнать, как код нашей программы-приветствия будет выглядеть в случае применения классов. Ниже пред- ставлен полный исходный код такого варианта (⇒ win dow8.py): А теперь с классами 147 # Разметка окна from tkinter import * class Dialog() : # Инициализация def __init__(self, Title) : self.Window = Tk() self.Window.title(Title) self.Window.config(width=260, height=120) self.Display = Label(self.Window, text="Как дела?") self.Display.place(x=50, y=20, width=160, height=30) self.Button1 = Button(self.Window, text="Хорошо", \ command=self.button1Click) self.Button2 = Button(self.Window, text="Плохо", \ command=self.button2Click) self.Button1.place(x=20, y=70, width=100, height=30) self.Button2.place(x=140, y=70, width=100, height=30) self.Window.mainloop() # Метод def button1Click(self) : self.Display.config(text="Это радует!") def button2Click(self) : self.Display.config(text="Это огорчает!") # Основная программа Window = Dialog("Привет") ¾ Напиши весь этот код и протестируй программу, про- исходит ли все то же самое, что и при запуске предыду- щих версий приложения (вновь обрати внимание, что однострочный код в этой книге записан в две строки). Я снова переключился на вывод текста в виде метки. В этом коде также много раз используется ключевое слово self. В противном случае все, что мы запрограммировали ранее, фактически будет относиться к классу Dialog. Метод _init_() определяет окно, ниже которого указываются методы событий. Основная программа получилась очень ко- роткой, поэтому мы можем не разбивать ее код на два файла. Размеется, метод init можно использовать так, чтобы при- менять больше параметров, а не только заголовок окна: def __init__(self, Title, Text, But1, But2) : Что привело бы к следующему вызову в основной прог- рамме: Глава Введение в tkinter 7 148 Window = Dialog("Привет", "Как дела?", "Хорошо", "Плохо") Подведение итогов Сейчас мы снова сделаем перерыв, прежде чем продолжить работу с модулем tkinter. На данный момент ты многое узнал . Подведем итоги этой главы: tkinter Модуль для графики, окон и компонентов Тк Класс главного окна mainloop() (Бесконечный) цикл событий Label Метка (текстовая) Button Кнопка MessageBox Окно сообщения showinfo() Отображение окна сообщений title() Строка заголовка главного окна config() Настройка компонента pack() Упаковка компонента Place() Точное размещение, определение размера компонента grid() Расположение компонентов на сетке Command= Ссылка на функцию/метод события height= Высота компонента width= Ширина компонента column= , row= Количество столбцов и строк сетки padx= , pady= Расстояние компонентов от краев сетки side= Расположение компонента в окне (слева или справа) sticky= Расположение компонента на краю (к основным направлениям) Несколько вопросов... 1. Какие компоненты модуля tkinter ты знаешь? 2. Как связаны компоненты и события? ...и одна задача 1. Создай программу-гороскоп, в которой есть кнопка для каждого знака зодиака и которая выводит короткое со- общение (например, месяц знака зодиака) после щелч- ка мышью. 149 8 Библиотека компонентов Теперь ты уже знаком с некоторыми важными компонен- тами, но tkinter предлагает гораздо больше. На самом деле ты мог бы использовать еще несколько элементов в окне. Программа-приветствие из прошлой главы предполагает еще некоторые возможности, которые ты скоро увидишь. Итак, в этой главе ты узнаешь: как использовать списки; о разнице между переключателями и флажками; что такое лямбда-выражения; еще о разметке интерфейса; о преимуществах использования рамок. Череда кнопок Давай еще раз взглянем на программу из предыдущей гла- вы. Возможны два ответа на вопрос: «Как дела?» Не так ли? Теперь мы должны мужественно расширить наш проект до шести кнопок. В табл. 8.1 ты найдешь мои варианты надпи- сей на кнопках и соответствующие варианты ответа: Глава Библиотека компонентов 8 150 Таблица 8.1. Варианты кнопок и ответов для программы Кнопка Результат Супер Это здорово! Хорошо Это радует! Так себе Все возможно. Плохо Это огорчает! Ужасно Это плохо! Не скажу Раз ты так думаешь... Таким образом программа сможет отреагировать на боль- шинство ответов пользователя. Порадоваться за него или посочувствовать. Придется довольно много набрать кода – фактически код программы меняется лишь в своем объеме. Поскольку в исходном коде, за исключением экранного текста, много повторений, для ускорения работы ты можешь использо- вать команды Copy (Копировать) и Insert (Вставить) в меню Edit (Правка). Или применять в Windows горячие сочетания клавиш: Ctrl+C и Ctrl+V. Понадобится изменить только несколько чисел и текст. ¾ Расширь свой (уже имеющийся) проект путем ввода следующего длинного кода. Убедись, что метка, кнопки и текст сообщения совпадают (⇒ hello3.py): from tkinter import * # Функция для события def button1Click() : Display.config(text="Это здорово!") def button2Click() : Display.config(text="Это радует!") def button3Click() : Display.config(text="Все возможно.") def button4Click() : Display.config(text="Это огорчает!") def button5Click() : Display.config(text="Это плохо!") def button6Click() : Display.config(text="Раз ты так думаешь ...") # Основная программа Window = Tk() Череда кнопок 151 Window.title("Привет!") Window.config(width=300, height=190) Display = Label(Window, text="Как это сделать?") Display.place(x=80, y=10, width=160, height=30) # Текст на кнопках Button1 = Button(Window, text="Супер", command=button1Click) Button2 = Button(Window, text="Хорошо", command=button2Click) Button3 = Button(Window, text="Так себе", command=button3Click) Button4 = Button(Window, text="Плохо", command=button4Click) Button5 = Button(Window, text="Ужасно", command=button5Click) Button6 = Button(Window, text="Не скажу", command=button6Click) # Позиционирование кнопок Button1.place(x=20, y=60, width=120, height=30) Button2.place(x=160, y=60, width=120, height=30) Button3.place(x=20, y=100, width=120, height=30) Button4.place(x=160, y=100, width=120, height=30) Button5.place(x=20, y=140, width=120, height=30) Button6.place(x=160, y=140, width=120, height=30) # Цикл событий Window.mainloop() В первую очередь обрати внимание, что определены шесть функций, обрабатывающих события, затем (в основной программе) в окне генерируется в общей сложности семь компонентов (1 метка, 6 кнопок). Кроме того, кнопки рас- положены парами. ¾ Теперь запусти программу и протестируй каждую кнопку (рис. 8.1). Рис. 8.1.Программа с шестью вариантами ответов Выглядит довольно громоздко. Но как быть, если понадо- бится значительно больше шести кнопок: явно возникнет хаос в исходном коде. Разве нет способа упростить это? |