Форум программистов, компьютерный форум, киберфорум
Viktorrus
Войти
Регистрация
Восстановить пароль
Оценить эту запись

Сетевая структура модулей

Запись от Viktorrus размещена 29.10.2020 в 14:40
Обновил(-а) Viktorrus 29.10.2020 в 15:18

. Примечание: почему возникла необходимость в такой технологии, смотрите в предыдущей записи блога.
. Технология разработана на базе применения ООП.
. Создается основная (главная) программа (ОП) и необходимое количество модулей, каждый из которых импортируется основной программой (одноуровневая зависимость с ОП). Импортирование осуществляется только с помощью синтаксиса
import <имя модуля> as <алиас> .
. В основу технологии заложен следующий принцип: в ОП мы размещаем класс Progr, который моделирует работу нашей программы. Где данные, используемые при работе программы, являются атрибутами-свойствами экземпляра класса Progr, а действия программы оформляются в виде атрибутов-методов.
. Вот простой пример такой технологии, в качестве теста.
Основная программа classTest.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
import shelve
import data as mD           # модуль с данными
import module1 as m1
import module2 as m2
 
class Progr:
    def __init__(self, bdName='Данные1', d1=None):
        self.d1 = mD.Data(bdName)    # создание экземпляра d1 класса базы данных Data
        pass                         # при необходимости создать дополнительные экземпляры базы данных
 
    def load_BD(self):
        # загрузка записей из базы данных db1, при необходимости добавить дополнительные БД
        db1 = shelve.open(self.d1.dbName)     # открытие базы данных (имя берется
                                              # из атрибута dbName экземпляра класса Data)
        self.d1.dic_recs = dict(db1.items())  # загрузка записей из базы данных в атрибут dic_recs
                                              # экземпляра класса Data (в словарь экземпляра класса)
        db1.close()                           # закрытие базы данных
    def save_BD(self):
        # сохранение записей в базе данных db1, при необходимости добавить дополнительные БД
        db1 = shelve.open(self.d1.dbName)     # открытие базы данных
        for (key, record) in self.d1.dic_recs.items():  # запись содержимого из словаря dic_recs
            db1[key] = record                       # экземпляра d1 класса Data в базу данных
        db1.close()                           # закрытие базы данных
 
if __name__ == '__main__':
    p1 = Progr("Записи")       # создание экземпляра класса Progr
    p1.load_BD()             # загрузка записей из внешней БД в словарь dic_recs
    p1.save_BD()             # сохранение записей из словаря dic_recs во внешнюю БД
    m1.p1 = p1            # передача в модуль module1 экземпляра p1 класса программы Progr
    m2.p1 = p1            # передача в модуль module2 экземпляра p1 класса программы Progr
    m1.f1()
    m1.f2()
    m1.f3()
И три модуля.
Модуль data.py :
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
"""
Оформление модуля в виде класса позволяет создавать сразу несколько баз данных 
и работать с ними одновременно.
"""
 
class Data:
    def __init__(self, dbName, var1=1, var2=2, var3=3, dic_recs={}):
        self.dbName = dbName
        self.var1 = var1
        self.var2 = var2
        self.var3 = var3
        self.dic_recs = dic_recs      # словарь записей

Модуль module1.py :
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
p1 = None
 
class Mod1:
    def __init__(self, var1=None, var2=None, var3=None):
        self.var1 = var1
        self.var2 = var2
        self.var3 = var3
 
def f1():
    print(p1.d1.var1)
 
def f2():
    p1.d1.var2 = 5
 
def f3():
    print(p1.d1.var2)

Модуль module2.py :
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
7
8
p1 = None
 
 
class Mod2:
    def __init__(self, var1=None, var2=None, var3=None):
        self.var1 = var1
        self.var2 = var2
        self.var3 = var3
