Статья Пишем графическую оболочку на Python - часть 3

explorer

explorer

Red Team
05.08.2018
824
1 741
Часть 1 Часть 2

Всем привет!

В предыдущих частях мы познакомились с двумя методами позиционирования элементов - pack() и place(). Для выполнения простых задач они вполне подходят. А если у нас планируется программа, где будет сложный интерфейс, или просто большое количество элементов, то самым лучшим методом будет несомненно grid(). На первый взгляд метод немного посложнее, но разобравшись в сути, он не станет выглядеть сложным.

Метод grid() как ясно из названия, представляет собой сетку. Выглядит схематично это следующим образом:

tabl.jpg


То есть окно программы делится на столбцы и строки, а нумерация начинается с нуля. И прежде чем начать программировать, лучше всего начертить будущую программу на обычном листочке в клеточку. Это даст полное представление в какие ячейки что помещать. Столбцы и строки можно объединять с помощью columnspan и rowspan.

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

grid.png


Здесь у нас 4 кнопки для вычисления сложения, вычитания, умножения и деления, а также 2 однострочных текстовых поля для введения цифр. И в нижней части будут показываться результаты вычислений в многострочном текстовом поле. Как видно многострочное поле занимает по ширине 3 колонки, поэтому необходимо объединить колонки с помощью columnspan.

Согласно первой табличке, легко понять, что например кнопка minus- находиться в строке 0 и колонке 1. А теперь посмотрим код. Поскольку кнопки идут с левого верхнего угла, с них и нужно начинать.

Python:
plus_button = Button(text="plus +", width=14, command=plus)
plus_button.grid(row=0, column=0, padx=10, pady=5, sticky="n")

minus_button = Button(text="minus -", width=14, command=minus)
minus_button.grid(row=0, column=1, padx=10, pady=5, sticky="n")

multiply_button = Button(text="multiply *", width=14, command=multiply)
multiply_button.grid(row=1, column=0, padx=10, pady=5, sticky="n")

split_button = Button(text="divide /", width=14, command=split)
split_button.grid(row=1, column=1, padx=10, pady=5, sticky="n")
Суть метода по написанию мало отличается от предыдущих. После создания любого элемента, мы следующей строкой через точку указываем метод, и пишем позиционирование согласно сетке + делаем необходимые отступы, а также можно указать ориентацию по сторонам света с помощью sticky. Дальше у нас находятся однострочные текстовые поля для ввода данных.

Python:
first_number = Entry(width=4, justify=CENTER)
first_number.grid(row=0, column=2, pady=5, sticky="ns")

two_number = Entry(width=4, justify=CENTER)
two_number.grid(row=1, column=2, pady=5, sticky="ns")
И завершает главное окно многострочное текстовое поле. Всё аналогично - размеры поля + позиционирование, и в данном случае объединение колонок.

Python:
text = Text(root, width=40, height=10)
text.grid(row=2, column=0, columnspan=3, padx=10, sticky='nswe')
Ну и чтобы всё это хозяйство заработало, нужно написать функции, которые будут делать вычисления при нажатии на соответствующие кнопки.

Python:
def plus():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a+b)
    text.insert(END, res + '\n')


def minus():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a - b)
    text.insert(END, res + '\n')


def multiply():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a * b)
    text.insert(END, res + '\n')


def split():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a / b)
    text.insert(END, res + '\n')
Обратите внимание, что поскольку математические действия мы производим с целыми числами, данные полученные от полей с цифрами, мы заворачиваем в int. А чтобы результаты вычислений были каждый раз с новой строки, мы добавили перенос строки '\n'. Но поскольку строки и числа не могут быть вместе при вставке вычислений в поле, то предварительно мы переводим результаты вычислений в строку с помощью str.

Python:
from tkinter import *

root = Tk()
root.title("Метод grid")
root.geometry("346x250")
root.resizable(width=False, height=False)


def plus():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a+b)
    text.insert(END, res + '\n')


def minus():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a - b)
    text.insert(END, res + '\n')


def multiply():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a * b)
    text.insert(END, res + '\n')


