Сетевая структура модулей
Запись от Viktorrus размещена 29.10.2020 в 14:40
Показов 4419
Комментарии 20
|
. Примечание: почему возникла необходимость в такой технологии, смотрите в предыдущей записи блога. . Технология разработана на базе применения ООП. . Создается основная (главная) программа (ОП) и необходимое количество модулей, каждый из которых импортируется основной программой (одноуровневая зависимость с ОП). Импортирование осуществляется только с помощью синтаксиса import <имя модуля> as <алиас> . . В основу технологии заложен следующий принцип: в ОП мы размещаем класс Progr, который моделирует работу нашей программы. Где данные, используемые при работе программы, являются атрибутами-свойствами экземпляра класса Progr, а действия программы оформляются в виде атрибутов-методов. . Вот простой пример такой технологии, в качестве теста. Основная программа classTest.py : Кликните здесь для просмотра всего текста
Модуль data.py : Кликните здесь для просмотра всего текста
Модуль module1.py : Кликните здесь для просмотра всего текста
Модуль module2.py : Кликните здесь для просмотра всего текста
. Смысл эксперимента в том, что из модуля module1 , не имея прямой связи, можно непосредственно обращаться к модулю data передавая туда данные и получая от туда данные. . Применение этой технологии в практическом проекте (из за которого я собственно и разработал эту технологию) я выложу позже, когда закончу проект (он уже в основном на стадии завершения). | ||||||||||||||||||||
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 20
Комментарии
-
это очень не читаемо и не явно, а мы в питоне крайне любим читаемость и явность. По сути имея перед глазами модуль я не смогу понять откуда он берет данные и кто на него влияет, представляю в какой ужас превращается отладка.
Пример -у меня что-то упало в модуле1 - открываю, там никаких импортов, они ничегое не вызывает, но сам изниоткуда берет
данные, например p1.s1.var
Мало того что я сам не понимаю откуда это, мне еще и ИДЕ (пичарм например) все красным подчеркнет ибо непонятно откуда эти поля взялись.
Вообще сам подход в корне неверен если говорить о модулях, а не о классах - подмена каких то полей модуля извне не рекомендуется как раз ибо фиг отследишь кто и где это сделал. Модуль то знает только о себе, а не о тех кто его где то вызвал и импортировал его переменные. ТО есть мало того что это неявно и сложно отлаживать, так еще и ИДЕ не поможет ибо ей тоже непонятны обратные зависимости ваши.Запись от Welemir1 размещена 29.10.2020 в 18:33
-
Welemir1 , что интересно, Microsoft Visual Studio Community 2019 видит эти связи и даже после ввода точки подсказывает какие атрибуты я могу подставить в квалифицированное имя (какие атрибуты есть у данного объекта из другого модуля). Но в чем я с Вами соглашусь (и у меня была такая мысль), что здесь не хватает информации для разработчика, когда он читает такой код. Поэтому в шапке doc модуля (заключенной в тройные кавычки """ ....""") при такой технологии видимо нужно описывать информацию о его связях, что бы можно было разобраться в алгоритме работы кода. В общем когда я изучу материал по Вашей ссылке и доделаю свой проект "Журнал записей", в котором я использовал описанную мной технологию, то посмотрим как это получится на реальном примере.Запись от Viktorrus размещена 29.10.2020 в 20:10
-
Welemir1 цитата "Вообще сам подход в корне неверен если говорить о модулях, а не о классах".
Суть подхода как раз и состоит в том, что модули оформляются как классы, содержащие всю информацию об этих модулях. Что и позволяет осуществлять такие связи между модулями, а точнее между классами этих модулей. В общем проект доделаю, а там посмотрим. Может заменю на технологию, по ссылке, которую Вы мне прислали.Запись от Viktorrus размещена 29.10.2020 в 20:16
-
к классам, созданию объектов и использованию их атрибутов претензий нет. Но в 1 строке модуля у вас переменная, которую вы проимпортировав сделали глобальной для всего приложения, а не 1 модуля. Теперь ее может кто угодно поменять, нарушив работу всех использующих.
Плюс, повторюсь, ее назначение не понятно
А что произойдет если кто то сделает релоад модуля?
Например у функционального программирование основной плюс именно в том что они стараются нигде не менять состояние, так как основная проблема любых программ именно в том что кто-то где-то что-то поменял и в итоге получаются не те данные и не там. А вы к общей сложности и изменчивости ООП и процедурных программ предлагаете добавить еще один слой "изменчивости", то есть теперь состояние может поменять не только сам модуль и его класс но и вообще кто угодно из вашей сети модулей.Запись от Welemir1 размещена 29.10.2020 в 20:30
-
"Но в 1 строке модуля у вас переменная, которую вы проимпортировав сделали глобальной для всего приложения, а не 1 модуля".
Это не так, она глобальная переменная только для модуля1 , так как принадлежит пространству имен только этого модуля. Это обеспечивается синтаксисом import <имя модуля> as <алиас> .
Использование импортирования с помощью from ... такая технология не допускает.
А что есть что, я комментариями в модулях не расписывал, так как этот код нужен был только мне, что бы проверить идею.
Я доделал код работающей с использованием этой технологии программы, состоящей из основного файла и двух модулей.
Основной файл docsCatalog.py .
Модули journal.py и record.py .
Допишу комментарии к коду и выложу здесь.
Код представляет собой шаблон, с помощью которого можно быстро (за 20 мин) создать журнал записей на любую тематику.
Например складской журнал, каталог документов, каталог книг и так далее.
В отличие от "Телефонной книги", которую я выкладывал ранее, здесь любую запись из журнала можно открыть в отдельном окне, где добавляются дополнительные поля для записи и поля можно раскрыть на ширину экрана, что позволяет видеть целиком более длинные записи.
В общем когда выложу код то увидите.Запись от Viktorrus размещена 29.10.2020 в 22:25
-
. Программа кроме технологии "Сетевой структуры модулей" делает еще много чего. Поэтому довольно объемная и поэтому Вы вряд ли будете с ней разбираться. Но посмотреть, как она работает Вы можете.
. Для этого нужно разместить три файла, коды которых ниже, в один каталог и запустить "Основной файл". Названия файлов должны соответствовать тем, которые указаны ниже.
(Из за ограничения размера записи придется разбить на десять частей.
Основной файл journalEntriesTemplate1.py (первая часть):
Кликните здесь для просмотра всего текстаPython 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
""" "Журнал записей" Шаблон """ # файл journalEntriesTemplate1.pyw (расширение .pyw необходимо для подавления окна DOS) # в модуле journalEntriesTemplate1 заменить Поле1 внутри кода на название соответствующее теме # в модуле journalEntriesTemplate1 заменить Поле2 внутри кода на название соответствующее теме # в модуле journalEntriesTemplate1 заменить Поле3 внутри кода на название соответствующее теме # в модуле journalEntriesTemplate1 заменить Поле4 внутри кода на название соответствующее теме # в модуле journalEntriesTemplate1 заменить Поле5 внутри кода на название соответствующее теме # в модуле journalEntriesTemplate1 заменить Поле6 внутри кода на название соответствующее теме # в строке 70 заменить название экземпляра программы (имя базы данных), которое находится в атрибуте nameBook from tkinter import * # импорт объектов для графического интерфейса from tkinter.messagebox import * # импорт объектов для диалоговых окон import shelve # импорт модуля для работы с базой данных import journal as mJ # импорт модуля с формой журнала import record as mR # импорт модуля с формой для одной выбранной записи class Progr: # создание класса моделирующего данные программы и ее дествия def __init__(self, dbName, j1=None): self.j1 = mJ.Journal(dbName) # создание экземпляра j1 класса Journal self.dbName = dbName self.fieldnamesRecTab = ('keyRec', 'char', 'field1', 'field2', 'field3', 'commen', 'delR') # кортеж имен полей записи в таблице self.fieldnamesRecTabCyr = ('№№', 'Буква', 'Поле1', 'Поле2', 'Поле3', 'Комментарий', 'тип') # кортеж имен полей на руском self.fieldnamesRec = ('char', 'field1', 'field2', 'field3', 'field4', 'field5', 'field6', 'commen') # кортеж имен полей для формы с одной записью self.fieldnamesRecCyr = {'char':'Буква', 'field1':'Поле1', 'field2':'Поле2', 'field3':'Поле3', 'field4':'Поле4', 'field5':'Поле5', 'field6':'Поле6', 'commen':'Комментарий'} # словарь для перевода полей в кирилицу self.fieldnamesRecFull = ('keyRec', 'char', 'field1', 'field2', 'field3', 'field4', 'field5', 'field6', 'commen', 'delR') # кортеж всех полей в записи self.activCh = 'А' # буква, активная на текущий момент # текущая запись self.typeRec = '' # тип выводимых на экран записей, '' - открытые, "с" - скрытые self.dicRem = {} # словарь оставшихся не выведенными записей def load_DB(self): # загрузка записей из базы данных db1, при необходимости добавить дополнительные БД db1 = shelve.open(self.j1.dbName) # открытие базы данных (имя берется # из атрибута dbName экземпляра класса Data) self.j1.dic_recs = dict(db1.items()) # загрузка записей из базы данных в атрибут dic_recs # экземпляра класса Data (в словарь экземпляра класса) db1.close() # закрытие базы данных def save_DB(self): # сохранение записей в базе данных db1, при необходимости добавить дополнительные БД db1 = shelve.open(self.j1.dbName) # открытие базы данных for (key, record) in self.j1.dic_recs.items(): # запись содержимого из словаря dic_recs db1[key] = record # экземпляра j1 класса Data в базу данных db1.close() # закрытие базы данных
Запись от Viktorrus размещена 30.10.2020 в 16:47
-
Файл journalEntriesTemplate1.py (вторая часть)
Кликните здесь для просмотра всего текстаPython 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
def open_Journal(self): mJ.p1 = p1 # передача в модуль journal экземпляра p1 класса программы Progr mJ.fieldnamesRecTab = p1.fieldnamesRecTab # кортеж имен полей записи в таблице mJ.fieldnamesRecTabCyr = p1.fieldnamesRecTabCyr # кортеж имен полей на руском mJ.fieldnamesRec = p1.fieldnamesRec # кортеж имен полей для формы с одной записью mJ.fieldnamesRecCyr = p1.fieldnamesRecCyr # словарь для перевода полей в кирилицу mJ.fieldnamesRecFull = p1.fieldnamesRecFull # кортеж всех полей в записи mJ.window = mJ.makeWidgets() # создание формы mJ.fetchChr('А') # вывод в качестве стартовой страницу с буквой "А" mJ.window.mainloop() # передача управления форме def open_Record(self): mR.p1 = p1 # передача в модуль record экземпляра p1 класса программы Progr mR.fieldnamesRec = p1.fieldnamesRec # имена полей у записи (передается в модуль record) mR.fieldnamesRecCyr = p1.fieldnamesRecCyr # словарь для перевода полей в кирилицу (передается в модуль record) mR.record = p1.j1.dic_recs[p1.j1.currentKey] # экземпляр записи для вывода в форме в модуле mR.winRec = mR.makeWidgets() # создание в модуле формы с одной записью mR.fetchRecord(mR.record) # вывод в форме в модуле указанной записи mR.winRec.mainloop() # передача управления форме в модуле if __name__ == '__main__': p1 = Progr("Записи") # создание экземпляра класса Progr p1.load_DB() # загрузка записей из внешней БД в словарь dic_recs p1.open_Journal()
Запись от Viktorrus размещена 30.10.2020 в 16:51
-
Модуль journal.py (первая часть):
Кликните здесь для просмотра всего текстаPython 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
# файл journal.py - модуль, импортируемый сценарием journalEntriesTemplate1.py (или journalEntriesTemplate1.pyw) from tkinter import * # импорт объектов для графического интерфейса from tkinter.messagebox import * # импорт объектов для диалоговых окон import shelve # импорт модуля для работы с базой данных p1 = None # экземпляр класса Progr (присваивается из модуля journalEntriesTemplate1) window = None # окно для журнала записей (присваивается из модуля journalEntriesTemplate1) fieldnamesRecTab = None # кортеж имен полей записи в таблице (передается из journalEntriesTemplate1) fieldnamesRecTabCyr = None # кортеж имен полей на руском (передается из journalEntriesTemplate1) fieldnamesRec = None # кортеж имен полей для формы с одной записью (передается из journalEntriesTemplate1) fieldnamesRecCyr = None # словарь для перевода полей в кирилицу (передается из journalEntriesTemplate1) fieldnamesRecFull = None # кортеж всех полей в записи (передается из journalEntriesTemplate1) activCh = 'А' # буква, активная на текущий момент # текущая запись typeRec = '' # тип выводимых на экран записей, '' - открытые, "с" - скрытые dicRem = {} # словарь оставшихся не выведенными записей class Journal: def __init__(self, dbName, currentKey=None, dic_recs={}): self.dbName = dbName # название журнала self.currentKey = currentKey # номер текущей записи в журнале self.dic_recs = dic_recs # словарь записей, который загружается из БД # и с которым программма динамически работеет, # чтобы затем измененные данные сохранить в БД class Record: # класс Запись def __init__(self, keyRec, char, field1, field2, field3, field4, field5, field6, commen, delR=''): # инициализация атрибутов экземпляров класса self.keyRec = keyRec # ключ записи self.char = char # буква, на странице которой находится запись self.field1 = field1 # метка, к чему относится запись self.field2 = field2 # Поле2 self.field3 = field3 # Поле3 self.field4 = field4 # Поле4 self.field5 = field5 # Поле5 self.field6 = field6 # Поле6 self.commen = commen # комментарий self.delR = delR # служебное поле для пометки записи: # ''- видимая, 'с' - скрытая, 'у' - удаляемая def onDeleteRequest(): # print('Got wm delete') # щелчок на кнопке X в окне: можно отменить или перехватить saveRec() window.destroy() # возбудит событие <Destroy>
Запись от Viktorrus размещена 30.10.2020 в 17:05
-
Модуль journal.py (вторая часть)
Кликните здесь для просмотра всего текстаPython 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
def makeWidgets(): # создание графической формы global entriesRec, entRec, lab1, alph # перечень глобальных переменных, которые будут использоваться и за пределами функции entRec = {} # словарь, в который будут заносится объекты ввода entFind (поиск) и entKeyRec (ключ) window = Tk() # создание главного окна window.title('Книги') # заголовок окна window.geometry('1260x600+0+0') # размеры окна # window.bind('FocusIn', updatePage) # при получении окном фокуса, обновление таблицы записей # window.bind('<Destroy>', doRootDestroy) # для корневого и дочерних window.protocol('WM_DELETE_WINDOW', onDeleteRequest) # на кнопке X окна (перехватывает нажатие кнопки Х) form1 = Frame(window) # создание внутри окна window контейнера form1 form1.pack() lab1 = Label(form1, text=activCh, fg="#eee", bg="#333", width=5) # метка, показывающая lab1.pack(side=LEFT) # активную букву Label(form1, text=' ', width=30).pack(side=LEFT) # вспомагательная пустая метка для улучшения расположения alph = ["А", "Б", "В", "Г", "Д", "Е", "Ж", "З", "И", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Э", "Ю", "Я"] # список букв for i in range(len(alph)): # создание кнопок с буквами Button(form1, text=alph[i], command=(lambda x=alph[i]: fetchChr(x))).pack(side=LEFT) ent = Entry(form1, width=27) # поле ввода для поиска ent.pack(side=LEFT) entRec['entFind'] = ent # поместить объект поля ввода в словарь entRec Button(form1, text="Поиск", command=fetchFind).pack(side=LEFT) # создание кнопки Поиск form2 = Frame(window) # создание внутри окна window контейнера form2 form2.pack() entriesRec = {} # словарь, для занесения в него объектов Entry ячеек таблицы ввода записей for (ix, label) in enumerate(fieldnamesRecTabCyr): # создание надписей заголовков столбцов таблицы lab = Label(form2, text=label) lab.grid(row=2, column=ix) for i in range(1, 26): # создаются ячейки таблицы для ввода записей for (ix, label) in enumerate(fieldnamesRecTab): if label == 'keyRec' or label == 'char' or label == 'delR': # выделяются столбцы, которые потом будут иметь особый режим доступа ent = Entry(form2, state='normal', width=6) else: ent = Entry(form2, width=40) ent.bind('<Button-1>', getKey) ent.grid(row=i+2, column=ix) entriesRec[label+str(i)] = ent # объекты ячеек таблицы заносятся в словарь, причем к имени # столбца ячейки добавляется номер строки, # тем самым однозначно определяются координаты ячейки, # что бы к ней обращаться
Запись от Viktorrus размещена 30.10.2020 в 17:11
-
Модуль journal.py (третья часть)
Кликните здесь для просмотра всего текстаPython 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
form3 = Frame(window) # создание внутри окна window контейнера form3 form3.pack() Button(window, text="Следующая страница", command=fetchNext).pack() # кнопка Следующая страница Label(window, text=' ', width=10).pack(side=LEFT) # вспомогательная пустая метка labKeyRec = Label(window, text='№').pack(side=LEFT) # надпись перед полем ввода номера ключа ent = Entry(window, width=10) # поле ввода номера ключа ent.pack(side=LEFT) entRec['entKeyRec'] = ent # занесение объекта поле ввода номера ключа в словарь entRec Button(window, text="Скрыть", command=hideRec).pack(side=LEFT) # кнопка Скрыть (запись) Button(window, text="Показать скрытые", command=fetchHide).pack(side=LEFT) # кнопка Показать скрытые Button(window, text="Открыть", command=openRec).pack(side=LEFT) # кнопка Открыть (запись) Label(window, text=' ', width=2).pack(side=LEFT) # вспомогательная пустая метка Button(window, text="Удалить", command=delKeyRec).pack(side=LEFT) # кнопка удалить (запись) Label(window, text=' ', width=10).pack(side=LEFT) # вспомогательная пустая метка Button(window, text="Вывести запись", command=fetchRecord).pack(side=LEFT) # кнопка выводит запись в отдельной форме Label(window, text=' ', width=3).pack(side=LEFT) # вспомогательная пустая метка Button(window, text="Восстановить", command=updatePage).pack(side=LEFT) Label(window, text=' ', width=30).pack(side=LEFT) # вспомогательная пустая метка btns = Button(window, text="Сохранить", command=interSave).pack(side=LEFT) # кнопка Сохранить (страницу) Label(window, text=' ', width=20).pack(side=LEFT) # вспомогательная пустая метка Button(window, text="Выход", command=fin).pack(side=LEFT) # кнопка Выход (из программы) return window # функция makeWidgets возвращает окно window def clear_sheet(): # очистка листа for i in range(1, 26): for field in fieldnamesRecTab: if field == 'keyRec' or field == 'delR': # для очистки полей keyRec и delR, entriesRec[field+str(i)].config(state='normal') # нужно открыть их для записи entriesRec[field+str(i)].delete(0, END) entriesRec[field+str(i)].config(state='readonly') else: entriesRec[field+str(i)].delete(0, END) # очистка остальных полей def fetchChr(ch): # выбрать записи на букву ch global activCh, typeRec, lab1 saveRec() # предварительно сохранить предыдущую страницу typeRec = '' # выбор для буквы делать только из открытых записей activCh = ch # сделать ch текущей буквой lab1.config(text=activCh) # написать, для какой буквы выводятся записи dic_recsChr = {} # словарь, в который помещаются выбранные записи for key in p1.j1.dic_recs.keys(): # выбор записей и помещение их в словарь if p1.j1.dic_recs[key].char == ch: dic_recsChr[key] = p1.j1.dic_recs[key] fetch(dic_recsChr) # вывод записей в таблицу формы
Запись от Viktorrus размещена 30.10.2020 в 17:17
-
Модуль journal.py (четвертая часть)
Кликните здесь для просмотра всего текстаPython 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
def interSave(): # принудительное сохранение текущей страницы и повторный вывод записей для этой буквы начиная с первой страницы fetchChr(activCh) def fetchHide(): # вывод скрытых записей global typeRec, lab1 saveRec() lab1.config(text='скр') typeRec = 'с' # выбор делать только из скрытых записей fetch(p1.j1.dic_recs) def fetch(dicR): # вывод записей из заданнго словаря global dicRem # словарь записей, оставшихся не выведенными clear_sheet() # очистка таблицы count = 1 # счетчик показывающий номер строки, в которую выводится запись dicRe = dicR.copy() # словарь, ведущий учет записей, которые еще не выведены while count <= 25 and len(dicRe): # в цикле, заполнение строк таблицы записями for key in dicR.keys(): # в цикле вывод записи удовлетворяющей условию if dicR[key].delR == typeRec: record = dicR[key] # запись для вывода for field in fieldnamesRecTab: # в цикле последовательное заполнение полей в строке if field == 'keyRec' or field == 'delR': # поля, которые необходимо открыть для записи entriesRec[field+str(count)].config(state='normal') entriesRec[field+str(count)].insert(0, getattr(record, field)) entriesRec[field+str(count)].config(state='readonly') else: entriesRec[field+str(count)].insert(0, getattr(record, field)) # все остальные поля count += 1 # переход к следующей строке таблицы dicRe.pop(key) # удаление записи, которая выведена из словаря учета оставшихся записей if count > 25: # если все строки таблицы заполнены, то выход из цикла while break else: dicRe.pop(key) # удаление из словаря учета записи, которая не удовлетворяет условию вывода в таблицу dicRem = dicRe.copy() # словарь записей, оставшихся не выведенными def fetchNext(): # вывод на следующей странице записей, оставшихся не выведенными saveRec() fetch(dicRem) def updatePage(): # обновление страницы global activCh, typeRec, lab1 lab1.config(text=activCh) # написать, для какой буквы выводятся записи dic_recsChr = {} # словарь, в который помещаются выбранные записи for key in p1.j1.dic_recs.keys(): # выбор записей и помещение их в словарь if p1.j1.dic_recs[key].char == activCh: dic_recsChr[key] = p1.j1.dic_recs[key] fetch(dic_recsChr) # вывод записей в таблицу формы
Запись от Viktorrus размещена 30.10.2020 в 17:21
-
Модуль journal.py (пятая часть)
Кликните здесь для просмотра всего текстаPython 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
def delKeyRec(): # физическое удаление из базы данных записи, которая указана в ячейке entKeyRec key = entRec['entKeyRec'].get() # из ячейки entKeyRec берется ключ записи для удаления if key.isnumeric() and (key in p1.j1.dic_recs.keys()): # проверка, указан ли номер существующей записи if askyesno('Подтверждение', 'Удалить запись без возможности востановления?'): # подтверждение на удаление del p1.j1.dic_recs[key] # запись удаляется из динамического словаря p1.j1.dic_recs db = shelve.open(p1.j1.nameBook) # открывается база данных del db[key] # указанная запись физически удаляется из базы данных db.close() # база данных закрывается for i in range(1, 26): # ищется строка таблицы с этой записью, и помечается как удаленная, if entriesRec['keyRec'+str(i)].get() == key: # что бы потом при сохранении страницы, entriesRec['delR'+str(i)].config(state='normal') # она не была вновь занесена в базу данных entriesRec['delR'+str(i)].insert(0, 'у') entriesRec['delR'+str(i)].config(state='readonly') entRec['entKeyRec'].delete(0, END) # очищается ячейка, содержащая номер удаляемой записи else: showinfo('Отмена', 'Удаление записи отменено') # удаление отменено else: showinfo('Отмена', 'Укажите номер существующей записи') # не указан номер записи def hideRec(): # пометить как скрытую key = entRec['entKeyRec'].get() # из ячейки entKeyRec берется ключ записи для сокрытия for i in range(1, 26): # ищется строка таблицы с этой записью, и помечается как скрытая if entriesRec['keyRec'+str(i)].get() == key: entriesRec['delR'+str(i)].config(state='normal') entriesRec['delR'+str(i)].insert(0, 'с') entriesRec['delR'+str(i)].config(state='readonly') entRec['entKeyRec'].delete(0, END) # очищается ячейка, содержащая номер скрываемой записи записи def openRec(): # открыть скрытую запись key = entRec['entKeyRec'].get() # из ячейки entKeyRec берется ключ записи для открытия for i in range(1, 26): # ищется строка таблицы с этой записью, и помечается как открытая if entriesRec['keyRec'+str(i)].get() == key: entriesRec['delR'+str(i)].config(state='normal') entriesRec['delR'+str(i)].delete(0, END) entriesRec['delR'+str(i)].insert(0, '') entriesRec['delR'+str(i)].config(state='readonly') entRec['entKeyRec'].delete(0, END) # очищается ячейка, содержащая номер открываемой записи
Запись от Viktorrus размещена 30.10.2020 в 17:26
-
Модуль journal.py (шестая часть)
Кликните здесь для просмотра всего текстаPython 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
def fetchFind(): # поиск записей по заданной строке global lab1 saveRec() clear_sheet() lab1.config(text='поиск') # сигнализирует о режиме поиска strF = entRec['entFind'].get().lower() # строка для поиска берется из ячейки entFind dicFind = {} # словарь, для занесения в него найденных записей for key in p1.j1.dic_recs.keys(): # в тлефонном справочнике ищутся записи содержащие искомую строку record = p1.j1.dic_recs[key] for field in fieldnamesRecFull: #for field in fieldnamesRecTab: if (field != 'keyRec' and field != 'char' and field != 'delR' and # поиск в полях, за исключением перечисленных getattr(record, field).lower().find(strF) != -1): dicFind[key] = record break fetch(dicFind) # вывод найденных записей def saveRec(): # сохранение текущей страницы global typeRec for i in range(1, 26): # просмотр строк и при наличии хотя бы в одном поле строки данных, сохранение ее key = entriesRec['keyRec'+str(i)].get() # проверка наличия в строке ключа if entriesRec['delR'+str(i)].get() == 'у': # записи помеченные как удаленные пропускаются continue elif key: # иначе, если запись не удаленная и с ключом, то она перезаписывается record = p1.j1.dic_recs[key] for field in fieldnamesRecTab: setattr(record, field, entriesRec[field+str(i)].get()) p1.j1.dic_recs[key] = record else: # иначе, если в строке нет ключа, но в одном из полей есть данные, то создается запись-экземпляр existRec = False # и помещается а словарь p1.j1.dic_recs for field in fieldnamesRecTab: if entriesRec[field+str(i)].get(): existRec = True # Если существует запись в поле на этой строке if existRec: # если данные в строке существуют, то создается запись if entriesRec['char'+str(i)].get(): # если поле буквы не пусто, то в запись заносится эта буква char = entriesRec['char'+str(i)].get() else: # иначе в запись заносится буква, являющаяся на данный момент активной char = activCh field1 = entriesRec['field1'+str(i)].get() # заполняются переменные field2 = entriesRec['field2'+str(i)].get() # для формирования записи field3 = entriesRec['field3'+str(i)].get() field4 = '' field5 = '' field6 = '' commen = entriesRec['commen'+str(i)].get() if len(p1.j1.dic_recs)>0: # если телефонный справочник не пуст, то к максимальному значению ключа L = sorted(p1.j1.dic_recs.items(), key=lambda item: int(item[0])) # прибавляется единица keyRec = str(int(L[-1][0]) + 1) else: # иначе записи присваивается ключ равный 1 keyRec = "1" record = Record(keyRec, char, field1, field2, field3, field4, field5, field6, commen) # создается запись, экземпляр класса Record p1.j1.dic_recs[keyRec] = record # и записывается в словарь p1.j1.dic_recs p1.save_DB() # словарь p1.j1.dic_recs сохраняется во внешней базе данных "Книги"
Запись от Viktorrus размещена 30.10.2020 в 17:28
-
Модуль journal.py (седьмая часть)
Кликните здесь для просмотра всего текстаPython 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
def get_key(val): # функция для возврата ключа из словаря по значению for key, value in entriesRec.items(): # перебираем пары (ключ, значение) if val == value: # и находим ключ, у которого заданное значение return key print("key doesn't exist") def getKey(event): # получить ключ записи currStr = get_key(event.widget)[6:] # номер текущей строки currKey = entriesRec['keyRec'+currStr].get() # ключ текущей записи entRec['entKeyRec'].delete(0, END) # очистка ячейки указывающей выбранный номер записи entRec['entKeyRec'].insert(0, currKey) # запись текущего номера записи в ячейку выбранного номера записи def fetchRecord(): # вывод формы с одной записью saveRec() # сохранение текущей страницы таблицы currentKey = entRec['entKeyRec'].get() # из ячейки entKeyRec берется ключ записи if currentKey.isnumeric() and (currentKey in p1.j1.dic_recs.keys()): # проверка, указан ли номер существующей записи p1.j1.currentKey = currentKey # p1.j1.dic_recs[currentKey] # экземпляр записи для вывода в форме в модуле window.destroy() p1.open_Record() # открытие окна текущей записи else: showinfo('Отмена', 'Укажите номер существующей записи') # не указан номер записи def fin(): # сохранение перед закрытием окна (в том числе крестом) saveRec() # сохранение текущей страницы window.destroy() # закрытие окна
Запись от Viktorrus размещена 30.10.2020 в 17:31
-
Модуль record.py :
Кликните здесь для просмотра всего текстаPython 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
# файл record.py - модуль, импортируемый сценарием journalEntriesTemplate1.py (или journalEntriesTemplate1.pyw) from tkinter import * # импорт объектов для графического интерфейса from tkinter import Toplevel # класс дополнительных окон from tkinter.messagebox import showerror # всплывающее окно диалога сообщающее об ошибке import shelve # импорт модуля для работы с базой данных p1 = None # экземпляр класса Progr (передается из journalEntriesTemplate1) winRec = None fieldnamesRec = None #p1.fieldnamesRec # имена полей у записи (передается из journalEntriesTemplate1) fieldnamesRecCyr = None #p1.fieldnamesRecCyr # словарь для перевода полей в кирилицу (передается из journalEntriesTemplate1) record = None # экземпляр записи для вывода в форме (передается через функцию) entriesRec = {} # словарь, для занесения в него объектов Entry ячеек формы ввода записи def onDeleteRequest(): # print('Got wm delete') # щелчок на кнопке X в окне: можно отменить или перехватить saveRec() # сохранение текущей записи winRec.destroy() # закрытие окна текущей записи (возбудит событие <Destroy>) p1.open_Journal() # открытие окна журнала def makeWidgets(): # создание графической формы для вывода одной записи global entriesRec winRec = Tk() # создание дополнительного окна для второй формы winRec.title('Книга') # заголовок окна winRec.geometry('500x250+350+150') # размеры окна winRec.protocol('WM_DELETE_WINDOW', onDeleteRequest) # на кнопке X окна (перехватывает нажатие кнопки Х) form = Frame(winRec) # создание фрейма form.pack(side=TOP, expand=YES, fill=BOTH) # упаковка фрейма entriesRec = {} # словарь содержащий объекты Entry for (ix, label) in enumerate(fieldnamesRec): # формирование названия полей и полей ввода Entry lab = Label(form, text= fieldnamesRecCyr[label]) # название поля (в кирилице) ent = Entry(form, width=200) # поле ввода lab.grid(row=ix, column=0) # размещение по сетке ent.grid(row=ix, column=1) entriesRec[label] = ent # запись в словарь Button(winRec, text="Сохранить", command=saveRec).pack(side=LEFT) # кнопка Сохранить Button(winRec, text="Выход", command=fin).pack(side=RIGHT) # закрывает одно окно return winRec # возвращает второе окно со сформированной второй формой #def recBook(recordsBook): # функция для передачи в модуль экземпляра t1 книги класса RecordsBook global t1 t1 = recordsBook # содержит экземпляр t1 класса RecordsBook #def curRec(curRecord): # функция для передачи в модуль экземпляра текущей записи класса Record global record _record = curRecord # экземпляр записи переданный в модуль def fetchRecord(record): # вывод в форме указанной записи for field in fieldnamesRec: entriesRec[field].insert(0, getattr(record, field)) # для каждого поля заполняется виджет Entry def saveRec(): # сохранение записи (занесение в экземпляр записи содержимого формы и сохранение экземпляра) global record # экземпляр записи выведенный в форме key = record.keyRec # ключ записи for field in fieldnamesRec: # занесение в экземпляр записи содержимого формы setattr(record, field, entriesRec[field].get()) #print(record) # печать атрибутов для отладки p1.j1.dic_recs[key] = record # сохранение экземпляра записи в словаре книги p1.save_DB() # словарь t1.dicRec сохраняется во внешней базе данных "Книги" def fin(): # сохранение перед закрытием окна saveRec() # сохранение текущей записи winRec.destroy() # закрытие окна текущей записи (возбудит событие <Destroy>) p1.open_Journal() # открытие окна журнала
Запись от Viktorrus размещена 30.10.2020 в 17:33
-
Оказалось, что выкладывать здесь большие программы не реально. Я это сделал первый и последний раз.
. Сейчас думаю изучить технологию "Наблюдатель", которая по ссылке и если ее реализация отличается от моей, то сделать свою реализацию того примера, который там дается. И потом сравнить что там и что получится у меня. И посмотреть какой вариант удобнее.Запись от Viktorrus размещена 30.10.2020 в 17:39
-
Запись от Welemir1 размещена 30.10.2020 в 17:45
-
Запись от Avazart размещена 30.10.2020 в 19:28
-
Я на сайте GitHub создал открытый Repository с названием
journalEntriesTemplate1
Там разместил 3 файла моего проекта.
Мое имя на Гитхабе Viktorrus350
Вы можете оттуда скачать эти файлы?
А я займусь обучающей программой на Гитхабе, что бы научится с ним работать.Запись от Viktorrus размещена 30.10.2020 в 22:08
-
Вот страничка где мои файлы.
https://github.com/Viktorrus35... sTemplate1
Но как их оттуда взять я пока не знаю.Запись от Viktorrus размещена 30.10.2020 в 22:13


