Виджеты Button, Label, Entry
В этом уроке рассмотрим подробнее три наиболее простых и часто используемых виджета GUI – кнопку, метку и однострочное текстовое поле. В tkinter объекты этих элементов интерфейса порождаются соответственно от классов Button , Label и Entry .
Свойства и методы виджетов бывают относительно общими, характерными для многих типов, а также частными, зачастую встречающимися только у какого-то одного класса. В любом случае список настраиваемых свойств велик. В этом курсе мы будем рассматривать только ключевые свойства и методы классов пакета tkinter .
В Tkinter существует три способа конфигурирования свойств виджетов:
- в момент создания объекта,
- с помощью метода config , он же configure ,
- путем обращения к свойству как к элементу словаря.
Button – кнопка
Самыми важными свойствами виджета класса Button являются text , с помощью которого устанавливается надпись на кнопке, и command для установки действия, то есть того, что будет происходить при нажатии на кнопку.
По умолчанию размер кнопки соответствует ширине и высоте текста, однако с помощью свойств width и height эти параметры можно изменить. Единицами измерения в данном случае являются знакоместа (количество символов).
Такие свойства как bg , fg , activebackground и activeforeground определяют соответственно цвет фона и текста, цвет фона и текста во время нажатия и установки курсора мыши над кнопкой.
from tkinter import * def change(): b1['text'] = "Изменено" b1['bg'] = '#000000' b1['fg'] = '#ffffff' b1['activebackground'] = '#555555' b1['activeforeground'] = '#ffffff' root = Tk() b1 = Button(text="Изменить", width=15, height=3) b1.config(command=change) b1.pack() root.mainloop()
Здесь значение свойства command устанавливается с помощью метода config . Однако можно было сделать и так: b1[‘command’] = change . Вот так будет выглядеть кнопка после запуска программы и после нажатия на нее:
Label – метка
Виджет Label просто отображает текст в окне и служит в основном для информационных целей (вывод сообщений, подпись других элементов интерфейса). Свойства метки во многом схожи с таковыми у кнопки. Однако у меток нет опции command . Поэтому связать их с событием можно только с помощью метода bind .
На примере объекта типа Label рассмотрим свойство font – шрифт.
from tkinter import * root = Tk() l1 = Label(text="Машинное обучение", font="Arial 32") l2 = Label(text="Распознавание образов", font=("Comic Sans MS", 24, "bold")) l1.config(bd=20, bg='#ffaaaa') l2.config(bd=20, bg='#aaffff') l1.pack() l2.pack() root.mainloop()
Значение шрифта можно передать как строку или как кортеж. Второй вариант удобен, если имя шрифта состоит из двух и более слов. После названия шрифта можно указать размер и стиль.
Также как font свойство bd есть не только у метки. С его помощью регулируется размер границ. Здесь единицей измерения является пиксель.
Бывает, что метки и кнопки не присваивают переменным, если потом к ним в коде не приходится обращаться. Их создают от класса и сразу размещают:
from tkinter import * def take(): lab['text'] = "Выдано" root = Tk() Label(text="Пункт выдачи").pack() Button(text="Взять", command=take).pack() lab = Label(width=10, height=1) lab.pack() root.mainloop()
В данном примере только у одной метки есть связь с переменной, так как одно из ее свойств может быть изменено в процессе выполнения программы.
Entry – однострочное текстовое поле
Текстовые поля предназначены для ввода информации пользователем. Однако нередко также для вывода, если предполагается, что текст из них будет скопирован. Текстовые поля как элементы графического интерфейса бывают однострочными и многострочными. В tkinter вторым соответствует класс Text , который будет рассмотрен позже.
Свойства экземпляров Entry во многом схожи с двумя предыдущими виджетами. А вот методы – нет. Из текстового поля можно взять текст. За это действие отвечает метод get . В текстовое поле можно вставить текст методом insert . Также можно удалить текст методом delete .
Метод insert принимает позицию, в которую надо вставлять текст, и сам текст. Такой код
from tkinter import * from datetime import datetime as dt def insert_time(): t = dt.now().time() e1.insert(0, t.strftime('%H:%M:%S ')) root = Tk() e1 = Entry(width=50) but = Button(text="Время", command=insert_time) e1.pack() but.pack() root.mainloop()
приведет к тому, что после каждого нажатия на кнопку будет вставляться новое время перед уже существующей в поле строкой.
Если 0 в insert заменить на константу END , то вставляться будет в конец. Можно указать любое число-индекс знакоместа, тогда вставка будет производиться куда-либо в середину строки.
Метод delete принимает один или два аргумента. В первом случае удаляется один символ в указанной позиции. Во втором – срез между двумя указанными индексами, не включая последний. Если нужно полностью очистить поле, то первым аргументом должен быть 0, вторым – END .
Практическая работа
Напишите программу, состоящую из семи кнопок, цвета которых соответствуют цветам радуги. При нажатии на ту или иную кнопку в текстовое поле должен вставляться код цвета, а в метку – название цвета.
Коды цветов в шестнадцатеричной кодировке: #ff0000 – красный, #ff7d00 – оранжевый, #ffff00 – желтый, #00ff00 – зеленый, #007dff – голубой, #0000ff – синий, #7d00ff – фиолетовый.
Примерно должно получиться так:
Для выравнивания строки по центру в текстовом поле используется свойство justify со значением CENTER .
Курс с примерами решений практических работ: pdf-версия
X Скрыть Наверх
Tkinter. Программирование GUI на Python
Python.Tkinter. Как назначить команду на кнопку в цикле, считывая данные из json-файла? [дубликат]
В цикле считывается файл settings.json с категориями. Создаются окна, количество которых равно количеству словарей массива. Во внутреннем цикле создаются кнопки. Причём, в каждом окне кнопкам задаётся определённое имя из словаря. Проблема заключается в том, что в bind посылается лишь последнее имя команды — thunar . То есть, все кнопки вызывают thunar . Как это исправить? Программа:
#-*-coding:utf-8-*-# from tkinter import * import json for category in json.load(open('settings.json')): topwindow = Toplevel() stuff = [] for apps in category['apps']: stuff.append(apps['command']) button1 = Button(topwindow,text=apps['name']) button1.bind("",lambda e: print(apps['command'])) button1.pack(fill='both') print("name: command: ".format(apps['name'],apps['command'])) topwindow.mainloop()
settings.json:
Отслеживать
задан 21 мая 2016 в 21:41
CockLobster CockLobster
446 1 1 золотой знак 11 11 серебряных знаков 26 26 бронзовых знаков
Похожий вопрос: Why results of map() and list comprehension are different?
22 мая 2016 в 14:38
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
В вашем коде callback-функция всегда обращалась к переменной apps , которая имела значение, присвоенное в последней итерации цикла, это и вызывало всегда одно и тоже значение. Для решения задачи можно использовать значение аргумента функции по умолчанию.
Также нет смысла создавать ссылку на объект кнопки, которая будет перезаписана при каждой итерации.
#-*-coding:utf-8-*-# from tkinter import * import json Tk().withdraw() # блокируем отрисовку главного окна for category in json.load(open('settings.json')): topwindow = Toplevel() stuff = [] for apps in category['apps']: stuff.append(apps['command']) cmd = lambda e=apps['command']: print(e) # задаем значение аргумента по умолчанию Button(topwindow, text=apps['name'], command=cmd).pack(fill='both') print("name: command: ".format(apps['name'],apps['command'])) topwindow.mainloop()
Структура приложения и работа с кнопкам / tkinter 1
Одно из главных преимуществ создания приложения с Tkinter в том, что с его помощью очень просто настроить интерфейс всего в несколько строк. И если программа становится сложнее, то и сложнее логически разделять ее на части, а организованная структура помогает сохранять код в чистом виде.
Простой пример
Возьмем в качестве примера следующую программу:
from tkinter import * root = Tk()
btn = Button(root, text="Нажми!")
btn.config(command=lambda: print("Привет, Tkinter!"))
btn.pack(padx=120, pady=30)
root.title("Мое приложение Tkinter")
root.mainloop()Она создает окно с кнопкой, которая выводит Привет, Tkinter! каждый раз при нажатии. Кнопка расположена с внутренним отступом 120px по горизонтальной оси и 30px – по вертикальной. Последняя строка запускает основной цикл, который обрабатывает все пользовательские события и обновляет интерфейс до закрытия основного окна.
Программу можно запустить, чтобы убедиться, что она работает. Все переменные определяются в глобальном пространстве имен, и чем больше виджетов добавляется, тем сложнее разобраться в том, какие части они используют.
Wildcard-импорты ( from … import * ) считаются плохой практикой, поскольку они загрязняют глобальное пространство имен. Здесь они используются для иллюстрации анти-паттерна, который часто встречается в примерах онлайн.
Эти проблемы настройки решаются с помощью базовых техник объектно-ориентированного программирования, что считается хорошей практикой для любых типов программ на Python.
Правильный пример
Чтобы улучшить модуль простой программы, стоит определить несколько классов, которые станут обертками вокруг глобальных переменных:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.btn = tk.Button(self, text="Нажми!",
command=self.say_hello)
self.btn.pack(padx=120, pady=30)
def say_hello(self):
print("Привет, Tkinter!")
if __name__ == "__main__":
app = App()
app.title("Мое приложение Tkinter")
app.mainloop()Теперь каждая переменная хранится в конкретной области видимости, включая функцию command , которая находится в отдельном методе.
Как работает это приложение?
Во-первых нужно заменить wildcard-импорт на импорт в формате import … as для лучшего контроля над глобальным пространством имен.
Затем класс App определяется как подкласс Tk , который теперь ссылается на пространство имен tk . Для правильной инициализации базового класса, вызывается метод __init__() класса Tk с помощью встроенной функции super() . За это отвечают следующие строки:
class App(tk.Tk):
def __init__(self):
super().__init__()
# .Теперь есть ссылка на экземпляр App с переменной self . Так что виджет кнопки будет добавлен как атрибут класса.
Это может казаться излишним для такой простой программы, но подобный рефакторинг помогает работать с каждой отдельной частью. Создание кнопки отделено от обратного вызова, которые исполняется при нажатии. А генерация приложения перемещена в if __name__ == "main" , что является стандартной практикой для исполняемых скриптов в Python.
Такой же принцип будет использовать в примерах и дальше, поэтому его можно взять как шаблон-стартовая точка для крупных приложений.
Дополнение о структуре приложения
Класс Tk вынесен в отдельный класс в примере, но распространенной практикой считается выделять так же другие классы виджетов. Это делается для воссоздания тех же инструкций, которые были до рефакторинга.
Однако может быть более удобно разделять классы Frame или Toplevel особенно для больших программ, где, например, есть несколько окон. Это все потому что у приложения Tkinter должен быть один экземпляр Tk , а система создает их автоматически при создании экземпляра виджета до создания экземпляра самого Tk .
Помните, что это не влияет на структуру класса App , поскольку у всех классов виджетов есть метод mainloop , который запускает основной цикл Tk .
Работа с кнопками
Виджеты кнопок представляют собой кликабельные элементы графического интерфейса приложений. Они обычно используют текст или изображение, указывающие на то, какое действие будет выполнено при нажатии. Tkinter позволяет легко настраивать их функциональность с помощью стандартных настроек класса виджета Button .
Как создать кнопку
Следующий блок содержит кнопку с изображением, которая выключается при нажатии, а также список кнопок с разными типами анимации после нажатия:
import tkinter as tk
RELIEFS = [tk.SUNKEN, tk.RAISED, tk.GROOVE, tk.RIDGE, tk.FLAT]
class ButtonsApp(tk.Tk):
def __init__(self):
super().__init__()
self.img = tk.PhotoImage(file="python.gif")
self.btn = tk.Button(self, text="Кнопка с изображением",
image=self.img, compound=tk.LEFT,
command=self.disable_btn)
self.btns = [self.create_btn(r) for r in RELIEFS]
self.btn.pack()
for btn in self.btns:
btn.pack(padx=10, pady=10, side=tk.LEFT)def create_btn(self, relief):
return tk.Button(self, text=relief, relief=relief)def disable_btn(self):
self.btn.config(state=tk.DISABLED)if __name__ == "__main__":
app = ButtonsApp()
app.mainloop()Цель программы — показать разные варианты настройки, которые могут быть использованы при создании виджета кнопки.
После выполнения кода выше, возвращается следующее:
Простейший способ создания экземпляра Button — использование параметра text для настройки метки кнопки и command , который ссылается на вызываемую функцию при нажатии кнопки.
В этом примере также добавляется PhotoImage с помощью параметра image , который имеет приоритет над строкой text . Этот параметр используется для объединения изображения и текста на одной кнопке, определяя местоположение, где будет находиться картинка. Он принимает следующие константы: CENTER, BOTTOM, LEFT, RIGHT и TOP.
Второй ряд кнопок создается с помощью сгенерированного списка и списка значений RELIEF . Метка каждой кнопки соответствует константе, так что можно заметить разницу во внешнем виде.
Для сохранения ссылки на экземпляр PhotoImage использовался атрибут, хотя его и нет вне метода __init__ . Причина в том, что изображения удаляются при сборке мусора. Это и происходит, если объявить их в качестве локальных переменных.
Для избежания этого нужно помнить о сохранении ссылки на каждый объект PhotoImage до тех пор, пока окно, где он показывается, не закрыто.
Следующий урок: Работа с текстом (в разработке)
Руководство по модулю клавиатуры Python
Python является одним из наиболее подходящих языков для автоматизации задач. Будь то повторяемый (этический) веб-скоб через некоторое время, запуск некоторых программ при запуске компьютера или автоматизацию отправки повседневных электронных писем, Python имеет много модулей, которые облегчают вашу жизнь.
Одним из них является модуль под названием keyboard, который полностью контролирует вашу клавиатуру. С помощью данного модуля вы можете печатать что угодно, создавать горячие клавиши, сокращения, блокировать клавиатуру, ждать ввода и т. д.
В этом руководстве мы рассмотрим, как настроить и использовать модуль клавиатуры в Python.
Примечание: Приложения, работающие с автоматизацией человекоподобных процессов, должны разрабатываться этично и ответственно. Модуль клавиатуры сделан так, чтобы быть очень заметным, и, таким образом, делает его одновременно обескураживающим и прозрачным, если кто-то использует его для создания клавиатурных шпионов или вредоносных ботов.
Установка модуля клавиатуры
Версия Python, используемая в этом руководстве, равна 3.8. Однако модуль клавиатуры может работать как с Python 2.x, так и с Python 3.x.
Если вы используете Linnux, чтобы использовать эту библиотеку, вы должны установить ее от root. Если вы этого не сделаете, вы получите:
ImportError: You must be root to use this library on linux.
Кроме того, при запуске сценария вы должны запускать его с правами суперпользователя:
$ sudo pip3 install keyboard $ sudo python3 my_script.py
В Windows и macOS, поскольку привилегии работают совсем по-другому - вы можете установить его просто через pip и запустить сценарии:
$ pip install keyboard $ python my_script.py
Примечание: Для MacOS вам, возможно, придется разрешить терминалу или другим приложениям изменять состояние вашей машины, например, путем ввода текста. Также имейте в виду, что по состоянию на сентябрь 2021 года библиотека все еще находится в экспериментальном состоянии на MacOS.
Функция модуля клавиатуры
В этом модуле есть много функций, которые можно использовать для имитации действий клавиатуры.
- keyboard.write(message, [delay])- пишет сообщение с задержкой или без нее.
- keyboard.wait(key) - блокирует программу до тех пор, пока не будет нажата клавиша. Ключ передается в виде строки ("пробел", "esc" и т.д.)
- keyboard.press(key)- нажимает клавишу и удерживается до вызова функции release(key)
- keyboard.release(key)- выпускает ключ.
- keyboard.send(key)- нажимает и отпускает клавишу.
- keyboard.add_hotkey(hotkey, function)- создает hotkey, которая при нажатии выполняет function.
- keyboard.record(key)- записывает активность клавиатуры до нажатия key.
- keyboard.play(recorded_events, [speed_factor]) - воспроизводит события, записанные with keyboard.record(key) функция, с дополнительным speed_factor.
Тем не менее, мы рассмотрим все это. Вот быстрый пример:
>>> import keyboard >>> keyboard.write("Hello") >>> Hello
Приветственное сообщение появляется на экране в терминале, как будто вы его написали. Вы можете очень легко автоматизировать команду и создать для нее псевдоним горячей клавиши. Вот (грубый) пример выхода из REPL Python, написания команды curl:
>>> import keyboard >>> keyboard.write("exit()"); keyboard.send("enter"); keyboard.write("curl https://www.google.com"); keyboard.send("enter"); >>> exit() curl https://www.google.com $ curl https://www.google.com
Функции write() и wait() клавиатуры
Команда write() записывает сообщение, как мы видели ранее, с необязательной задержкой при запуске. Если задержка не установлена, запись выполняется мгновенно. Это очень хорошо сочетается с функцией wait (), которая ожидает нажатия определенной клавиши.
Например, мы можем создать импровизированный макрос, привязанный, скажем, к 1, который отвечает на этот ввод новым сообщением. Обратите внимание, что вместо этого есть фактический способ создания горячих клавиш, который мы рассмотрим позже.
Мы создадим бесконечный цикл True, чтобы проверить, нажата ли клавиша, и вы можете запустить сценарий в фоновом режиме:
import keyboard while True: keyboard.wait("1") keyboard.write("\n The key '1' was pressed!")
Примечание: Специальные символы не поддерживаются этой функцией, поэтому, если вы добавите, скажем, ! - вы получите исключение остановки.
Функции клавиши press() и release()
Поскольку сложно имитировать press () и release(), чтобы действия были видны, мы также увидим в действии record() и play() .
Функция press() нажимает клавишу и отпускает ее, когда вы вызываете release() на той же клавише.
>>> import keyboard >>> from time import sleep >>> keyboard.press("a") >>> sleep(1) >>> keyboard.release("a") >>> a
Тем не менее, вы можете удерживать некоторые специальные клавиши, такие как [SHIFT] или [CTRL] следующим образом:
>>> keyboard.press("shift") >>> keyboard.write("lowercase") >>> keyboard.release("shift") >>> LOWERCASE
Функции клавиатуры record() и play()
Речь не всегда идет о вводе новых клавиш - иногда вы хотите записать происходящий и воспроизвести это. Имейте в виду, что вам понадобятся права администратора для записи любого подобного ввода, так как технология может быть легко использована для создания кейлоггеров.
Функция record() принимает ключ запуска, до которого она записывает, и возвращает последовательность событий типа KeyboardEvent. Затем вы можете поместить эту последовательность событий в функцию play(), которая точно воспроизводит их, с дополнительным аргументом speed_factor. Он действует как множитель скорости исходных событий:
import keyboard recorded_events = keyboard.record("esc") keyboard.play(recorded_events)
Если мы напечатаем recorded_events, они будут выглядеть примерно так:
KeyboardEvent(w up), KeyboardEvent(o down), . ]
Функция клавиатуры send()
Функция send() включает в себя press () и release () вместе и используется для отдельных клавиш, в отличие от функции write(), которая используется для целых предложений:
import keyboard recorded_events = keyboard.record("s") keyboard.send("w") keyboard.send("a") keyboard.play(recorded_events)
После нажатия клавиши s воспроизводятся клавиши w и a.
Функция press() также может принимать комбинации нажатых клавиш. Вы можете отправить комбинацию "ctrl + shift + s", например, и должен появиться диалог для сохранения файла, если вы находитесь в приложении, которое поддерживает эту операцию:
import keyboard while True: keyboard.wait("s") keyboard.press("ctrl+shift+s") # Or for MacOS keyboard.press("command+shift+s)
Хотя это неправильный способ добавить горячие клавиши. Также вы можете использовать функцию add_hotkey().
Функция клавиатуры add_abreviation()
Функция add_abbreviation() является довольно изящной, так как она позволяет определять сокращения для длинных входных данных и заменяет сокращенные версии сохраненными полными версиями.
Например, подобно тому, как такие службы, как Google, сохраняют вашу электронную почту для большинства форм ввода, вы можете создать свою собственную аббревиатуру и запустить ее через [SPACE]:
>>> import keyboard >>> keyboard.add_abbreviation("@", "john@stackabuse.com")
Во время выполнения, если вы введете @, за которым следует [ПРОБЕЛ] - ввод в длинной форме заменит введенный @.
Функция клавиатуры add_hotkey()
Функция add_hotkey() принимает горячую клавишу, которую вы хотите сохранить, или комбинацию клавиш и функцию. Здесь легко передать анонимные лямбда-функции, хотя вы также можете добавить именованные функции.
Например, давайте добавим горячую клавишу для CTRL+j, которая запускает лямбда-функцию, регистрирующей это:
import keyboard keyboard.add_hotkey("ctrl+alt+j", lambda: print("ctrl+alt+j was pressed"))
Горячая клавиша ctrl + alt + p сохраняется, и при нажатии этой комбинации вы должны увидеть вывод лямбды.
Заключение
Модуль клавиатуры представляет собой легкую и простую библиотеку, используемую для моделирования нажатий клавиш и простой автоматизации в Python. Он не очень функциональный, но может быть использован для автоматизации некоторых задач, которые вы можете выполнять в своей повседневной работе, или просто для развлечения.
- модульное программирование
- phyton