def split():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a / b)
    text.insert(END, res + '\n')


plus_button = Button(text="plus +", width=14, command=plus)
plus_button.grid(row=0, column=0, padx=10, pady=5, sticky="n")

minus_button = Button(text="minus -", width=14, command=minus)
minus_button.grid(row=0, column=1, padx=10, pady=5, sticky="n")

multiply_button = Button(text="multiply *", width=14, command=multiply)
multiply_button.grid(row=1, column=0, padx=10, pady=5, sticky="n")

split_button = Button(text="divide /", width=14, command=split)
split_button.grid(row=1, column=1, padx=10, pady=5, sticky="n")

first_number = Entry(width=4, justify=CENTER)
first_number.grid(row=0, column=2, pady=5, sticky="ns")

two_number = Entry(width=4, justify=CENTER)
two_number.grid(row=1, column=2, pady=5, sticky="ns")

text = Text(root, width=40, height=10)
text.grid(row=2, column=0, columnspan=3, padx=10, sticky='nswe')

root.mainloop()

Теперь проверим работоспособность программы. Запускаем и сделаем все вычисления по-очереди. Всё работает.

grid2.png


Вот и разобрались с методом grid(), как видите ничего сложного. Именно этот метод я и использую в большинстве случаев.
А теперь домашнее задание.

Продолжите работу с калькулятором, добавив 3 кнопки - exponentiation возведение в степень, rootin извлечение корня и Clean для очистки многострочного поля.

grid3.png


В данном примере я сначала ввёл 3 и 4, проделал вычисления, и чтобы проверить правильно ли у нас работает возведение в степень и извлечение корня, ввёл 81.
3 в 4 степени = 81 а извлечение из 81 корня 4 степени = 3 Всё верно.
 
M

Miron_T32

New member
06.09.2018
3
0
Часть 1 Часть 2

Всем привет!

В предыдущих частях мы познакомились с двумя методами позиционирования элементов - pack() и place(). Для выполнения простых задач они вполне подходят. А если у нас планируется программа, где будет сложный интерфейс, или просто большое количество элементов, то самым лучшим методом будет несомненно grid(). На первый взгляд метод немного посложнее, но разобравшись в сути, он не станет выглядеть сложным.

Метод grid() как ясно из названия, представляет собой сетку. Выглядит схематично это следующим образом:

Посмотреть вложение 24944

То есть окно программы делится на столбцы и строки, а нумерация начинается с нуля. И прежде чем начать программировать, лучше всего начертить будущую программу на обычном листочке в клеточку. Это даст полное представление в какие ячейки что помещать. Столбцы и строки можно объединять с помощью columnspan и rowspan.

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

Посмотреть вложение 24945

Здесь у нас 4 кнопки для вычисления сложения, вычитания, умножения и деления, а также 2 однострочных текстовых поля для введения цифр. И в нижней части будут показываться результаты вычислений в многострочном текстовом поле. Как видно многострочное поле занимает по ширине 3 колонки, поэтому необходимо объединить колонки с помощью columnspan.

Согласно первой табличке, легко понять, что например кнопка minus- находиться в строке 0 и колонке 1. А теперь посмотрим код. Поскольку кнопки идут с левого верхнего угла, с них и нужно начинать.

Python:
plus_button = Button(text="plus +", width=14, command=plus)
plus_button.grid(row=0, column=0, padx=10, pady=5, sticky="n")

minus_button = Button(text="minus -", width=14, command=minus)
minus_button.grid(row=0, column=1, padx=10, pady=5, sticky="n")

multiply_button = Button(text="multiply *", width=14, command=multiply)
multiply_button.grid(row=1, column=0, padx=10, pady=5, sticky="n")

split_button = Button(text="divide /", width=14, command=split)
split_button.grid(row=1, column=1, padx=10, pady=5, sticky="n")
Суть метода по написанию мало отличается от предыдущих. После создания любого элемента, мы следующей строкой через точку указываем метод, и пишем позиционирование согласно сетке + делаем необходимые отступы, а также можно указать ориентацию по сторонам света с помощью sticky. Дальше у нас находятся однострочные текстовые поля для ввода данных.

