Работа с интерфейсом / подсказка к 1 задачке

1

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

И так, чтобы создать приложение с интерфейсом в python достаточно написать следующее:

from tkinter import * # подключаем библиотечку для работы с интерфейсом

gui = Tk() # создаем интерфейс в памяти
gui.mainloop() # запускаем интерфейс и отображаем его пользователю

если это запустить увидим следующее:

тут важный момент — вот этот вызов функции gui.mainloop() должен быть обязательно в конце файла.

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

from tkinter import *


# добавили новую функцию, я назвал ее my_setup, вы можете назвать ее как хотите
def my_setup(gui):
    print("Настройка интерфейса") # в ней просто пока сообщение вывожу


gui = Tk() # создаем интерфейс в памяти
my_setup(gui) # <<< НОВАЯ СТРОЧКА, собственно вызов нашей функции
gui.mainloop() # запускаем интерфейс и отображаем его пользователю

если запустить, то все сработает как прежде, только еще и в консоль будет написано Настройка интерфейса

Вообще полезно понимать, как работает программа в таком случае. Вот последовательность вызова команд при таком коде

Добавляем поле для ввода

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

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

tkinter – один из простейших фреймворков для разработки интерфейсов, но нормального редактора к сожалению, не имеет. Зато он встроен в питон и его можно сразу использовать. Так что придется запастись линейкой и бумажкой для расчетов.

И так, первое что хочется сделать это изменить размеры окна.

Для этого есть функция geometry где указываются размеры в пикселях:

def my_setup(gui):
    gui.geometry("300x200")

получается такое окно:

теперь попробуем добавить на него поле для ввода. Делается это так:

def my_setup(gui):
    gui.geometry("300x200")

    txtName = Entry(gui) # создали поле для ввода
    txtName.place(x=10,y=10, width=150) # поставили его на форму

надо помнить, что во всех интерфейсах центр координат располагается в левом верхнем углу, а ось y перевернута, поэтому если запустить, то получаем такое:

Добавляем кнопку

Давайте теперь добавим кнопку, кликая на которую будем получать приветствие:

def my_setup(gui):
    gui.geometry("300x200")

    txtName = Entry(gui)
    txtName.place(x=10, y=10, width=150)
    
    # у кнопки указываем свойство текст
    button = Button(gui, text="Привет!")
    # тут получается, что координату X считаю, как 10 пикселей отступ слева, 
    # + 150px -- ширина поля для ввода
    # + 10px -- отступ от поля для ввода
    button.place(x=10 + 150 + 10, y=10) 

о как:

теперь попробуем добавить реакцию на клик.

Чтобы на кнопку можно было кликнуть и получить какую-то реакцию необходимо создать функцию которая будет вызываться. Делается это так:

from tkinter import *

 
# добавил новую функцию
def on_button_click():
    print("Привет!")


def my_setup(gui):
    gui.geometry("300x200")

    txtName = Entry(gui)
    txtName.place(x=10,y=10, width=150)
		
    # добавил аргумент command, куда передал новую нашу новую функцию on_button_click
    button = Button(gui, text="Привет!", command=on_button_click)
    button.place(x=150 + 10 + 10, y=10)

# ...

запускаем и проверяем:

Считываем текст с поля для ввода

Допустим я хочу, чтобы мне выводился текст с поля для ввода, как мне это сделать?

У поля для ввода есть функция get() которая позволяет узнать что введено в поле, работает это так:

def on_button_click():
    print(txtName.get()) # запрашиваю текст с поля 


def my_setup(gui):
    gui.geometry("300x200")

    txtName = Entry(gui)
    txtName.place(x=10,y=10, width=150)

        
    button = Button(gui, text="Привет!", command=on_button_click)
    button.place(x=150 + 10 + 10, y=10)

ну во всяком случае должно работать, на деле ж получаем:

ошибка выглядит так:

Exception in Tkinter callback
Traceback (most recent call last):
  File "D:\_DISTR\WPy32-3760\python-3.7.6\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "D:\_DISTR\WPy32-3760\settings\.spyder-py3\temp.py", line 5, in on_button_click
    print(txtName.get())
NameError: name 'txtName' is not defined

в ней сказано что функция on_button_click ничего не знает про txtName и поэтому не знает что ей делать. Оно и понятно почему.

txtName создается внутри функции my_setup и только внутри нее можно работать с этой переменной. Эта так называемая область видимость переменных. Каждая функция знает только про переменные, которые находятся внутри нее.

Чтобы обойти эту проблему мы можем запихать функцию внутрь функции, это не очень хороший подход, но на пару раз сойдет.

И так, утаскиваем on_button_click внутрь my_setup


# удаляем
# def on_button_click():
#    print(txtName.get())

def my_setup(gui):
    gui.geometry("300x200")

    txtName = Entry(gui)
    txtName.place(x=10,y=10, width=150)
    
    # объявляю функцию теперь здесь, прямо перед созданием кнопки
    def on_button_click():
        print(txtName.get()) 
        
    button = Button(gui, text="Привет!", command=on_button_click)
    button.place(x=150 + 10 + 10, y=10)

проверяем:

Собственно, такие дела. Теперь добавьте еще одну кнопку и сделаете задание:

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