Перейти к содержимому

Как сделать калькулятор в python с графическим интерфейсом

  • автор:

GUI Калькулятор на Python tkinter

Статьи

Автор Admin На чтение 9 мин Просмотров 8.5к. Опубликовано 02.03.2023

Введение

В ходе статьи напишем GUI калькулятор на языке программирования Python с использованием модуля tkinter.

Написание GUI калькулятора

Для начала импортируем библиотеку tkinter:

from tkinter import *

Создадим объект класса Tk(), укажем разрешение окна 268×288, заголовок «Калькулятор» и запретим возможность изменять разрешение окна:

from tkinter import * root = Tk() root.geometry("268x288") root.title("Калькулятор") root.resizable(0, 0) root.mainloop()

Создадим виджет Frame() и отобразим его методом grid():

from tkinter import * root = Tk() root.geometry("268x288") root.title("Калькулятор") root.resizable(0, 0) frame_input = Frame(root) frame_input.grid(row=0, column=0, columnspan=4, sticky="nsew") root.mainloop()

Добавим текстовое поле (виджет Entry()) на фрейм, укажем шрифт Arial 15 размера жирного начертания, толщину 24 и запретим возможность писать в нём. Отобразим его методом pack():

from tkinter import * root = Tk() root.geometry("268x288") root.title("Калькулятор") root.resizable(0, 0) frame_input = Frame(root) frame_input.grid(row=0, column=0, columnspan=4, sticky="nsew") input_field = Entry(frame_input, font='Arial 15 bold', width=24, state="readonly") input_field.pack(fill=BOTH) root.mainloop()

Далее создадим кортеж, в котором будут храниться кнопки будущего калькулятора:

from tkinter import * root = Tk() root.geometry("268x288") root.title("Калькулятор") root.resizable(0, 0) frame_input = Frame(root) frame_input.grid(row=0, column=0, columnspan=4, sticky="nsew") input_field = Entry(frame_input, font='Arial 15 bold', width=24, state="readonly") input_field.pack(fill=BOTH) buttons = (('7', '8', '9', '/', '4'), ('4', '5', '6', '*', '4'), ('1', '2', '3', '-', '4'), ('0', '.', '=', '+', '4') ) root.mainloop()

Создадим пустую переменную expression строкового типа данных. Она нам пригодится для избежания ошибок в будущем. Также добавим кнопку, которая в последующем
будет служить для очищения текстового поля:

from tkinter import * root = Tk() root.geometry("268x288") root.title("Калькулятор") root.resizable(0, 0) frame_input = Frame(root) frame_input.grid(row=0, column=0, columnspan=4, sticky="nsew") input_field = Entry(frame_input, font='Arial 15 bold', width=24, state="readonly") input_field.pack(fill=BOTH) buttons = (('7', '8', '9', '/', '4'), ('4', '5', '6', '*', '4'), ('1', '2', '3', '-', '4'), ('0', '.', '=', '+', '4') ) expression = "" button = Button(root, text='C', command=lambda: bt_clear()) button.grid(row=1, column=3, sticky="nsew") root.mainloop()

Теперь добавим основные кнопки калькулятора с помощью цикла. И в основном, и во вложенном циклах будет по 4 итерации. Во вложенном цикле создаётся кнопка, с шириной 2, и высотой 3. Текстом будет являться поиндексное значение из кортежа buttons. Команда будет задаваться с помощью анонимной функции lambda, позиционироваться кнопки будут с помощью метода grid():

from tkinter import * root = Tk() root.geometry("268x288") root.title("Калькулятор") root.resizable(0, 0) frame_input = Frame(root) frame_input.grid(row=0, column=0, columnspan=4, sticky="nsew") input_field = Entry(frame_input, font='Arial 15 bold', width=24, state="readonly") input_field.pack(fill=BOTH) buttons = (('7', '8', '9', '/', '4'), ('4', '5', '6', '*', '4'), ('1', '2', '3', '-', '4'), ('0', '.', '=', '+', '4') ) expression = "" button = Button(root, text='C', command=lambda: bt_clear()) button.grid(row=1, column=3, sticky="nsew") for row in range(4): for col in range(4): Button(root, width=2, height=3, text=buttons[row][col], command=lambda row=row, col=col: btn_click(buttons[row][col])).grid(row=row + 2, column=col, sticky="nsew", padx=1, pady=1) root.mainloop()