Python:
first_number = Entry(width=4, justify=CENTER)
first_number.grid(row=0, column=2, pady=5, sticky="ns")

two_number = Entry(width=4, justify=CENTER)
two_number.grid(row=1, column=2, pady=5, sticky="ns")
И завершает главное окно многострочное текстовое поле. Всё аналогично - размеры поля + позиционирование, и в данном случае объединение колонок.

Python:
text = Text(root, width=40, height=10)
text.grid(row=2, column=0, columnspan=3, padx=10, sticky='nswe')
Ну и чтобы всё это хозяйство заработало, нужно написать функции, которые будут делать вычисления при нажатии на соответствующие кнопки.

Python:
def plus():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a+b)
    text.insert(END, res + '\n')


def minus():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a - b)
    text.insert(END, res + '\n')


def multiply():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a * b)
    text.insert(END, res + '\n')


def split():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a / b)
    text.insert(END, res + '\n')
Обратите внимание, что поскольку математические действия мы производим с целыми числами, данные полученные от полей с цифрами, мы заворачиваем в int. А чтобы результаты вычислений были каждый раз с новой строки, мы добавили перенос строки '\n'. Но поскольку строки и числа не могут быть вместе при вставке вычислений в поле, то предварительно мы переводим результаты вычислений в строку с помощью str.

Python:
from tkinter import *

root = Tk()
root.title("Метод grid")
root.geometry("346x250")
root.resizable(width=False, height=False)


def plus():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a+b)
    text.insert(END, res + '\n')


def minus():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a - b)
    text.insert(END, res + '\n')


def multiply():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a * b)
    text.insert(END, res + '\n')


def split():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a / b)
    text.insert(END, res + '\n')


plus_button = Button(text="plus +", width=14, command=plus)
plus_button.grid(row=0, column=0, padx=10, pady=5, sticky="n")

minus_button = Button(text="minus -", width=14, command=minus)
minus_button.grid(row=0, column=1, padx=10, pady=5, sticky="n")

multiply_button = Button(text="multiply *", width=14, command=multiply)
multiply_button.grid(row=1, column=0, padx=10, pady=5, sticky="n")

split_button = Button(text="divide /", width=14, command=split)
split_button.grid(row=1, column=1, padx=10, pady=5, sticky="n")

first_number = Entry(width=4, justify=CENTER)
first_number.grid(row=0, column=2, pady=5, sticky="ns")

two_number = Entry(width=4, justify=CENTER)
two_number.grid(row=1, column=2, pady=5, sticky="ns")

text = Text(root, width=40, height=10)
text.grid(row=2, column=0, columnspan=3, padx=10, sticky='nswe')

root.mainloop()

Теперь проверим работоспособность программы. Запускаем и сделаем все вычисления по-очереди. Всё работает.

Посмотреть вложение 24946

Вот и разобрались с методом grid(), как видите ничего сложного. Именно этот метод я и использую в большинстве случаев.
А теперь домашнее задание.

Продолжите работу с калькулятором, добавив 3 кнопки - exponentiation возведение в степень, rootin извлечение корня и Clean для очистки многострочного поля.

Посмотреть вложение 24947

В данном примере я сначала ввёл 3 и 4, проделал вычисления, и чтобы проверить правильно ли у нас работает возведение в степень и извлечение корня, ввёл 81.
3 в 4 степени = 81 а извлечение из 81 корня 4 степени = 3 Всё верно.
Я бы хотел спросить насчёт двух текстовых полей sticky="ns". Почему ns? Ведь n - север, а s - юг. У кнопок только n, но при этом они расположены с текстовыми полями на одном уровне
 
explorer

explorer

Red Team
05.08.2018
824
1 741
Я бы хотел спросить насчёт двух текстовых полей sticky="ns". Почему ns? Ведь n - север, а s - юг. У кнопок только n, но при этом они расположены с текстовыми полями на одном уровне
Всё просто - если указать ns, то поле растягивается с севера на юг, таким образом кнопки и однострочные поля становятся одинакового размера. Просто сами попробуйте ставить разные значения, и сразу будет видна разница.

P.S. Надеюсь с этим вопросом разобрались. Дополню - в данном случае, кнопкам вообще не нужно указывать sticky, так как они занимают полностью весь размер ячейки. Но в одну ячейку не обязательно заключать один элемент. Их там может быть несколько. И вот тогда, чтобы они не накладывались друг на друга, необходимо использовать sticky и отступы.
 
Последнее редактирование:
  • Нравится
Реакции: dustver
explorer

explorer

Red Team
05.08.2018
824
1 741
Решение задачи

Python:
from tkinter import *

root = Tk()
root.title("Метод grid")
root.geometry("346x290")
root.resizable(width=False, height=False)


def plus():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a+b)
    text.insert(END, res + '\n')


def minus():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a - b)
    text.insert(END, res + '\n')


def multiply():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a * b)
    text.insert(END, res + '\n')


def split():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a / b)
    text.insert(END, res + '\n')


def exponentiation():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a ** b)
    text.insert(END, res + '\n')


def rooting():
    a = int(first_number.get())
    b = int(two_number.get())
    res = str(a**(1/b))
    text.insert(END, res + '\n')


def clean():
    text.delete(1.0, END)


plus_button = Button(text="plus +", width=14, command=plus)
plus_button.grid(row=0, column=0, padx=10, pady=5, sticky="n")

minus_button = Button(text="minus -", width=14, command=minus)
minus_button.grid(row=0, column=1, padx=10, pady=5, sticky="n")

multiply_button = Button(text="multiply *", width=14, command=multiply)
multiply_button.grid(row=1, column=0, padx=10, pady=5, sticky="n")

split_button = Button(text="divide /", width=14, command=split)
split_button.grid(row=1, column=1, padx=10, pady=5, sticky="n")

exponentiation_button = Button(text="exponentiation", width=14, command=exponentiation)
exponentiation_button.grid(row=2, column=0, padx=10, pady=5, sticky="n")

rooting_button = Button(text="rootin √", width=14, command=rooting)
rooting_button.grid(row=2, column=1, padx=10, pady=5, sticky="n")

clean_button = Button(text="Clean", width=6, command=clean)
clean_button.grid(row=2, column=2, pady=5, sticky="n")

first_number = Entry(width=4, justify=CENTER)
first_number.grid(row=0, column=2, pady=5, sticky="ns")

two_number = Entry(width=4, justify=CENTER)
two_number.grid(row=1, column=2, pady=5, sticky="ns")

text = Text(root, width=40, height=10)
text.grid(row=3, column=0, columnspan=3, padx=10, sticky='nswe')

root.mainloop()
 
  • Нравится
Реакции: Pirnazar
Азиз

Азиз

Well-known member
30.05.2018
213
68
Графические оболочки программ напоминают мне html
 
explorer

explorer

Red Team
05.08.2018
824
1 741
Графические оболочки программ напоминают мне html
Есть некоторое сходство в атрибутах ширины, высоты, расположения и пр.
В следующей части поработаем над внешним видом программы, будем наводить красоту ;)
 
  • Нравится
Реакции: Азиз
Азиз

Азиз

Well-known member
30.05.2018
213
68
Есть некоторое сходство в атрибутах ширины, высоты, расположения и пр.
В следующей части поработаем над внешним видом программы, будем наводить красоту ;)
Ну вот ещё и css подъехал, полноценная верстка!
 
win95

win95

New member
04.03.2020
1
0
Спасибо, хороший цикл статей! А продолжение планируется?
 
explorer

explorer

Red Team
05.08.2018
824
1 741
Спасибо, хороший цикл статей! А продолжение планируется?
Было в планах статью про стили как минимум написать, но уже скорее всего не будет, плотно занят курсом по пайтону. На русском языке посмотреть материалы по Tk можно
 
  • Нравится
Реакции: win95
Мы в соцсетях: