#python #инспекция_кода #tkinter
from tkinter import *
root=Tk()
root.title("Нумерация")
flats = []
flats1 = []
flats2 = []
flats3 = []
def addFlat():
kom_kv=Label(root,text='Введите номер квартиры с несколькими собственниками:')
kom_kv.grid()
kom_kv1=Entry(root)
kom_kv1.grid()
sobs=Label(root,text='Введите колличество собственников:')
sobs.grid()
sobs1=Entry(root)
sobs1.grid()
flats.append(kom_kv)
flats1.append(kom_kv1)
flats2.append(sobs)
flats3.append(sobs1)
def deleteFlat():
if flats!=0 and flats1!=0 and flats2!=0 and flats!=0:
flats.pop().grid_forget()
flats1.pop().grid_forget()
flats2.pop().grid_forget()
flats3.pop().grid_forget()
plus=Button(root,text='Добавить квартиру', command=addFlat)
plus.grid()
plus2=Button(root,text='Удалить квартиру', command=deleteFlat)
plus2.grid()
root.mainloop()
Ответы
Ответ 1
1. Один список вместо четырех Вместо параллельных списков используем один список из объектов. Условно это можно представить как таблицу с несколькими строками. Каждая строка может быть представлена как: кортеж (tuple), список, словарь (dict), namedtuple, объект своего класса, dataclass (Python 3.7 и новее). Преимущество списка перед своим контейнерным типом (вариант @RafaelOsipov): не нужно самому реализовывать велосипед все свойства и методы, которые могут пригодиться, а просто используем уже готовый встроенный тип, который все умеет, и может хранить все что в него положишь. Теперь по поводу типов данных, которые мы можем использовать для хранения "строк" таблицы внутри списка: Минус кортежей и списков: поля кортежа и элементы списка не имеют имен, можно что-то случайно перепутать, если записать не в том порядке. Минус словаря: в словаре может быть больше полей или меньше чем нужно, у полей нет определенного порядка. Минус namedtuple: namedtuple (кортеж с именованными полями) - это неизменяемый тип (как и обычный кортеж), т.е. значения в нем нельзя изменить, только создать новый другой кортеж с другими значениями. Но если значения в строке таблицы не планируется изменять, то это вполне рабочий вариант. Минус своего класса: нужно полностью описывать поведение класса (например, инициализацию значений, строковое представление, методы сравнения на равенство или порядок). dataclass в этом плане удобнее - просто описываются поля класса, а большая часть полезных методов генерируется автоматически. Вариант с dataclass всем прекрасен, но лично я пока не перешел на Python 3.7 :) Кстати да, можно сгруппировать элементы управления в фрейм и хранить в списке фреймы. Но это сделает более сложным процесс извлечения данных из элементов управления, например, если вы захотите сохранить данные в файл. Пример с кортежем: flats = [] def addFlat(): ... flats.append((kom_kv, kom_kv1, sobs, sobs1)) def deleteFlat(): if flats: kom_kv, kom_kv1, sobs, sobs1 = flats.pop() kom_kv.destroy() kom_kv1.destroy() sobs.destroy() sobs1.destroy() Элементы управления в tkinter лучше удалять с помощью destroy, а не с помощью grid_forget, если вы не собираетесь потом возвращать их обратно. Все элементы управления "удаленные" через grid_forget остаются висеть в памяти до закрытия программы. 2. Отделение данных от графического интерфейса У вас данные хранятся прямо в окне. Желательно так не делать, а хранить данные во внутреннем представлении, а уже при необходимости их вывода создавать элементы управления. В качестве бонуса у вас не будет такой жесткой привязки к тому же tkinter. А внутреннее представление можно уже будет перевести в любое внешнее представление: с помощью другой библиотеки GUI, на консоли, в файле, в базе данных. 3. Таблица для отображения данных вместо кучи текстовых полей Можно оставить фиксированное количество текстовых полей (2 в вашем случае) для ввода данных и таблицу для отображения данных. Представьте, что вы вводите данные о многоквартирном доме: всего лишь 5 подъездов по 5 этажей по 4 квартиры на лестничной площадке и по 4 элемента управления = 400 элементов управления уезжают далеко вниз за границы экрана. Можно прикрутить полосу прокрутки, но это будет довольно костыльно. Минимальный пример с таблицей: from tkinter import * import tkinter.ttk as ttk root=Tk() root.title("Нумерация") def addFlat(): flat_number = entry_flat_number.get() owner_number = entry_owner_number.get() table.insert('', 'end', values=(flat_number, owner_number)) def deleteFlat(): selected = table.selection() if selected: table.delete(selected) Label(root,text = 'Введите номер квартиры с несколькими собственниками:').grid() entry_flat_number = Entry(root) entry_flat_number.grid(row=0, column=1) Label(root,text='Введите количество собственников:').grid() entry_owner_number = Entry(root) entry_owner_number.grid(row=1, column=1) Button(root,text='Добавить квартиру', command=addFlat).grid() Button(root,text='Удалить выбранные квартиры', command=deleteFlat).grid(row=2, column=1) table = ttk.Treeview(root) table.grid(columnspan=2, sticky='nswe') table['columns'] = ['flat_number', 'owner_number'] table.column('#0', width=0) table.heading('#1', text='Номер квартиры') table.heading('#2', text='Количество собственников') root.mainloop()Ответ 2
Вместо того, чтобы держать несколько параллельно обрабатываемых массивов, сделайте класс Flat, в котором будут поля: Номер квартиры Количество собственников Затем сделайте класс FlatCollection, внутри которого и будет массив объектов класса Flat и у которого будут методы addFlat и deleteFlat Затем создавайте экземпляр класса FlatCollection и добавляйте/удаляйте объекты класса Flat в него. Так будет намного элегантнее. Небольшое дополнение: Согласно PEP-8 методы классов в пайтоне принято именовать не в camelCase а в snakeCase. То есть вместо addFlat и deleteFlat принято называть методы add_flat и delete_flat.
Комментариев нет:
Отправить комментарий