Переменные Tkinter. Урок 9

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

Библиотека Tkinter содержит специальные классы, объекты которых выполняют роль переменных для хранения значений о состоянии различных виджет. Изменение значения такой переменной ведет к изменению и свойства виджета, и наоборот: изменение свойства виджета изменяет значение ассоциированной переменной.

Существует несколько таких классов Tkinter, предназначенных для обработки данных разных типов.

  1. StringVar() - для строк;
  2. IntVar() - целых чисел;
  3. DoubleVar() - дробных чисел;
  4. BooleanVar() - для обработки булевых значений (true и false).

Пример 1.

Во втором уроке мы уже использовали переменную-объект типа IntVar() при создании группы радиокнопок:

var=IntVar()
var.set(1)
rad0 = Radiobutton(root,text="Первая",variable=var,value=0)
rad1 = Radiobutton(root,text="Вторая",variable=var,value=1)
rad2 = Radiobutton(root,text="Третья",variable=var,value=2)

Здесь создается объект класса IntVar и связывается с переменной var. С помощью метода set устанавливается начальное значение, равное 1. Три радиокнопки относятся к одной группе: об этом свидетельствует одинаковое значение опции (свойства) variable. Variable предназначена для связывания переменной Tkinter с радиокнопкой. Опция value определяет значение, которое будет передано переменной, если данная кнопка будет в состоянии "включено". Если в процессе выполнения скрипта значение переменной var будет изменено, то это отразится на группе кнопок. Например, это делается во второй строчке кода: включена кнопка rad1.

Если метод set позволяет устанавливать значения переменных, то метод get, наоборот, позволяет получать (узнавать) значения для последующего их использования.

def display(event):
     v = var.get()
     if v == 0:
          print ("Включена первая кнопка")
     elif v == 1:
          print ("Включена вторая кнопка")
     elif v == 2:
          print ("Включена третья кнопка")
 
but = Button(root,text="Получить значение")
but.bind('<Button-1>',display) 

При вызове функции display в переменную v “записывается“ значение, связанное в текущий момент с переменной var. Чтобы получить значение переменной var, используется метод get (вторая строчка кода).
Пример 2.

Несколько сложнее обстоит дело с флажками. Поскольку состояния флажков независимы друг друга, то для каждого должна быть введена собственная ассоциированная переменная-объект.

from tkinter import *
 
root = Tk()
 
var0=StringVar() # значение каждого флажка ...
var1=StringVar() # ... хранится в собственной переменной
var2=StringVar()
# если флажок установлен, то в ассоциированную переменную ...
# ...(var0,var1 или var2) заносится значение onvalue, ...
# ...если флажок снят, то - offvalue.
ch0 = Checkbutton(root,text="Окружность",variable=var0,
          onvalue="circle",offvalue="-")
ch1 = Checkbutton(root,text="Квадрат",variable=var1,
          onvalue="square",offvalue="-")
ch2 = Checkbutton(root,text="Треугольник",variable=var2,
          onvalue="triangle",offvalue="-")
 
lis = Listbox(root,height=3)
def result(event):
     v0 = var0.get()
     v1 = var1.get()
     v2 = var2.get()
     l = [v0,v1,v2] # значения переменных заносятся в список
     lis.delete(0,2) # предыдущее содержимое удаляется из Listbox
     for v in l: # содержимое списка l последовательно ...
          lis.insert(END,v) # ...вставляется в Listbox
 
but = Button(root,text="Получить значения")
but.bind('<Button-1>',result)
 
ch0.deselect()# "по умолчанию" флажки сняты
ch1.deselect()
ch2.deselect()
 
ch0.pack()
ch1.pack()
ch2.pack()
but.pack()
lis.pack()
 
root.mainloop()

Пример 3.

Помимо свойства (опции) variable, связывающей виджет с переменной-объектом Tkinter (IntVar, StringVar и др.), у многих виджет существует опция textvariable, которая определяет текст-содержимое или текст-надпись виджета. Несмотря на то, что «текстовое свойство» может быть установлено для виджета и изменено в процессе выполнения кода без использования ассоциированных переменных, иногда такой способ изменения оказывается более удобным.

from tkinter import *
root = Tk()
v = StringVar()
ent1 = Entry (root, textvariable = v,bg="black",fg="white")
ent2 = Entry(root, textvariable = v)
ent1.pack()
ent2.pack()
root.mainloop()

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

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

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

Задача № 1 мое решение крайне

Задача № 1 мое решение крайне примитивное так как я не додумался как вытащить значение при выключенном флажке...Может кто подскажет реальное решение этой задачки с учетом что бы по правому клику выводил значения по выключенным флажкам???

def left(event):
     v0 = var0.get()
     v1 = var1.get()
     v2 = var2.get()
     l = [v0,v1,v2] # значения переменных заносятся в список
     f = []
     for i in l:
          if i != "-":
               f.append(i)
     lis.configure(text = ", ".join(f))