Модуль module2.py пока не использовался. Для эксперимента хватило модулей data.py и module1.py .
. Смысл эксперимента в том, что из модуля module1 , не имея прямой связи, можно непосредственно обращаться к модулю data передавая туда данные и получая от туда данные.
. Применение этой технологии в практическом проекте (из за которого я собственно и разработал эту технологию) я выложу позже, когда закончу проект (он уже в основном на стадии завершения).
Размещено в Без категории
Просмотров 1014 Комментарии 20
Всего комментариев 20
Комментарии
  1. Старый комментарий
    Аватар для Welemir1
    это очень не читаемо и не явно, а мы в питоне крайне любим читаемость и явность. По сути имея перед глазами модуль я не смогу понять откуда он берет данные и кто на него влияет, представляю в какой ужас превращается отладка.

    Пример -у меня что-то упало в модуле1 - открываю, там никаких импортов, они ничегое не вызывает, но сам изниоткуда берет
    данные, например p1.s1.var
    Мало того что я сам не понимаю откуда это, мне еще и ИДЕ (пичарм например) все красным подчеркнет ибо непонятно откуда эти поля взялись.

    Вообще сам подход в корне неверен если говорить о модулях, а не о классах - подмена каких то полей модуля извне не рекомендуется как раз ибо фиг отследишь кто и где это сделал. Модуль то знает только о себе, а не о тех кто его где то вызвал и импортировал его переменные. ТО есть мало того что это неявно и сложно отлаживать, так еще и ИДЕ не поможет ибо ей тоже непонятны обратные зависимости ваши.
    Запись от Welemir1 размещена 29.10.2020 в 18:33 Welemir1 вне форума
  2. Старый комментарий
    Welemir1 , что интересно, Microsoft Visual Studio Community 2019 видит эти связи и даже после ввода точки подсказывает какие атрибуты я могу подставить в квалифицированное имя (какие атрибуты есть у данного объекта из другого модуля). Но в чем я с Вами соглашусь (и у меня была такая мысль), что здесь не хватает информации для разработчика, когда он читает такой код. Поэтому в шапке doc модуля (заключенной в тройные кавычки """ ....""") при такой технологии видимо нужно описывать информацию о его связях, что бы можно было разобраться в алгоритме работы кода. В общем когда я изучу материал по Вашей ссылке и доделаю свой проект "Журнал записей", в котором я использовал описанную мной технологию, то посмотрим как это получится на реальном примере.
    Запись от Viktorrus размещена 29.10.2020 в 20:10 Viktorrus вне форума
  3. Старый комментарий
    Welemir1 цитата "Вообще сам подход в корне неверен если говорить о модулях, а не о классах".
    Суть подхода как раз и состоит в том, что модули оформляются как классы, содержащие всю информацию об этих модулях. Что и позволяет осуществлять такие связи между модулями, а точнее между классами этих модулей. В общем проект доделаю, а там посмотрим. Может заменю на технологию, по ссылке, которую Вы мне прислали.
    Запись от Viktorrus размещена 29.10.2020 в 20:16 Viktorrus вне форума
  4. Старый комментарий
    Аватар для Welemir1
    к классам, созданию объектов и использованию их атрибутов претензий нет. Но в 1 строке модуля у вас переменная, которую вы проимпортировав сделали глобальной для всего приложения, а не 1 модуля. Теперь ее может кто угодно поменять, нарушив работу всех использующих.
    Плюс, повторюсь, ее назначение не понятно
    А что произойдет если кто то сделает релоад модуля?

    Например у функционального программирование основной плюс именно в том что они стараются нигде не менять состояние, так как основная проблема любых программ именно в том что кто-то где-то что-то поменял и в итоге получаются не те данные и не там. А вы к общей сложности и изменчивости ООП и процедурных программ предлагаете добавить еще один слой "изменчивости", то есть теперь состояние может поменять не только сам модуль и его класс но и вообще кто угодно из вашей сети модулей.
    Запись от Welemir1 размещена 29.10.2020 в 20:30 Welemir1 вне форума
  5. Старый комментарий
    "Но в 1 строке модуля у вас переменная, которую вы проимпортировав сделали глобальной для всего приложения, а не 1 модуля".
    Это не так, она глобальная переменная только для модуля1 , так как принадлежит пространству имен только этого модуля. Это обеспечивается синтаксисом import <имя модуля> as <алиас> .
    Использование импортирования с помощью from ... такая технология не допускает.
    А что есть что, я комментариями в модулях не расписывал, так как этот код нужен был только мне, что бы проверить идею.
    Я доделал код работающей с использованием этой технологии программы, состоящей из основного файла и двух модулей.
    Основной файл docsCatalog.py .
    Модули journal.py и record.py .
    Допишу комментарии к коду и выложу здесь.
    Код представляет собой шаблон, с помощью которого можно быстро (за 20 мин) создать журнал записей на любую тематику.
    Например складской журнал, каталог документов, каталог книг и так далее.
    В отличие от "Телефонной книги", которую я выкладывал ранее, здесь любую запись из журнала можно открыть в отдельном окне, где добавляются дополнительные поля для записи и поля можно раскрыть на ширину экрана, что позволяет видеть целиком более длинные записи.
    В общем когда выложу код то увидите.
    Запись от Viktorrus размещена 29.10.2020 в 22:25 Viktorrus вне форума
  6. Старый комментарий
    . Программа кроме технологии "Сетевой структуры модулей" делает еще много чего. Поэтому довольно объемная и поэтому Вы вряд ли будете с ней разбираться. Но посмотреть, как она работает Вы можете.
    . Для этого нужно разместить три файла, коды которых ниже, в один каталог и запустить "Основной файл". Названия файлов должны соответствовать тем, которые указаны ниже.
    (Из за ограничения размера записи придется разбить на десять частей.

    Основной файл 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 Viktorrus вне форума
    Обновил(-а) Viktorrus 30.10.2020 в 17:42
  7. Старый комментарий
    Файл 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 Viktorrus вне форума
    Обновил(-а) Viktorrus 30.10.2020 в 16:58
  8. Старый комментарий
    Модуль 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 Viktorrus вне форума
  9. Старый комментарий
    Модуль 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 Viktorrus вне форума
  10. Старый комментарий
    Модуль 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 Viktorrus вне форума
  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
    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 Viktorrus вне форума
  12. Старый комментарий
    Модуль 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 Viktorrus вне форума
  13. Старый комментарий
    Модуль 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 Viktorrus вне форума
  14. Старый комментарий
    Модуль 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 Viktorrus вне форума
  15. Старый комментарий
    Модуль 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 вне форума
  16. Старый комментарий
    Оказалось, что выкладывать здесь большие программы не реально. Я это сделал первый и последний раз.
    . Сейчас думаю изучить технологию "Наблюдатель", которая по ссылке и если ее реализация отличается от моей, то сделать свою реализацию того примера, который там дается. И потом сравнить что там и что получится у меня. И посмотреть какой вариант удобнее.
    Запись от Viktorrus размещена 30.10.2020 в 17:39 Viktorrus вне форума
  17. Старый комментарий
    Аватар для Welemir1
    а в архив то нельзя все упаковать? Так я точно собирать все не буду. Или выложи в репозиторий гит, там посмотрю
    Запись от Welemir1 размещена 30.10.2020 в 17:45 Welemir1 вне форума
  18. Старый комментарий
    Аватар для Avazart
    Освойте гит-гитхаб.
    Запись от Avazart размещена 30.10.2020 в 19:28 Avazart на форуме
  19. Старый комментарий
    Я на сайте GitHub создал открытый Repository с названием
    journalEntriesTemplate1
    Там разместил 3 файла моего проекта.
    Мое имя на Гитхабе Viktorrus350
    Вы можете оттуда скачать эти файлы?
    А я займусь обучающей программой на Гитхабе, что бы научится с ним работать.
    Запись от Viktorrus размещена 30.10.2020 в 22:08 Viktorrus вне форума
  20. Старый комментарий
    Вот страничка где мои файлы.
    https://github.com/Viktorrus35... sTemplate1
    Но как их оттуда взять я пока не знаю.
    Запись от Viktorrus размещена 30.10.2020 в 22:13 Viktorrus вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.