Программирование событий в Tkinter. Урок 8

Методическая разработка урока
Элективный курс: Модуль tkinter. Создание графического интерфейса пользователя с помощью языка программирования Python
Уровень: Программирование для начинающих

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

Типы событий

Можно выделить три основных типа событий: производимые мышью, нажатиями клавиш на клавиатуре, а также события, возникающие в результате изменения других графических объектов.

Типы событий в программировании

Способ записи

При вызове метода bind событие передается в качестве первого аргумента.

Привязка события в методе bind (Tkinter)

Название события заключается в кавычки, а также в знаки < и >. Событие описывается с помощью зарезервированных последовательностей ключевых слов.

События, производимые мышью

  • <Button-1> - щелчок левой кнопкой мыши
  • <Button-2> - щелчок средней кнопкой мыши
  • <Button-3> - щелчок правой кнопкой мыши
  • <Double-Button-1> - двойной клик левой кнопкой мыши
  • <Motion> - движение мыши
  • и т. д.

Пример:

from tkinter import *
def b1(event):
     root.title("Левая кнопка мыши")
def b3(event):
     root.title("Правая кнопка мыши")
def move(event):
     root.title("Движение мышью")
 
root = Tk()
root.minsize(width = 500, height=400)
 
root.bind('<Button-1>',b1)
root.bind('<Button-3>',b3)
root.bind('<Motion>',move)
 
root.mainloop() 

В этой программе меняется надпись в заголовке главного окна в зависимости от того двигается мышь, щелкают левой или правой кнопкой мыши.

События, производимые с помощью клавиатуры

  • Буквенные клавиши можно записывать без угловых скобок (например, 'L').
  • Для неалфавитных клавиш существуют специальные зарезервированные слова
    * <Return> - нажатие клавиши Enter;
    * <space>- пробел;
    * и т. д.
  • Сочетания клавиш пишутся через тире. Например:
    * <Control-Shift> - одновременное нажатие клавиш Ctrl и Shift.

from tkinter import *
 
def exit_(event):
     root.destroy()
def caption(event):
     t = ent.get()
     lbl.configure(text = t)
 
root = Tk()
 
ent = Entry(root, width = 40)
lbl = Label(root, width = 80)
 
ent.pack()
lbl.pack()
 
ent.bind('<Return>',caption)
root.bind('<Control-z>',exit_)
 
root.mainloop() 

При нажатии клавиши Enter в пределах текстовой строки (ent) вызывается функция caption, которая помещает символы из текстовой строки (ent) в метку (lbl). Нажатие комбинации клавиш Ctrl + z приводит к закрытию главного окна.

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

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

#!/usr/bin/env python2 # -*-

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
 
import Tkinter as tk
 
class myapp:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Lesson 8 app 1")
        self.root.bind("q",self.exitself)
        self.text = tk.Label(self.root,text='Press "q" to exit"')
        self.flagsDic = {
        'First':1,
        'Second':2,
        'Third':3,
        'Fourth':4
        }
        for key in self.flagsDic:
            self.flagsDic[key] = tk.IntVar()
            Flag = tk.Checkbutton(self.root,text=key,variable=self.flagsDic[key])
            Flag.grid(sticky='w')
        self.ent = tk.Entry(self.root,width=20)
        self.fstatus = tk.Text(self.root)
        self.text.grid(row=4,column=0,columnspan=2)
        self.fstatus.grid(row=0,column=1,rowspan=len(self.flagsDic))
        self.fstatus.bind("<Button-1>",self.display)
    def display(self,event):
        checked = []
        unchecked = []
        for key, value in self.flagsDic.items():
            if value.get():
                checked.append(key)
            else:
                unchecked.append(key)
        if len(checked) == 0:
            message = "Unchecked:"
            for s in unchecked:
                message = message + " " + s
            print message
        if len(unchecked) == 0:
            message = "Checked:"
            for s in checked:
                message = message + " " + s
        if len(checked) != 0 and len(unchecked) != 0:
            message = "Unchecked:"
            for s in unchecked:
                message = message + " " + s
            message = message + "\nChecked:"
            for s in checked:
                message = message + " " + s
        self.fstatus.delete(0.0,tk.END)
        self.fstatus.insert(0.0,message)
    def exitself(self,event):
        self.root.destroy()
 