def right(event):
     f = []
     if var0.get() == '-':
          ch0.select()
          f.append(var0.get())
          ch0.deselect()
     if var1.get() == '-':
          ch1.select()
          f.append(var1.get())
          ch1.deselect()
     if var2.get() == '-':
          ch2.select()
          f.append(var2.get())
          ch2.deselect()
     lis.configure(text = ", ".join(f))
from tkinter import *
root = Tk()
var0=StringVar() # значение каждого флажка ...
var1=StringVar() # ... хранится в собственной переменной
var2=StringVar()
# если флажок установлен, то в ассоциированную переменную ...
# ...(var0,var1 или var2) заносится значение onvalue, ...
# ...если флажок снят, то - offvalue.
ch0 = Checkbutton(root,text="Окружность",variable=var0,
          onvalue="circle",offvalue="-")
ch1 = Checkbutton(root,text="Квадрат",variable=var1,
          onvalue="square",offvalue="-")
ch2 = Checkbutton(root,text="Треугольник",variable=var2,
          onvalue="triangle",offvalue="-")
 
lis = Label(root, text = "Left click TRUE! \n Right click FALS", font = "Arial 10")
 
but = Button(root,text="Получить значения")
but.bind('<Button-1>',left)
but.bind('<Button-3>',right)
 
ch0.deselect()# "по умолчанию" флажки сняты
ch1.deselect()
ch2.deselect()
 
ch0.pack()
ch1.pack()
ch2.pack()
but.pack()
lis.pack()
 
root.mainloop()

вторая from tkinter import

вторая

from tkinter import *
 
root = Tk()
 
colors = ['red', 'blue', 'green', 'yellow', 'white', 'black', 'cyan']
 
def command(value):
    frame.config(background = colors[int(value) - 1])
 
scale = Scale(root, orient = 'horizontal', length = 300, from_ = 1, to = len(colors), command = command)
scale.pack()
 
frame = Frame(root, width = 200, height = 150)
frame.pack()
 
root.mainloop()

Решение 2й задачи... from

Решение 2й задачи...

from tkinter import *
root = Tk()
fra = Frame(root, width=500, height=500, bg='blue')
var = IntVar()
sca1 = Scale(root, orient=HORIZONTAL, length=300, from_=1, to=10, tickinterval=1, resolution=1, variable=var)
 
def change(event):
    colors = {1: "blue", 2: "black", 3: "red", 4:"white", 5:"yellow", 6:"green", 7:"lightblue", 8:"grey", 9:"lightgrey", 10:"lightyellow"}
    x = sca1.get()
    for key in colors.keys():
        if x == key:
            fra.configure(bg=colors.get(key))
 
sca1.bind("<Motion>", change)
sca1.pack()
fra.pack()
root.mainloop()

Второе задание Решил с

Второе задание
Решил с использованием трёх шкал с выбором значения цвета RGB

from tkinter import *
 
def change_color(event):
    r = hex(red.get())[2:4]
    g = hex(green.get())[2:4]
    b = hex(blue.get())[2:4]
    if len(r)==1:
        r = '0' + r
    if len(g)==1:
        g = '0' + g
    if len(b)==1:
        b = '0' + b
    clr = '#'+r+g+b
    fr1.configure(bg=clr)
 
root = Tk()
fr1 = Frame(root, width=200, height=200, bg='white')
red = Scale(root,orient=HORIZONTAL,length=180,from_=0,to_=255,tickinterval=50,resolution=1)
green = Scale(root,orient=HORIZONTAL,length=180,from_=0,to_=255,tickinterval=50,resolution=1)
blue = Scale(root,orient=HORIZONTAL,length=180,from_=0,to_=255,tickinterval=50,resolution=1)
 
but = Button(root,text="Set color")
but.bind("<Button-1>",change_color)
fr1.pack()
red.pack()
green.pack()
blue.pack()
but.pack()
 
root.mainloop()

Листинг события можно

Листинг события можно вместить и в 2 строки (без ветвления)

clr='#'+hex(r.get())[2:4].zfill(2)+hex(b.get())[2:4].zfill(2)+hex(g.get())[2:4].zfill(2)
fr1.configure(bg=clr)

Очень интересное решение

Очень интересное решение задачи)))

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

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

примерное решение второго задания

from tkinter import *
 
def changecolor(event):
    col = sca.get()
    if col == 0:
        fra.configure(bg="white")
    elif col == 1:
        fra.configure(bg="red")
    elif col == 2:
        fra.configure(bg="green")
    elif col == 3:
        fra.configure(bg="blue")
 
root = Tk()
 
fra = Frame(root,width=500,height=150,bg="darkblue")
sca = Scale(root,orient=HORIZONTAL,length=200,
          from_=0,to=3,tickinterval=1,resolution=1)
 
sca.bind("<B1-Motion>",changecolor)
 
fra.pack()
sca.pack()
 
root.mainloop()

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

Надо поменять список для вывода на метку или текстовую строку