Создадим функцию btn_click(), и в качестве аргумента укажем item. Сделаем переменную expression глобальной, после чего добавим конструкцию try … except:

from tkinter import * def btn_click(item): global expression try: pass except: pass root = Tk() root.geometry("268x288") root.title("Калькулятор") root.resizable(0, 0) frame_input = Frame(root) frame_input.grid(row=0, column=0, columnspan=4, sticky="nsew") input_field = Entry(frame_input, font='Arial 15 bold', width=24, state="readonly") input_field.pack(fill=BOTH) buttons = (('7', '8', '9', '/', '4'), ('4', '5', '6', '*', '4'), ('1', '2', '3', '-', '4'), ('0', '.', '=', '+', '4') ) expression = "" button = Button(root, text='C', command=lambda: bt_clear()) button.grid(row=1, column=3, sticky="nsew") for row in range(4): for col in range(4): Button(root, width=2, height=3, text=buttons[row][col], command=lambda row=row, col=col: btn_click(buttons[row][col])).grid(row=row + 2, column=col, sticky="nsew", padx=1, pady=1) root.mainloop()

В try мы даём возможность писать в текстовое поле, приведя параметр state в normal. Далее к expression прибавляем item. И вводим результат в текстовое поле:

from tkinter import * def btn_click(item): global expression try: input_field['state'] = "normal" expression += item input_field.insert(END, item) except: pass root = Tk() root.geometry("268x288") root.title("Калькулятор") root.resizable(0, 0) frame_input = Frame(root) frame_input.grid(row=0, column=0, columnspan=4, sticky="nsew") input_field = Entry(frame_input, font='Arial 15 bold', width=24, state="readonly") input_field.pack(fill=BOTH) buttons = (('7', '8', '9', '/', '4'), ('4', '5', '6', '*', '4'), ('1', '2', '3', '-', '4'), ('0', '.', '=', '+', '4') ) expression = "" button = Button(root, text='C', command=lambda: bt_clear()) button.grid(row=1, column=3, sticky="nsew") for row in range(4): for col in range(4): Button(root, width=2, height=3, text=buttons[row][col], command=lambda row=row, col=col: btn_click(buttons[row][col])).grid(row=row + 2, column=col, sticky="nsew", padx=1, pady=1) root.mainloop()

Зададим условие, что если на;ата кнопка «равно», то будет подсчитываться результат методом eval(). После чего результат будет выведен в текстовое поле, а expression обнулится. В конце try снова замораживаем текстовое поле:

from tkinter import * def btn_click(item): global expression try: input_field['state'] = "normal" expression += item input_field.insert(END, item) if item == '=': result = str(eval(expression[:-1])) input_field.insert(END, result) expression = "" input_field['state'] = "readonly" except: pass root = Tk() root.geometry("268x288") root.title("Калькулятор") root.resizable(0, 0) frame_input = Frame(root) frame_input.grid(row=0, column=0, columnspan=4, sticky="nsew") input_field = Entry(frame_input, font='Arial 15 bold', width=24, state="readonly") input_field.pack(fill=BOTH) buttons = (('7', '8', '9', '/', '4'), ('4', '5', '6', '*', '4'), ('1', '2', '3', '-', '4'), ('0', '.', '=', '+', '4') ) expression = "" button = Button(root, text='C', command=lambda: bt_clear()) button.grid(row=1, column=3, sticky="nsew") for row in range(4): for col in range(4): Button(root, width=2, height=3, text=buttons[row][col], command=lambda row=row, col=col: btn_click(buttons[row][col])).grid(row=row + 2, column=col, sticky="nsew", padx=1, pady=1) root.mainloop()

В except мы будем ловить ошибку ZeroDivisionError, и говорить, что деление на 0 запрещено.
Также добавим ошибку синтаксиса, при которой будет просто выводиться слово «Ошибка»:

