Метод bind модуля Tkinter. Урок 7

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

В отличие от консольных приложений, которые обычно выполняются при минимальных внешних воздействиях, графическое приложение обычно ждет каких-либо внешних воздействий (щелчков кнопкой мыши, нажатий клавиш на клавиатуре, изменения виджетов) и затем выполняет заложенное программистом действие. Из такого принципа работы можно вывести следующую схему настройки функциональности GUI: на виджет что-то «влияет» из вне ? выполняется какая-то функция (действие). Внешнее воздействие на графический компонент называется событием. Событий достаточно много (основной их перечень мы рассмотрим на следующем занятии). На этом занятии будем использовать лишь два вида событий: щелчок левой кнопкой мыши () и нажатие клавиши Enter ().

Одним из способов связывания виджета, события и функции (того, что должно происходить после события) является использование метода bind. Синтаксис связывания представлен на рисунке ниже.

Связывание графического элемента, события и функции с помощью метода bind

Рассмотрим различные примеры добавления функциональности GUI.

Пример 1.

def output(event):
     s = ent.get()
     if s == "1":
          tex.delete(1.0,END)
          tex.insert(END,"Обслуживание клиентов на втором этаже")
     elif s == "2":
          tex.delete(1.0,END)
          tex.insert(END,"Пластиковые карты выдают в соседнем здании")
     else:
          tex.delete(1.0,END)
          tex.insert(END,"Введите 1 или 2 в поле слева")
 
from tkinter import *
root = Tk()
 
ent = Entry(root,width=1)
but = Button(root,text="Вывести")
tex = Text(root,width=20,height=3,font="12",wrap=WORD)
 
ent.grid(row=0,column=0,padx=20)
but.grid(row=0,column=1)
tex.grid(row=0,column=2,padx=20,pady=10)
 
but.bind("<Button-1>",output)
 
root.mainloop() 

Рассмотрим код, начиная с 16-й строки.

В строках 16-18 создаются три виджета: однострочное текстовое поле, кнопка и многострочное текстовое поле. В первое поле пользователь должен что-то ввести, затем нажать кнопку и получить ответ во втором поле.

В строках 20-22 используется менеджер grid для размещения виджетов. Свойства padx и pady определяют количество пикселей от виджета до края рамки (или ячейки) по осям x и y соответственно.

В стоке 24 как раз и происходит связывание кнопки с событием нажатия левой кнопки мыши и функцией output. Все эти три компонента (виджет, событие и функция) связываются с помощью метода bind. В данном случае, при нажатии левой кнопкой мыши по кнопке but будет вызвана функция output.

Итак, если вдруг пользователь щелкнет левой кнопкой мыши по кнопке, то выполнится функция output (ни в каком другом случае она выполняться не будет). Данная функция (строки 1-11) выводит информацию во второе текстовое поле. Какую именно информацию, зависит от того, что пользователь ввел в первое текстовое поле. В качестве аргумента функции передается событие (в данном случае ).

Внутри веток if-elif-else используются методы delete и insert. Первый из них удаляет символы из текстового поля, второй — вставляет. 1.0 — обозначает первую строку, первый символ (нумерация символов начинается с нуля).

Пример 2.

li = ["red","green"]
def color(event):
     fra.configure(bg=li[0])
     li[0],li[1] = li[1],li[0]
 
def outgo(event):
     root.destroy()
 
from tkinter import *
root = Tk()
 
fra = Frame(root,width=100,height=100)
but = Button(root,text="Выход")
 
fra.pack()
but.pack()
 
root.bind("<Return>",color)
but.bind("<Button-1>",outgo)
 
root.mainloop()

Здесь создаются два виджета (строки 12, 13): фрейм и кнопка.

Приложение реагирует на два события: нажатие клавиши Enter в пределах главного окна (строка 18) и нажатие левой кнопкой мыши по кнопке but (строка 19). В первом случае вызывается функция color, во втором — outgo.

Функция color изменяет цвет фона (bg) фрейма (fra) с помощью метода configure, который предназначен для изменения значения свойств виджетов в процессе выполнения скрипта. В качестве значения опции bg подставляется первый элемент списка. Затем в списке два элемента меняются местами, чтобы при следующем нажатии Enter цвет фрейма снова изменился.

В функции outgo вызывается метод destroy по отношению к главному окну. Данный метод предназначен для «разрушения» виджета (окно закроется).

Практическая работа

  1. Создайте приложение, в котором меняется размер фрейма в зависимости от того, какая из трех объектов-кнопок была нажата.
  2. Напишите скрипт, генерирующий окно с меткой и текстовым полем. После ввода пользователем текста в поле и нажатия Enter, введенный текст должен отображаться в метке.

а как удалить кнопку зарание

а как удалить кнопку зарание спс

Разъясните columnspan в

Разъясните columnspan в методе grid пожалуйста.

from tkinter import* from

from tkinter import*
from tkinter.filedialog import*
import fileinput
def _open():
    op=askopenfilename()
    for l in fileinput.input(op):
        txt.insert(END,l)
def _save(event):
     sa = asksaveasfilename()
     letter = txt.get(1.0,END)
     f = open(sa,"w")
     f.write(letter)
     f.close()
root=Tk()
m=Menu(root)
root.config(menu=m)
fm=Menu(m)
m.add_cascade(label="File",menu=fm)
fm.add_command(label="Open...",command=_open)
txt=Text(root,width=40,height=15,font="12")
txt.pack()
 
but=Button(root,text="in file ",bg="yellow",fg="black")
 
but.bind('<Button-1>',_save)
but.pack()
root.mainloop()

Не пойму почему кнопка не отжимается? хоть и работает как планировалась. За ранее спасибо

Как сделать комбинацию трех

Как сделать комбинацию трех клавишь контрол шифт S
она работает только при включенном капслоке.
""

Подскажите пожалуйста!

Подскажите пожалуйста! Возможно ли обрабатывать события в условном операторе или нет? Например: при нажатии на какую либо кнопку.

Не совсем понятно, что

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

Спасибо! Именно это и хотел

Спасибо! Именно это и хотел узнать, что легче написать отдельные функции для каждой кнопки, чем обрабатывать события!

Спасибо за сайт! У меня

Спасибо за сайт!
У меня вопрос: как считать значение с Text или Entry полей?

class Main:
    def __init__ (self):
 
        self.frame = Frame(root)
        self.frame.grid()
        self.wtxt = Entry (root, width = 20, bd=3)
        self.wtxt.grid(row = 0, column = 0, columnspan = 3)
 
        self.but1 = Button (root, text="1", width=3, height=1)
        self.but2 = Button (root, text="2", width=3, height=1)
        self.but3 = Button (root, text="3", width=3, height=1)
        self.butrez = Button (root, text="=", width=3, height=1)
 
        self.but1.bind("<Button-1>", self.event_textb1)
        self.but2.bind("<Button-1>", self.event_textb1)
        self.but3.bind("<Button-1>", self.event_textb3)
        self.butrez.bind("<Button-1>", self.event_rez)
        self.but1.grid(row = 2, column = 0, sticky=NW+SE)
        self.but2.grid(row = 2, column = 1, sticky=NW+SE)
        self.but3.grid(row = 2, column = 2, sticky=NW+SE)
        self.butrez.grid(row = 6, column = 2, sticky=NW+SE)
 
    def event_textb1 (self, event):
        self.wtxt.insert(END, event.widget["text"])
    def event_textb2 (self, event):
        self.wtxt.insert(END, event.widget["text"])
    def event_textb3 (self, event):
        self.wtxt.insert(END, event.widget["text"])
 
    def event_rez (self, event):
       #Как считать и отправить куда нибудь значение поля Entry
root = Tk()
main = Main()
root.title("string")
 
root.mainloop()

Методом get(). Здесь есть

Методом get(). Здесь есть пример

Здравствуйте! Скажите

Здравствуйте!
Скажите пожалуйста, как сделать, чтобы кнопки стояли на месте и не двигались?

Здравствуйте, попробовал

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

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import random
import time
strategys = (0, 1, 2) #камень, ножницы и бумага
stat = [] #хранилище решений игрока
pl_vic = [0] #вместо счетчика
com_vic = [0] #вместо счетчика
 
def exit_(event):  #функция выхода
     root.destroy()
 
def pl_choice_0(event):  #игрок выбирает камень
    stat.append(strategys[0]) #сбор статистики
    root.title('Размышляю над своим выбором...')
    time.sleep(random.randint(1, 3))  #псевдодуматель
    lab.configure(text = 'Готово. Нажмите кнопку "Сравнить"')
 
def pl_choice_1(event):  #игрок выбирает ножницы
    stat.append(strategys[1])
    root.title('Думаю что выбрать...')
    time.sleep(random.randint(1, 3))
    lab.configure(text = 'Готово. Нажмите кнопку "Сравнить"')
 
def pl_choice_2(event):  #игрок выбирает бумагу
    stat.append(strategys[2])
    root.title('Принимаю решение...')
    time.sleep(random.randint(1, 3))
    lab.configure(text = 'Готово. Нажмите кнопку "Сравнить"')
 
def compering(event):
    player_choice = stat[-1] #смотрим что выбрал игрок
    com_choice = random.choice(strategys) #случайный выбор стратегии
    if player_choice > com_choice and (player_choice + com_choice) == 1:
        lab.configure(text = 'камень бьет ножницы, победа машины')
        com_vic.append(1)  #как-то же надо делать статистику
        labstatcom.configure(text = 'Побед машины: ' + str(sum(com_vic)))
    elif player_choice < com_choice and (player_choice + com_choice) == 1:
        lab.configure(text = 'камень бьет ножницы, победа игрока')
        pl_vic.append(1)
        labstatpl.configure(text = 'Побед игрока: ' + str(sum(pl_vic)))
    elif player_choice > com_choice and (player_choice + com_choice) == 2:
        lab.configure(text = 'бумага бьет камень, победа игрока')
        pl_vic.append(1)
        labstatpl.configure(text = 'Побед игрока: ' + str(sum(pl_vic)))
    elif player_choice < com_choice and (player_choice + com_choice) == 2:
        lab.configure(text = 'бумага бьет камень, победа машины')
        com_vic.append(1)
        labstatcom.configure(text = 'Побед машины: ' + str(sum(com_vic)))
    elif player_choice > com_choice and (player_choice + com_choice) == 3:
        lab.configure(text = 'ножницы бьют бумагу, победа машины')
        com_vic.append(1)
        labstatcom.configure(text = 'Побед машины: ' + str(sum(com_vic)))
    elif player_choice < com_choice and (player_choice + com_choice) == 3:
        lab.configure(text = 'ножницы бьют бумагу, победа игрока')
        pl_vic.append(1)
        labstatpl.configure(text = 'Побед игрока: ' + str(sum(pl_vic)))
    else:
        lab.configure(text = 'ничья')
    root.title('Делайте выбор')
 
from tkinter import *
root = Tk()
 
lab = Label(root, text = 'Сделайте выбор', font = 'Arial 14')
labstatpl = Label(root, text = 'Побед игрока: ' + str(sum(pl_vic)), font = 'Arial 10')
labstatcom = Label(root, text = 'Побед машины: ' + str(sum(com_vic)), font = 'Arial 10')
 
rockbut = Button(root, text = 'Камень', width = 15, height = 5, font = 'Arial 12')
scissorsbut = Button(root, text = 'Ножницы', width = 15, height = 5, font = 'Arial 12')
paperbut = Button(root, text = 'Бумага', width = 15, height = 5, font = 'Arial 12')
comperingbut = Button(root, text = 'Сравнить', width = 15, height = 5, font = 'Arial 12')
 
 
lab.grid(row = 0, column = 1)
rockbut.grid(row = 1, column = 0, padx = 20, pady = 20)
scissorsbut.grid(row = 1, column = 1, padx = 40, pady = 40)
paperbut.grid(row = 1, column = 2, padx = 60, pady = 60)
comperingbut.grid(row = 2, column = 1)
labstatpl.grid(row = 4, column = 2)
labstatcom.grid(row = 5, column = 2)
root.geometry('750x500')
 
rockbut.bind('<Button-1>', pl_choice_0)
scissorsbut.bind('<Button-1>', pl_choice_1)
paperbut.bind('<Button-1>', pl_choice_2)
comperingbut.bind('<Button-1>', compering)
root.bind('<Control-z>', exit_)
 
root.mainloop()

Объединяйте ячейки по

Объединяйте ячейки по горизонтали. Например:

lab.grid(row = 0, column = 0, columnspan=3)

подскажите с помощью какого

подскажите с помощью какого может быть метода(...) можно считывать данные из Entry (output) (например:1+2 чтобы получился правильный ответ)
Вот простенький пример:

from Tkinter import *
root = Tk()
x1=1
x2=2
x4='+'
x6='-'
def bu1(b1):
    output.insert(END,x1)
def bu2(b2):
    output.insert(END,x2)        
def bu3(b3):
    output.delete(0,END)
def bu4(b4):
    output.insert(END,x4)
def bu6(b4):
    output.insert(END,x6)
def bu5(b5):
 
 
    output.delete(0,END)
    output.insert(END,'=')
 
 
output=Entry(root,width=12,bd=3,font='Verdana 15')
output.grid(row=0,column=0,columnspan=4)
 
but1 = Button(root,text="1",width=4,height=3,bg='gray',fg='black',font='Verdana 10')
but2 = Button(root,text="2",width=4,height=3,bg='gray',fg='black',font='Verdana 10')
but3 = Button(root,text="C0",width=4,height=3,bg='gray',fg='black',font='Verdana 10')
but4 = Button(root,text="+",width=4,height=3,bg='gray',fg='black',font='Verdana 10')
but5 = Button(root,text="=",width=4,height=3,bg='gray',fg='black',font='Verdana 10')
but6 = Button(root,text="-",width=4,height=3,bg='gray',fg='black',font='Verdana 10')
 
but1.grid(row=4,column=0)
but2.grid(row=4,column=1)
but3.grid(row=4,column=2)
but4.grid(row=3,column=0)
but5.grid(row=3,column=1)
but6.grid(row=3,column=2)
 
but=(but1,but2,but3,but4,but5,but6)
bu=(bu1,bu2,bu3,bu4,bu5,bu6)
b=zip(but,bu)
for i in b:
    i[0].bind('<Button-1>',i[1])
 
root.mainloop() 

Мне кажется проще не

Мне кажется проще не считывать данные из Entry (т.к. в любом случае получите сторку из которой надо вырезать и обрабатывать данные), а выполнять действия по ходу нажатия кнопок (то ли сразу суммировать/вычитать, то ли помещать числа в список, а потом выполнять действия в зависимости от выбранного знака).

Доброго! Подскажите

Доброго! Подскажите пожалуйста, как обратиться(в каком пространстве имен) к метке и текстовому полю в функции inte:

def inte(event):
	s=entry1.get()
	entry1.delete(0,END)
	label0.configure(text=s)
from Tkinter import *
def __init__(self):
	self.label0=Label(root,text="Input Text",width=30,height=10)
	self.entry1=Entry(root,width=30)
	self.label0.grid(row=0,column=0,padx=10,pady=20)
	self.entry1.grid(row=0,column=1,padx=10,pady=20)
self.entry1.bind("<Return>",inte)
root=Tk()
obj=interface()
root.mainloop()

напишите пожалуйста решение.

напишите пожалуйста решение.

Второе задание

from tkinter import *
 
def changetext(event):
    lab.configure(text=tex.get())
 
root = Tk()
 
lab = Label(root,width=50,bg="grey",
            text="Input text in the field")
tex = Entry(root,width=50)
 
tex.bind("<Return>",changetext)
 
lab.pack()
tex.pack()
 
root.mainloop()

Первое задание

from tkinter import *
 
def small(event):
    fra.configure(width=100)
def middle(event):
    fra.configure(width=200)
def big(event):
    fra.configure(width=300)
 
root = Tk()
 
fra = Frame(root,width=100,height=100,bg="green")
but1 = Button(root,text="100x100")
but2 = Button(root,text="200x100")
but3 = Button(root,text="300x100")
 
but1.bind("<Button-1>",small)
but2.bind("<Button-1>",middle)
but3.bind("<Button-1>",big)
 
fra.grid(row=0,column=0,columnspan=3)
but1.grid(row=1,column=0)
but2.grid(row=1,column=1)
but3.grid(row=1,column=2)
 
root.mainloop()

А можно ли ка кто реализовать

А можно ли ка кто реализовать всё в одной функции(в первом задании)?

Да, если в функцию передавать

Да, если в функцию передавать информацию о том, какая кнопка нажата, а в функции реализовать ветвление if-elif.

и как будет выглядеть

и как будет выглядеть функция?