...
tex = Entry(root,width=20)
def result(event):
     v0 = var0.get()
     v1 = var1.get()
     v2 = var2.get()
     l = [v0,v1,v2] 
     tex.delete(0,END) 
     for v in l: 
          tex.insert(END,v+', ') 
...
tex.pack()
...

Отлично - в задаче

Отлично - в задаче сформулировано, чтобы результат отображался в метке (Label). Свое решение приводите для текстовой строки(Entry). Но оно абсолютно не идентично в исполнении Label!
У лейбла нет методов insert, delete... И поэтому нет и реализации с постепенным заливом переменных в отображение. А в конце вообще ненужная запятая будет жить....
Второе. Вообще перекроили первоначальное задание. Посмотрите - там же было так - при щелчке левой кнопкой отобразить то, что с флажком. При щелчке правой, то что не отмечено.
А тут - пользователю свалят просто значения положения чекбоксов.

думаю так будет поинтереснее

думаю так будет поинтереснее и не отходим от основного задания =)

lab = Label(root,text="Флажки")
def result(event):
     s=""
     v0 = var0.get()
     v1 = var1.get()
     v2 = var2.get()
     l = [v0,v1,v2] # значения переменных заносятся в список
     lab.configure(text="") # предыдущее содержимое удаляется из Listbox
     for v in l: # содержимое списка l последовательно ...
          s=s+v+"," # ...вставляется в Listbox
     lab.configure(text=s[0:-1])
</pyton>

1-e задание - неккоректно.

1-e задание - неккоректно. Я что, один вижу, что задачу перекроили?
В предыдущем уроке было так красиво - жмешь левую кнопу мыши - тебе показывают отмеченные.
Жмешь правую - показывают неотмеченные.
Это же песня была. Сортировка. Фильтрация. А тут - свалили все значения чекбоксов в кучу пользователю. Читай....

У меня программа 1 из предыдущего урока показывала характеристики кандидата. Если чекбокс отмечен - значит есть положительная характеристика.
Например, кандидат готов к перезду, готов к командировкам, есть загранпаспорт, есть санкнижка, не привлекался к угол.ответсвенности.
Пользователь клацает левой кнопкой в окне - и вуаля, он знает положительные характеристики.
Негатив хочешь посмотреть - клацаешь правой.
Короче - вывод. Эту задачу нельзя перекраивать для примера с переменными. Переменные строчного типа здесь просто не нужны.
Лучше дайте задание написать небольшой генератор предложений. База подлежащего, сказуемого. Эти переменные забирают из базы значения и вставляют в строку.

Видимо в том и фишка, чтобы

Видимо в том и фишка, чтобы разобраться как работают эти чекеры в других условиях и напороться на новые особенности и способы работы с ними. Вот что получилось у меня на первую задачу.

from tkinter import *

def leftclick(event):
s=''
if c1.get()[0]!='-':
s+=c1.get()+', '
if c2.get()[0]!='-':
s+=c2.get()+', '
if c3.get()[0]!='-':
s+=c3.get()+', '
if c4.get()[0]!='-':
s+=c4.get()+', '
if s!='':
s=s[0:-2]
lab.configure(text=s)

def rightclick(event):
s=''
if c1.get()[0]=='-':
s+=c1.get()[1:]+', '
if c2.get()[0]=='-':
s+=c2.get()[1:]+', '
if c3.get()[0]=='-':
s+=c3.get()[1:]+', '
if c4.get()[0]=='-':
s+=c4.get()[1:]+', '
if s!='':
s=s[0:-2]
lab.configure(text=s)

root = Tk()

c1 = StringVar()
c2 = StringVar()
c3 = StringVar()
c4 = StringVar()

c1.set('1')
c2.set('-2')
c3.set('3')
c4.set('-4')

che1 = Checkbutton(root, text='Первая галка',
variable=c1, onvalue='1', offvalue='-1')
che2 = Checkbutton(root, text='Вторая галка',
variable=c2, onvalue='2', offvalue='-2')
che3 = Checkbutton(root, text='Третья птичка',
variable=c3, onvalue='3', offvalue='-3')
che4 = Checkbutton(root, text='Четвёртая птичка',
variable=c4, onvalue='4', offvalue='-4')

che1.pack()
che2.pack()
che3.pack()
che4.pack()

lab = Label(root, width=30, bg='green', fg='yellow')
lab.bind('',leftclick)
lab.bind('',rightclick)
lab.pack()

root.mainloop()

к чему все эти

к чему все эти сложности

lab=Label(root,width=20)
def result(event):
        lab.configure(text=(var0.get(),',',var1.get(),',',var2.get()))

Сложности и витиеватости кода

Сложности и витиеватости кода появляются от сложности реализации поставленной задачи. Твое прстое решение привело к тому что результат работы не будет корректен в 100%. По условиям задачи может возникнуть ситуация, что на экран не выдается никаких данных. Тогда у тебя будет в ответе сиять две запятые. Догадываешься, как тебя, создателя программы будут называть пользователи при таком результате?