from tkinter import * def btn_click(item): global expression try: input_field['state'] = "normal" expression += item input_field.insert(END, item) if item == '=': result = str(eval(expression[:-1])) input_field.insert(END, result) expression = "" input_field['state'] = "readonly" except ZeroDivisionError: input_field.delete(0, END) input_field.insert(0, 'Ошибка (деление на 0)') except SyntaxError: input_field.delete(0, END) input_field.insert(0, 'Ошибка') root = Tk() root.geometry("268x288") root.title("Калькулятор") root.resizable(0, 0) frame_input = Frame(root) frame_input.grid(row=0, column=0, columnspan=4, sticky="nsew") input_field = Entry(frame_input, font='Arial 15 bold', width=24, state="readonly") input_field.pack(fill=BOTH) buttons = (('7', '8', '9', '/', '4'), ('4', '5', '6', '*', '4'), ('1', '2', '3', '-', '4'), ('0', '.', '=', '+', '4') ) expression = "" button = Button(root, text='C', command=lambda: bt_clear()) button.grid(row=1, column=3, sticky="nsew") for row in range(4): for col in range(4): Button(root, width=2, height=3, text=buttons[row][col], command=lambda row=row, col=col: btn_click(buttons[row][col])).grid(row=row + 2, column=col, sticky="nsew", padx=1, pady=1) root.mainloop()

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

from tkinter import * def btn_click(item): global expression try: input_field['state'] = "normal" expression += item input_field.insert(END, item) if item == '=': result = str(eval(expression[:-1])) input_field.insert(END, result) expression = "" input_field['state'] = "readonly" except ZeroDivisionError: input_field.delete(0, END) input_field.insert(0, 'Ошибка (деление на 0)') except SyntaxError: input_field.delete(0, END) input_field.insert(0, 'Ошибка') def bt_clear(): global expression expression = "" input_field['state'] = "normal" input_field.delete(0, END) input_field['state'] = "readonly" root = Tk() root.geometry("268x288") root.title("Калькулятор") root.resizable(0, 0) frame_input = Frame(root) frame_input.grid(row=0, column=0, columnspan=4, sticky="nsew") input_field = Entry(frame_input, font='Arial 15 bold', width=24, state="readonly") input_field.pack(fill=BOTH) buttons = (('7', '8', '9', '/', '4'), ('4', '5', '6', '*', '4'), ('1', '2', '3', '-', '4'), ('0', '.', '=', '+', '4') ) expression = "" button = Button(root, text='C', command=lambda: bt_clear()) button.grid(row=1, column=3, sticky="nsew") for row in range(4): for col in range(4): Button(root, width=2, height=3, text=buttons[row][col], command=lambda row=row, col=col: btn_click(buttons[row][col])).grid(row=row + 2, column=col, sticky="nsew", padx=1, pady=1) root.mainloop()

Заключение

В ходе статьи мы с Вами написали код для GUI калькулятора на языке программирования Python с использованием модуля tkinter. Надеюсь Вам понравилась статья, желаю удачи и успехов! ��

Калькулятор

Многие программисты стараются изучать языки программирования с помощью написания достаточно простых программ. Один из вариантов – написание калькулятора. Конечно, можно посчитать в отладчике Python или запустив консоль. Но гораздо лучше написать на python свой калькулятор с графическим интерфейсом.

Считаем в консоле

Чтобы посчитать математические выражения можно запустить консоль. Запустить python. После этого набираем математические выражения и получаем ответ. Для этого даже не надо уметь программировать.

Делаем простой калькулятор

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

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

В нашем случае мы разберем, как создать простой графический калькулятор на Python 3. Для реализации графического интерфейса воспользуемся стандартным пакетом Tkinter. Он входит в состав Python 3. Соответственно, если у вас установлен Python, то дополнительно не надо ничего устанавливать.

В первых строках файла calculator.py подключаем библиотечные функции:

  • Tkinter для графического интерфейса;
  • Decimal для вычислений с большей точность, так как точности float не достаточно.

Импорт библиотек и исходные данные

Создаем окно приложения — объект Tk с заголовком Calculator. Во вложенном кортеже buttons будут храниться обозначения для кнопок. В список stack будем добавлять введенные числа и операции, которые надо совершить. activeStr предназначен для хранения набираемого числа.

from tkinter import * from decimal import * root = Tk() root.title('Calculator') buttons = (('7', '8', '9', '/', '4'), ('4', '5', '6', '*', '4'), ('1', '2', '3', '-', '4'), ('0', '.', '=', '+', '4') ) activeStr = '' stack = []

