Написать калькулятор который позволяет сложить два числа
Работа с интерфейсом / подсказка к 2 задачке
Рассмотрим еще одну компоненту, которую можно использовать просто для вывода значения на форме. Именуется она Label. То есть подпись или метка по-русски.
Возьмем болванку нашего кода:
from tkinter import *
def my_setup(gui):
gui.geometry("300x200")
gui = Tk()
my_setup(gui)
gui.mainloop()
и добавим label на форму:
def my_setup(gui):
gui.geometry("300x200")
label = Label(gui, text="Имя")
label.place(x=10, y=10)
получится текст без возможности редактирования:
теперь можно добавить поле для ввода, например,:
def my_setup(gui):
gui.geometry("300x200")
label = Label(gui, text="Имя")
label.place(x=10, y=10)
entry = Entry(gui)
entry.place(x=40, y=10, width=150)
вот что выйдет
главный неприятный момент здесь в том, что нам надо как-то угадывать длину Label, чтобы верно разместить поле для ввода. Ну, чтобы оно случайно не налезло на метку. На самом деле этого можно избежать. Для этого во все компоненты на форме встроен метод winfo_width
который позволяет узнать размер объекта на форме. Посмотрим, что он выдает:
def my_setup(gui):
gui.geometry("300x200")
label = Label(gui, text="Имя")
label.place(x=10, y=10)
print(label.winfo_width()) # добавил
# ...
напишет оно
“почему 1?” – спросите вы. А потому, что пока компонента не отобразилась на форме никто не может сказать какого она размера. Поэтому прежде чем вызвать метод winfo_width, надо обязательно попросить tkinter обновить форму. Для этого надо вызвать метод gui.update(). То есть так:
def my_setup(gui):
gui.geometry("300x200")
label = Label(gui, text="Имя")
label.place(x=10, y=10)
gui.update() # добавил
print(label.winfo_width())
entry = Entry(gui)
entry.place(x=40, y=10, width=150)
смотрим:
Ура! 30 пикселей – похоже на правду. Теперь можно более корректно расположить entry на форме:
def my_setup(gui):
gui.geometry("300x200")
label = Label(gui, text="Имя")
label.place(x=10, y=10)
gui.update()
print(label.winfo_width())
entry = Entry(gui)
# считаю теперь положение учитывая размеры label
entry.place(x=10 + label.winfo_width() + 10, y=10, width=150)
вообще, если так подумать, то сильно много кода надо писать, чтобы просто расположить поле для ввода на форме. А если еще и второе надо добавить, а если третье?
В общем чтобы жизнь нам упростить можно просто создать дополнительную функцию по созданию поля для ввода с меткой и использовать ее, если надо несколько полей. Попробуем это сделать:
# добавил функцию с 4-мя параметрами
def create_entry(x, y, label_text, entry_width):
pass
def my_setup(gui):
gui.geometry("300x200")
label = Label(gui, text="Имя")
label.place(x=10, y=10)
gui.update()
print(label.winfo_width())
entry = Entry(gui)
entry.place(x=10 + label.winfo_width() + 10, y=10, width=150)
теперь копируем в нее код по созданию метки:
def create_entry(x, y, label_text, entry_width):
# скопировал
label = Label(gui, text="Имя")
label.place(x=10, y=10)
gui.update()
print(label.winfo_width())
entry = Entry(gui)
entry.place(x=10 + label.winfo_width() + 10, y=10, width=150)
def my_setup(gui):
gui.geometry("300x200")
# а тут наоборот убрал
и заменяем в ней значения на параметры которые передаются в функцию:
def create_entry(x, y, label_text, entry_width):
label = Label(gui, text=label_text) # тут вставил label_text
label.place(x=x, y=y) # тут вставил x и y
gui.update()
#print(label.winfo_width()) убрал
entry = Entry(gui)
# тут вставил x, y и entry_width
entry.place(x=x + label.winfo_width() + 10, y=y, width=entry_width)
и теперь немного улучшим функцию, так чтобы она возвращала метку которая была создана:
def create_entry(x, y, label_text, entry_width):
label = Label(gui, text=label_text)
label.place(x=x, y=y)
gui.update()
entry = Entry(gui)
entry.place(x=x + label.winfo_width() + 10, y=y, width=entry_width)
gui.update() # еще раз обновим интерфейс
return entry # вернем метку
теперь можно эту функцию смело использовать для создания полей с метками:
def create_entry(x, y, label_text, entry_width):
label = Label(gui, text=label_text)
label.place(x=x, y=y)
gui.update()
entry = Entry(gui)
entry.place(x=x + label.winfo_width() + 10, y=y, width=entry_width)
gui.update() # еще раз обновим интерфейс
return entry # вернем метку
def my_setup(gui):
gui.geometry("300x200")
txtName = create_entry(10, 10, "Имя", 150)
получится так:
если вы не совсем понимаете, как срабатывает функция то вот вам схемка
то есть если немного упростить то, когда у вас есть функция и вы пишите
create_entry(10, 10, "Имя", 150)
то вызывается такой код:
def create_entry(10, 10, "Имя", 150):
label = Label(gui, text="Имя")
label.place(x=10, y=10)
gui.update()
entry = Entry(gui)
entry.place(x=10 + label.winfo_width() + 10, y=10, width=150)
gui.update()
return entry
то есть ваши параметры пробрасываются внутрь функции и заменяю соответствующие значения.
Плюс есть еще страшный return, который позволяет передать значение переменной созданной внутри функции во вне. То есть значение переменной entry
созданной внутри функции create_entry передается в переменную txtName внутри функции my_setup
. Для этого ее располагают слева от вызванной функции:
txtName = create_entry(10, 10, "Имя", 150)
Собственно, в чем прелесть этой функции? А в том, что я теперь могу быстро создать хоть 5 полей:
def my_setup(gui):
gui.geometry("300x200")
txtName = create_entry(10, 10, "Имя", 150)
# следите как я постепенно увеличиваю значения координаты y, для второго 40
txtSecondName = create_entry(10, 40, "Фамилия", 150)
txtPatronymic = create_entry(10, 70, "Отчество", 150) # двигаюсь по 30px, для третьего 70
txtGroup = create_entry(10, 100, "Группа", 150) # для четвертого 100
txtAge = create_entry(10, 130, "Возраст", 150) # для пятого 130
вот так получится:
кстати я могу сразу все эти поля заполнить:
def my_setup(gui):
gui.geometry("300x200")
txtName = create_entry(10, 10, "Имя", 150)
txtSecondName = create_entry(10, 40, "Фамилия", 150)
txtPatronymic = create_entry(10, 70, "Отчество", 150)
txtGroup = create_entry(10, 100, "Группа", 150)
txtAge = create_entry(10, 130, "Возраст", 150)
# добавил заполнение полей
txtName.insert(0, "Катя")
txtSecondName.insert(0, "Маргариткина")
txtPatronymic.insert(0, "Цветущая")
txtGroup.insert(0, "АМБ-20")
txtAge.insert(0, "17")
но, если я захочу значение поле поменять, то нельзя просто взять и написать новый insert
def my_setup(gui):
gui.geometry("300x200")
txtName = create_entry(10, 10, "Имя", 150)
txtSecondName = create_entry(10, 40, "Фамилия", 150)
txtPatronymic = create_entry(10, 70, "Отчество", 150)
txtGroup = create_entry(10, 100, "Группа", 150)
txtAge = create_entry(10, 130, "Возраст", 150)
txtName.insert(0, "Катя")
txtSecondName.insert(0, "Маргариткина")
txtPatronymic.insert(0, "Цветущая")
txtGroup.insert(0, "АМБ-20")
txtAge.insert(0, "17")
# пробую поменять
txtName.insert(0, "Оля")
получится вот так:
поэтому перед заменой значения надо очищать поле:
def my_setup(gui):
gui.geometry("300x200")
txtName = create_entry(10, 10, "Имя", 150)
txtSecondName = create_entry(10, 40, "Фамилия", 150)
txtPatronymic = create_entry(10, 70, "Отчество", 150)
txtGroup = create_entry(10, 100, "Группа", 150)
txtAge = create_entry(10, 130, "Возраст", 150)
txtName.insert(0, "Катя")
txtSecondName.insert(0, "Маргариткина")
txtPatronymic.insert(0, "Цветущая")
txtGroup.insert(0, "АМБ-20")
txtAge.insert(0, "17")
txtName.delete(0, END) # удаляю старый текст
txtName.insert(0, "Оля")
теперь все ок:
И так теперь обладая этими знаниями напишите программу:
Написать калькулятор который позволяет сложить два числа