def main():
    app = myapp()
    app.root.mainloop()
 
if __name__ == "__main__":
    main()

Мой вариант решения. from

Мой вариант решения.

from tkinter import *
 
root = Tk()
ent_1 = Entry(root, width=20)
ent_2 = Entry(root, width=20)
fra = Frame(root, width=500, height=500, bg='blue')
 
def change_width(event):
    fra.configure(width=int(ent_1.get()))
    ent_1.delete(0, END)
 
def change_height(event):
    fra.configure(height=int(ent_2.get()))
    ent_2.delete(0, END)
def change(event):
    fra.configure(width=500, height=500)
 
 
ent_1.bind("<Return>", change_width)
ent_2.bind("<Return>", change_height)
root.bind("<space>", change)
ent_1.pack()
ent_2.pack()
fra.pack()
root.mainloop()

лол первое задание не оч

лол первое задание
не оч разобрался с флажками хотел фориком прогнать а он пишет элементы intVar not colable и чекбатон тоже самое
скиньте свою версию плз

from tkinter import

from tkinter import *
main=Tk()
def onval(event):
    tex.delete(1.0,END)
    tex.insert(END,'Включены : ')
    tex.insert(END,'1 ' if ch1.get() else '')
    tex.insert(END,'2 ' if ch2.get() else '')
    tex.insert(END,'3' if ch3.get() else '')
def offval(event):
    tex.delete(1.0,END)
    tex.insert(END,'Выключены : ')
    tex.insert(END,'1 ' if not ch1.get() else '')
    tex.insert(END,'2 ' if not ch2.get() else '')
    tex.insert(END,'3' if not ch3.get() else '')
ch1=IntVar()
che1=Checkbutton(main,text=1,variable=ch1,onvalue=1,offvalue=0)
che1.pack()
ch2=IntVar()
che2=Checkbutton(main,text=2,variable=ch2,onvalue=1,offvalue=0)
che2.pack()
ch3=IntVar()
che3=Checkbutton(main,text=3,variable=ch3,onvalue=1,offvalue=0)
che3.pack()
tex=Text(main,width=20,height=3)
tex.pack()
tex.bind('<Button-1>',onval)
tex.bind('<Button-3>',offval)
main.mainloop()

Моя реализация второй

Моя реализация второй задачи

from tkinter import *
 
root = Tk()
ent_1 = Entry(root, width=20)
ent_2 = Entry(root, width=20)
fra = Frame(root, width=500, height=500, bg='blue')
 
def change_width(event):
    one = ent_1.get()
    fra.configure(width=int(one))
    ent_1.delete(0, END)
 
def change_height(event):
    two = ent_2.get()
    fra.configure(width=int(two))
    ent_2.delete(0, END)
def change(event):
    fra.configure(width=500, height=500)
 
 
ent_1.bind("<Return>", change_width)
ent_2.bind("<Return>", change_height)
root.bind("<space>", change)
ent_1.pack()
ent_2.pack()
fra.pack()
root.mainloop()

Нашел очень интересную

Нашел очень интересную особенность. Будет полезна всем.
В литературе можно встретить такой способ вывода виджетов:

ent = Entry(width=10).pack()

или

ent = Entry(width=10).grid(row=0, column=0)

Так вот при таком способе вывода метод bind не работает!!!!
При таком способе там другая техника, через command=

У вас ошибка. Методы pack и

У вас ошибка. Методы pack и grid возвращают None а не виджет.

Мое решение второй части

Мое решение второй части задания:

from Tkinter import * 
root = Tk()
 
frheight = 100
frwidth = 100
 
def _space(event):
    global frheight, frwidth
    frheight = frheight - 10
    frwidth = frwidth - 10
    frame1.configure(height = frheight, width = frwidth)
 
def value1(event):
    global frheight
    t1 = ent1.get()
    frheight = frheight + float(t1)
    frame1.configure(height = frheight)
 
def value2(event):
    global frwidth
    t2 = ent2.get()
    frwidth = frwidth + float(t2)
    frame1.configure(width = frwidth)
 
lab1 = Label(root, text="Высота", bg="white", font="Arial 11")
ent1 = Entry(root,width=20) 
lab2 = Label(root, text="Ширина", bg="white", font="Arial 11")
ent2 = Entry(root,width=20)
 
frame1=Frame(root,width=100,height=100,bg='green',bd=5)
 
root.bind('<space>', _space)
ent1.bind('<Return>', value1)
ent2.bind('<Return>', value2)
 
lab1.pack()
ent1.pack()
lab2.pack()
ent2.pack()
frame1.pack()
 
root.mainloop()

Пытаюсь на python сделать GUI

Пытаюсь на python сделать GUI калькулятор.
как лучше отправить данные с TEXT поля на обработку?
Создать список или по очереди записывать в переменные?
И как примерно это реализовать?

import sys
from tkinter import *
from textwrap import fill
from Calc import Calc
 
class Main:
    spisok = []
    def __init__ (self):
 
        self.frame = Frame(root)
 
        self.frame.grid()
 
        self.wtxt = Text (root, width = 20, height = 1, 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.butplus = Button (root, text="+", width=3, height=1)
        self.butminus = Button (root, text="-", width=3, height=1)
        self.butumn = Button (root, text="*", width=3, height=1)
        self.butdel = Button (root, text="/", width=3, height=1)
        self.butrez = Button (root, text="=", width=3, height=1)
 
        self.but0.bind("<Button-1>", self.event_textb0)
        self.but1.bind("<Button-1>", self.event_textb1)
        self.but2.bind("<Button-1>", self.event_textb2)
        self.but3.bind("<Button-1>", self.event_textb3)
        self.butplus.bind("<Button-1>", self.event_textplus)
        self.butminus.bind("<Button-1>", self.event_textminus)
        self.butumn.bind("<Button-1>", self.event_textumno)
        self.butdel.bind("<Button-1>", self.event_textdel)
        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.butplus.grid(row = 5, column = 1, sticky=NW+SE)
        self.butminus.grid(row = 5, column = 2, sticky=NW+SE)
        self.butumn.grid(row = 6, column = 0, sticky=NW+SE)
        self.butdel.grid(row = 6, column = 1, sticky=NW+SE)
        self.butrez.grid(row = 6, column = 2, sticky=NW+SE)
 
    def event_textb1 (self, event):
#       self.wtxt.insert(END, 1)
        self.wtxt.insert(END, event.widget["text"])
    def event_textb2 (self, event):
        self.wtxt.insert(END, 2)
    def event_textb3 (self, event):
        self.wtxt.insert(END, 3)
 
    def event_textplus (self, event):
        self.wtxt.insert(END, "+")
 
    def event_textminus (self, event):
        self.wtxt.insert(END, "-")
 
 
    def event_textumno (self, event):
        self.wtxt.insert(END, "*")
 
 
    def event_textdel (self, event):
        self.wtxt.insert(END, "/")
 
    def event_rez (self, event):
        self.get_rez = self.wtxt.get('0.1', 'end')
        self.wtxt.delete('0.1', 'end')
        self.spisok = [self.spisok for self.spisok in self.get_rez]
 
 
root = Tk()
main = Main()
root.title("string")
 
root.mainloop()

Мой вариант выполнения

Мой вариант выполнения первого задания (Python 2.7):

#!/usr/bin/env python
# --*-- coding:utf-8 --*--
 
from Tkinter import *
def b1(event):
     txt.delete(0.0, END)
     root.title("Включены")
     if f1.get() == 1:
         txt.insert(END, "Первый флажок\n")
     if f2.get() == 1:
         txt.insert(END, "Второй флажок\n")
     if f3.get() == 1:
         txt.insert(END, "Третий флажок\n")
 
def b3(event):
     txt.delete(0.0, END)
     root.title("Выключены")
     if f1.get() == 0:
         txt.insert(END, "Первый флажок\n")
     if f2.get() == 0:
         txt.insert(END, "Второй флажок\n")
     if f3.get() == 0:
         txt.insert(END, "Третий флажок\n")
 
root = Tk()
root.minsize(width = 193, height=143)
root.maxsize(width = 193, height=143)
f1 = IntVar()
f2 = IntVar()
f3 = IntVar()
fl1 = Checkbutton(root,text="Первый флажок",
          variable=f1,onvalue=1,offvalue=0)
fl2 = Checkbutton(root,text="Второй флажок",
          variable=f2,onvalue=1,offvalue=0)
fl3 = Checkbutton(root,text="Третий флажок",
          variable=f3,onvalue=1,offvalue=0)
txt = Text(root,bd=5,font=20,width=20, height=3)
 
fl1.grid(row=0,column=0)
fl2.grid(row=1,column=0)
fl3.grid(row=2,column=0)
txt.grid(row=3,column=0)
 
txt.bind('<Button-1>',b1)
txt.bind('<Button-3>',b3)
 
root.mainloop()

def show(event):

def show(event):
    txt.delete(0,END)
    if v1.get() == 1:
        txt.insert(END,"First-on ")
    else:
        txt.insert(END,"First-off ")
    if v2.get() == 1:
        txt.insert(END,"Second-on ")
    else:
        txt.insert(END,"Second-off ")
    if v3.get()==1:
        txt.insert(END,"Third-on ")
    else:
        txt.insert(END,"Third-off ")
 
from tkinter import *
root = Tk()
 
v1 = IntVar()
v2 = IntVar()
v3 = IntVar()
c1 = Checkbutton(root,
                 text="First flag",
                 variable=v1,
                 onvalue=1,
                 offvalue=0)
c2 = Checkbutton(root,
                 text="Second flag",
                 variable=v2)
c3 = Checkbutton(root,
                 text="Third flag",
                 variable=v3,
                 onvalue=1,
                 offvalue=0)
 
txt = Entry(root,width=30)
 
c1.grid(row=0,column=0)
c2.grid(row=0,column=1)
c3.grid(row=0,column=2)
txt.grid(row=1,columnspan=3)
txt.bind("<Button-1>",show)
 
root.mainloop()

Моё решение практической

Моё решение практической работы

#файл 1.py
#Первое задание
def onflag(event):
        e.delete(0,END)
        s=''
        if c1.get()=='1-on ': s=c1.get()
        if c2.get()=='2-on': s+=c2.get()
        e.insert(0,s)
 
def offflag(event):
        e.delete(0,END)
        s=''
        if c1.get()=='1-off ': s=c1.get()
        if c2.get()=='2-off': s+=c2.get()
        e.insert(0,s)
 
from tkinter import *
root=Tk()
 
c1=StringVar()
c2=StringVar()
ch1=Checkbutton(root,
                text='Первый флажок',
                variable=c1,
                onvalue='1-on ',
                offvalue='1-off ')
ch2=Checkbutton(root,
                text='Второй флажок',
                variable=c2,
                onvalue='2-on',
                offvalue='2-off')
 
e=Entry(root,width=20)
 
e.bind('<Button-1>',onflag)
e.bind('<Button-3>',offflag)
 
ch1.deselect()
ch2.deselect()
ch1.pack()
ch2.pack()
e.pack(pady=10)
root.mainloop()
 
#файл 2.py
#Второе задание
 
def widthFrame(event):
        f.configure(width=e1.get())
        e1.delete(0,END)
 
def heightFrame(event):
        f.configure(height=e2.get())
        e2.delete(0,END)
 
from tkinter import *
root=Tk()
 
e1=Entry(root,width=20)
e2=Entry(root,width=20)
f=Frame(root,width=100,height=100,bg='red')
 
e1.bind('<space>',widthFrame)
e2.bind('<space>',heightFrame)
 
e1.pack(pady=5,padx=3)
e2.pack()
f.pack(pady=5,padx=3)
root.mainloop()

Интересно,как можно написать

Интересно,как можно написать скрипт,без описанного в следующем уроке метода (get)?!Как можно получить значения флажков ещё?

) действительно, жестоко. В

) действительно, жестоко. В следующей версии исправлю.

Спасибо=)

Спасибо=)