Вычисление результата

Функция calculate получает из списка stack операнды и операцию которую над ними надо произвести. Результат отображается в надписи label. Получать из списка строки будем с помощью метода pop.

def calculate(): global stack global label result = 0 operand2 = Decimal(stack.pop()) operation = stack.pop() operand1 = Decimal(stack.pop()) if operation == '+': result = operand1 + operand2 if operation == '-': result = operand1 - operand2 if operation == '/': result = operand1 / operand2 if operation == '*': result = operand1 * operand2 label.configure(text=str(result))

Обработка нажатия

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

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

def click(text): global activeStr global stack if text == 'CE': stack.clear() activeStr = '' label.configure(text='0') elif '0' = 2: stack.append(label['text']) calculate() stack.clear() stack.append(label['text']) activeStr = '' if text != '=': stack.append(text) else: if text != '=': stack.append(label['text']) stack.append(text) activeStr = '' label.configure(text='0')

Внешний вид

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

label = Label(root, text='0', width=35) label.grid(row=0, column=0, columnspan=4, sticky="nsew") button = Button(root, text='CE', command=lambda text='CE': click(text)) button.grid(row=1, column=3, sticky="nsew") for row in range(4): for col in range(4): button = Button(root, text=buttons[row][col], command=lambda row=row, col=col: click(buttons[row][col])) button.grid(row=row + 2, column=col, sticky="nsew") root.grid_rowconfigure(6, weight=1) root.grid_columnconfigure(4, weight=1) root.mainloop()

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

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

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

Как сделать калькулятор в python с графическим интерфейсом

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Позиционирование окна в центре экрана

Чтобы разместить окно Tkinter приложения в центре экрана, необходимо:

  • Воспользоваться методами winfo_screenwidth() и winfo_screenheight() для получения ширины и высоты экрана соответственно.
  • Передать в метод geometry() координаты x и y, равные половине ширины и высоты экрана за минусом половины ширины и высоты окна приложения.

Код будет выглядеть так:

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Размещение элементов интерфейса в Tkinter

Элементы интерфейса в Tkinter называются виджетами. Существует три основных способа расположения виджетов на поверхности окна: pack(), place() и grid(). Каждый из этих методов имеет свои преимущества и недостатки, и выбор оптимального способа зависит от конкретной ситуации.

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

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

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

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

grid() – упорядочивает виджеты в сетку из рядов и столбцов. Самый гибкий и мощный, позволяет создавать сложные интерфейсы, состоящие из виджетов разных размеров. Сложнее в использовании, чем pack(), поскольку требует больше кода для компоновки виджетов.

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

В целом, pack() хорошо подходит для простых интерфейсов, place() – для более сложных, а grid() используют для создания сложных интерфейсов, которым нужна адаптивность, особое позиционирование или растягивание виджетов на несколько строк / столбцов.

Связывание виджетов с функциями

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

Метод command () используется для прямого связывания функции с нажатием кнопки:

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

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

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Назначение кнопке анонимной функции:

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Связывание кнопки с частично примененной функцией:

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

Практика

Задание 1

Создайте Tkinter интерфейс для программы, которая получает от пользователя текст с помощью виджетов Entry и Button , а затем выводит полученную строку в терминале.

Ожидаемый результат:

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter �� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

�� Самоучитель по Python для начинающих. Часть 20: Графический интерфейс на Tkinter

import tkinter as tk from tkinter import ttk from math import sqrt class Calculator: def __init__(self, master): self.master = master self.master.title("Калькулятор") self.master.geometry("380x140") self.number_entry = ttk.Entry(self.master, width=20) self.number_entry.grid(row=0, column=0, columnspan=5, padx=5, pady=5) self.button_1 = ttk.Button(self.master, text="1", command=lambda: self.button_click(1)) self.button_2 = ttk.Button(self.master, text="2", command=lambda: self.button_click(2)) self.button_3 = ttk.Button(self.master, text="3", command=lambda: self.button_click(3)) self.button_4 = ttk.Button(self.master, text="4", command=lambda: self.button_click(4)) self.button_5 = ttk.Button(self.master, text="5", command=lambda: self.button_click(5)) self.button_6 = ttk.Button(self.master, text="6", command=lambda: self.button_click(6)) self.button_7 = ttk.Button(self.master, text="7", command=lambda: self.button_click(7)) self.button_8 = ttk.Button(self.master, text="8", command=lambda: self.button_click(8)) self.button_9 = ttk.Button(self.master, text="9", command=lambda: self.button_click(9)) self.button_0 = ttk.Button(self.master, text="0", command=lambda: self.button_click(0)) self.button_clear = ttk.Button(self.master, text="C", command=self.button_clear) self.button_add = ttk.Button(self.master, text="+", command=self.button_add) self.button_equal = ttk.Button(self.master, text="=", command=self.button_equal) self.button_subtract = ttk.Button(self.master, text="-", command=self.button_subtract) self.button_multiply = ttk.Button(self.master, text="*", command=self.button_multiply) self.button_divide = ttk.Button(self.master, text="/", command=self.button_divide) self.button_floor_div = ttk.Button(self.master, text="//", command=self.button_floor_div) self.button_modulus = ttk.Button(self.master, text="%", command=self.button_modulus) self.button_sqrt = ttk.Button(self.master, text="√", command=self.button_sqrt) self.button_neg = ttk.Button(self.master, text="+/-", command=self.button_neg) self.button_1.grid(row=1, column=0) self.button_2.grid(row=1, column=1) self.button_3.grid(row=1, column=2) self.button_add.grid(row=1, column=3) self.button_floor_div.grid(row=1, column=4) self.button_4.grid(row=2, column=0) self.button_5.grid(row=2, column=1) self.button_6.grid(row=2, column=2) self.button_subtract.grid(row=2, column=3) self.button_modulus.grid(row=2, column=4) self.button_7.grid(row=3, column=0) self.button_8.grid(row=3, column=1) self.button_9.grid(row=3, column=2) self.button_multiply.grid(row=3, column=3) self.button_sqrt.grid(row=3, column=4) self.button_clear.grid(row=4, column=0) self.button_0.grid(row=4, column=1) self.button_equal.grid(row=4, column=2) self.button_divide.grid(row=4, column=3) self.button_neg.grid(row=4, column=4) self.f_num = 0 self.math = "" def button_click(self, number): current = self.number_entry.get() self.number_entry.delete(0, tk.END) self.number_entry.insert(0, str(current) + str(number)) def button_clear(self): self.number_entry.delete(0, tk.END) def button_add(self): first_number = self.number_entry.get() self.math = "addition" self.f_num = int(first_number) self.number_entry.delete(0, tk.END) def button_equal(self): second_number = self.number_entry.get() self.number_entry.delete(0, tk.END) if self.math == "addition": self.number_entry.insert(0, self.f_num + int(second_number)) if self.math == "multiplication": self.number_entry.insert(0, self.f_num * int(second_number)) if self.math == "division": self.number_entry.insert(0, self.f_num / int(second_number)) if self.math == "floor_div": self.number_entry.insert(0, self.f_num // int(second_number)) if self.math == "modulus": self.number_entry.insert(0, self.f_num % int(second_number)) def button_subtract(self): first_number = self.number_entry.get() self.math = "subtraction" self.f_num = int(first_number) self.number_entry.delete(0, tk.END) def button_multiply(self): first_number = self.number_entry.get() self.math = "multiplication" self.f_num = int(first_number) self.number_entry.delete(0, tk.END) def button_divide(self): first_number = self.number_entry.get() self.math = "division" self.f_num = int(first_number) self.number_entry.delete(0, tk.END) def button_floor_div(self): first_number = self.number_entry.get() self.math = "floor_div" self.f_num = int(first_number) self.number_entry.delete(0, tk.END) def button_modulus(self): first_number = self.number_entry.get() self.math = "modulus" self.f_num = int(first_number) self.number_entry.delete(0, tk.END) def button_sqrt(self): number = float(self.number_entry.get()) result = sqrt(number) if result.is_integer(): self.number_entry.delete(0, tk.END) self.number_entry.insert(0, int(result)) else: self.number_entry.delete(0, tk.END) self.number_entry.insert(0, result) def button_neg(self): current = self.number_entry.get() if current.startswith("-"): current = current[1:] else: current = "-" + current self.number_entry.delete(0, tk.END) self.number_entry.insert(0, current) if __name__ == '__main__': root = tk.Tk() calc = Calculator(root) root.mainloop() 

Подведем итоги

В этой статье мы рассмотрели основы создания GUI для Python -программ и научились использовать основные виджеты Tkinter . В следующей главе будем изучать основы разработки игр с Pygame .

  1. Особенности, сферы применения, установка, онлайн IDE
  2. Все, что нужно для изучения Python с нуля – книги, сайты, каналы и курсы
  3. Типы данных: преобразование и базовые операции
  4. Методы работы со строками
  5. Методы работы со списками и списковыми включениями
  6. Методы работы со словарями и генераторами словарей
  7. Методы работы с кортежами
  8. Методы работы со множествами
  9. Особенности цикла for
  10. Условный цикл while
  11. Функции с позиционными и именованными аргументами
  12. Анонимные функции
  13. Рекурсивные функции
  14. Функции высшего порядка, замыкания и декораторы
  15. Методы работы с файлами и файловой системой
  16. Регулярные выражения
  17. Основы скрапинга и парсинга
  18. Основы ООП: инкапсуляция и наследование
  19. Основы ООП: абстракция и полиморфизм
  20. Графический интерфейс на Tkinter
  21. Основы разработки игр на Pygame
  22. Основы работы с SQLite
  23. Основы веб-разработки на Flask
  24. Основы работы с NumPy
  25. Основы анализа данных с Pandas

Пишем десктоп-приложение на Python с помощью Tkinter

Знакомимся с библиотекой Tkinter — пишем на Python кросс-платформенный калькулятор, который рассчитывает вес человека.

Иллюстрация: Merry Mary для Skillbox Media

Антон Яценко

Антон Яценко
Изучает Python, его библиотеки и занимается анализом данных. Любит путешествовать в горах.

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

Одна из таких библиотек — Tkinter. Она входит в стандартный пакет Python и позволяет создавать приложения для Windows, mac OS и Linux. Давайте разберёмся, как устроена эта библиотека, и напишем десктопный калькулятор, помогающий рассчитать вес человека.

Что такое GUI и как с ним работать в Python

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

Противоположность графическому интерфейсу — командная строка, позволяющая управлять приложением с помощью текстовых команд. Такой интерфейс реализован в терминале macOS и командной строке Windows.

Для работы с GUI в Python есть четыре библиотеки:

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

Знакомимся с Tkinter

Tkinter — это удобный интерфейс для работы со средствами Tk. Приложения, созданные на основе этой библиотеки, кросс-платформенные, то есть могут запускаться на разных операционных системах.

Схематично работу с Tkinter можно представить в виде четырёх шагов:

Что здесь происходит:

  • Мы подключаем библиотеку Tkinter с помощью директивы import.
  • Создаём главное окно приложения, в котором будут размещаться все графические элементы.
  • Добавляем виджеты — визуальные элементы, выполняющие определённые действия.
  • Создаём главный цикл событий — он включает в себя все события, происходящие при взаимодействии пользователя с интерфейсом.

Ключевые объекты в работе с Tkinter — виджеты. Это аналоги тегов из HTML, которые позволяют создавать интерактивные и неинтерактивные элементы, например надписи или кнопки. Всего их 18, но чаще всего используют следующие:

  • Button — кнопки;
  • Canvas — «холст», на котором рисуют графические фигуры;
  • Entry — виджет для создания полей ввода;
  • Label — контейнер для размещения текста или изображения;
  • Menu — виджет для создания пунктов меню.

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

Создаём калькулятор для расчёта индекса массы тела

Мы напишем калькулятор индекса массы тела. ИМТ — это важный медицинский показатель, который позволяет оценить, есть ли у человека избыточный вес или ожирение. Он рассчитывается по следующей формуле: ​​

ИМТ = вес (в кг) / рост 2 (в метрах)

Результаты расчётов оценивают с помощью специальной таблицы. У врачей она имеет много градаций, мы же воспользуемся упрощённой версией:

Шаг 1

Запускаем Python и импортируем Tkinter

Писать код на Python лучше всего в специальной IDE, например в PyCharm или Visual Studio Code. Они подсвечивают синтаксис и предлагают продолжение кода — это сильно упрощает работу программиста. Весь код из этой статьи мы писали в Visual Studio Code.

Библиотека Tkinter предустановлена в Python. Поэтому её нужно только импортировать:

Шаг 2

Делаем эскиз интерфейса и продумываем логику приложения

Прежде чем писать код, необходимо ответить на несколько вопросов:

  • Какие данные мы хотим получить от пользователя и в каком виде?
  • Какое событие будет запускать расчёт ИМТ: нажатие кнопки, получение приложением всех необходимых данных или что-то другое?
  • Как будем показывать результат?

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

Схематично графический интерфейс нашего калькулятора будет выглядеть так:

Теперь попробуем реализовать интерфейс и работу калькулятора с помощью Python и Tkinter.

Шаг 3

Создаём основное окно и указываем название приложения

После импорта библиотеки в Python загрузим её методы:

Мы не указали размер окна, поэтому название приложения не помещается в него полностью. Исправим это с помощью метода geometry:

Шаг 4

Создаём виджет Frame для контроля за расположением элементов

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

  • pack — используется, когда мы работаем с контейнерами для элементов. Позволяет позиционировать кнопки, надписи или другие элементы внутри контейнеров.
  • place — позволяет позиционировать элементы, указывая точные координаты.
  • grid — размещает элементы по ячейкам условной сетки, разделяющей окно приложения.

Мы воспользуемся комбинацией методов pack и grid. Для начала создадим виджет Frame для размещения надписей, полей ввода и кнопок. Подробное описание работы виджета есть в документации. Мы же используем только два свойства: padx и pady.

Обозначим отступы по вертикали и горизонтали в 10 пикселей для элементов, которые будут расположены внутри Frame:

Сейчас элемент расположен в центре окна, но он займёт правильное положение, когда мы напишем другие элементы.

Добавим вторую надпись о весе аналогичным образом, но при позиционировании в grid укажем следующую, четвёртую строку:

Теперь добавим поля для ввода пользовательской информации, используя виджет Entry:

Всё получилось. Остаётся по аналогии добавить поле ввода веса:

Теперь добавим кнопку, которая будет запускать расчёт ИМТ. Сделаем это с помощью виджета Button:

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

Шаг 6

Получаем информацию из виджетов Entry и рассчитываем индекс массы тела

Напишем простую функцию и разберём её построчно:

Всё работает. Функция получает данные из полей ввода и рассчитывает индекс массы тела, показывая результат на экране.

Приведём код полностью без комментариев

from tkinter import * from tkinter import messagebox def calculate_bmi(): kg = int(weight_tf.get()) m = int(height_tf.get())/100 bmi = kg/(m*m) bmi = round(bmi, 1) if bmi < 18.5: messagebox.showinfo('bmi-pythonguides', f'ИМТ = соответствует недостаточному весу') elif (bmi > 18.5) and (bmi < 24.9): messagebox.showinfo('bmi-pythonguides', f'ИМТ = соответствует нормальному весу') elif (bmi > 24.9) and (bmi < 29.9): messagebox.showinfo('bmi-pythonguides', f'ИМТ = соответствует избыточному весу') else: messagebox.showinfo('bmi-pythonguides', f'ИМТ = соответствует ожирению') window = Tk() window.title('Калькулятор индекса массы тела (ИМТ)') window.geometry('400x300') frame = Frame( window, padx=10, pady=10 ) frame.pack(expand=True) height_lb = Label( frame, text="Введите свой рост (в см) " ) height_lb.grid(row=3, column=1) weight_lb = Label( frame, text="Введите свой вес (в кг) ", ) weight_lb.grid(row=4, column=1) height_tf = Entry( frame, ) height_tf.grid(row=3, column=2, pady=5) weight_tf = Entry( frame, ) weight_tf.grid(row=4, column=2, pady=5) cal_btn = Button( frame, text='Рассчитать ИМТ', command=calculate_bmi ) cal_btn.grid(row=5, column=2) window.mainloop()

Что дальше?

Узнать о возможностях Tkinter и особенностях работы с виджетами можно в официальной документации. А если хотите найти больше реальных примеров для практики, советуем две книги:

  • Python GUI Programming with Tkinter. Develop responsive and powerful GUI applications with Tkinter, Алан Мур.
  • Tkinter GUI Programming by Example, Дэвид Лав.

Больше интересного про код в нашем телеграм-канале. Подписывайтесь!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *