С Новым годом! Форум программистов, компьютерный форум, киберфорум
Python для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.85/88: Рейтинг темы: голосов - 88, средняя оценка - 4.85
1 / 1 / 0
Регистрация: 30.04.2019
Сообщений: 89
1

Телефонный справочник

10.06.2019, 22:54. Показов 17465. Ответов 23
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте!

Столкнулся с некоторыми проблемами реализации телефонного справочника. Условия:

1. Функции:
а) добавление ФИО, номера телефона, даты рождения
б) поиск по ФИО
в) удаление по ФИО
г) демонстрация всего справочника

2. Хранение справочника на жестком диске в текстовом документе
Для меня не понятно как лучше организовать доступ к данным и их редактирование. Что я сделал:

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

Адекватно ли подобное решение?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
10.06.2019, 22:54
Ответы с готовыми решениями:

Телефонный справочник
Всем привет, помогите решить задачу Напишите программу, которая имитировала бы работу простого...

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

Телефонный справочник
Помогите, пожалуйста, написать программу. Я запуталась в ее написании( Требования к программе:...

Написать программу - телефонный справочник (на основании словарей)
Здравствуйте, в общем нужно написать программу - телефонный справочник (на основании словарей)....

23
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
11.06.2019, 01:00 2
constantin_01, Само условие в задаче примитивное, использующее примитивные средства и потому трудоемкие.
Цитата Сообщение от constantin_01 Посмотреть сообщение
Хранение справочника на жестком диске в текстовом документе
подразумевает создание примитивного справочник без наличия классов. Вы не сможете сохранить экземпляры классов в текстовом документе. Их в виде объектов, а не текста, можно сохранить только в базе данных с помощью модуля shelve, или хотя бы используя модуль pickle. Писать телефонную книгу, что бы сохранять ее в виде текстового файла, это настолько муторная работа. Как это делается описано в книге Лутц М. Программирование на Python. Том 1 (4-е издание, 2011) стр.55-61. Я думаю там разбирается такой пример только для того, что бы люди поняли как это трудоемко, и в следующих главах оценили насколько удобнее создавать такие структуры с помощью классов и хранить в виде объектов (а не текстов), в базе данных с помощью модуля shelve.
0
1 / 1 / 0
Регистрация: 30.04.2019
Сообщений: 89
11.06.2019, 09:02  [ТС] 3
Viktorrus, это лабораторная работа из учебной программы ВУЗа (1 курс). Предполагается, что студент должен проделать ту же работу, что описана в упомянутой книге? Т.е. без использования классов и вспомогательных модулей?
0
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
11.06.2019, 16:21 4
constantin_01, Тогда понятно. Но эта работа очень нудная. Я когда читал этот материал, понял смысл, но глубоко вникать не стал, так как мне, при наличии более удобных средств, такая технология никогда не понадобится.

Я не знаю, что Вам нужно, выясняете это у того кто дал задание.

Добавлено через 4 минуты
Просто объекты классов и даже любые объекты питона, кроме текстовых строк, Вы не можете сохранять в текстовом файле.

Добавлено через 3 минуты
Просто у Лутца в примере объекты питона, списки и словари по определенной методике преобразуются в текстовую строку и записываются в файл. А затем при загрузке из файла, опять по той же методике но в обратном порядке восстанавливают списки и словари питона.
0
60 / 86 / 16
Регистрация: 25.03.2019
Сообщений: 235
11.06.2019, 16:42 5
Цитата Сообщение от constantin_01 Посмотреть сообщение
Адекватно ли подобное решение?
Адекватное решение - это создать SQLite базу данных. Все остальное решалось бы запросами к этой базе данных.

А то, что написано у вас, без кода непонятно.
0
5047 / 3392 / 1156
Регистрация: 21.03.2016
Сообщений: 8,214
11.06.2019, 19:06 6
я бы начал с конца
Цитата Сообщение от constantin_01 Посмотреть сообщение
Хранение справочника на жестком диске в текстовом документе
то есть определил структуру хранения
Иванов Иван Иванович : тел.8888 06.10.92
Петров Добрович : тел.9999 02.12.98
Шишков Павлович : тел.02 23.12.93
ну а дальше считываем из файла и получаем словарь где ключ фио а значение остальные данные
Python
1
2
3
4
5
6
7
base = {}
 
with open('text.txt') as f:
    for line in f:
        key,val = line.strip().split(':')
        base[key] = val.split()
print(base)
=
{'Иванов Иван Иванович ': ['тел.8888', '06.10.92'], 'Петров Добрович ': ['тел.9999', '02.12.98'], 'Шишков Павлович ': ['тел.02', '23.12.93']}
>>>
ну и по остальным пунктам работаем с словарем

Добавлено через 7 минут
а в файл пишите опять строки получив их из словаря
Python
1
2
for key,val in base.items():
    print(f"{key} : {' '.join(val)}")
=
Иванов Иван Иванович : тел.8888 06.10.92
Петров Добрович : тел.9999 02.12.98
Шишков Павлович : тел.02 23.12.93
>>>
0
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
11.06.2019, 21:43 7
constantin_01, Вот Вам дал нужное решение Semen-Semenich,
Я же не могу заставить себя работать с питоном на таком уровне, когда есть ООП, мне это не интересно. Такой у меня пунктик.
0
1 / 1 / 0
Регистрация: 30.04.2019
Сообщений: 89
11.06.2019, 23:07  [ТС] 8
Semen-Semenich, спасибо за ответ!

Viktorrus, меня интересует как в реальной жизни реализуются подобные проекты. На протяжении всего обучения я занимался только академической составляющей (алгоритмы, структуры, доказательства), решал задачи из сборников.

Я не имею никакого представления как правильно решать реальные задачи. Например, где я могу найти исходник реально использующегося онлайн-справочника написанного на python?
0
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
12.06.2019, 00:15 9
Цитата Сообщение от constantin_01 Посмотреть сообщение
онлайн-справочника
Онлайн справочник, это уже справочник написанный с использованием веб программирования, который размещается на сервере. Я веб знаю поверхностно. Когда я занимался вебом, сервера предоставляющие место для веб сайтов не поддерживали скрипты на питоне. Они поддерживали БД SQL и скрипты на PHP. Как сейчас обстоят дела не знаю.
И еще, для реальных задач на современном уровне нужен графический интерфейс. Все это есть у Лутца, но для того, что бы это освоить нужно изучить первую книгу и потом соответствующие разделы из второй и третьей книги.
Лутц М. Изучаем Python (4-е издание, 2011)
Лутц М. Программирование на Python. Том 1 (4-е издание, 2011)
Лутц М. Программирование на Python. Том 2 (4-е издание, 2011)

Представление, как создаются реальные проекты на питоне, можно понять, изучив главу 1 в книге
Лутц М. Программирование на Python. Том 1 (4-е издание, 2011). На протяжении главы осваивается конкретный пример.
И уже после этого можно дополнить свои знания в других главах, которые могут понадобится именно для Вашей задачи.

Добавлено через 16 минут
constantin_01, И попробуйте поискать исходники в интернете.
Если дать для поиска строку "Исходный текст реальной программы на Python", то дается много ссылок на исходники примеров программ на Python.
0
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
12.06.2019, 12:10 10
constantin_01, Кстати, не в качестве исходника, а в качестве хорошего онлайн справочника по питону на русском языке
https://pythonz.net/references/named/python/
в объеме приблизительно соответствующем первой книге Лутца ,
Лутц М. Изучаем Python (4-е издание, 2011)
0
1 / 1 / 0
Регистрация: 30.04.2019
Сообщений: 89
12.06.2019, 13:29  [ТС] 11
Viktorrus, спасибо за ответ!
0
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
12.06.2019, 14:27 12
constantin_01, Вот вариант Телефонного справочника с использованием технологии ООП.
Код работающий, но у меня никак руки не доходят доделать его. В первую очередь нужно создать графический интерфейс. В нем в том числе разместить поиск записи, а так же кнопку удаления записи. А в переспективе скролинг и другие прибамбасы, в том числе кнопку резервного копирования. Но в принципе уже с тем что есть можно реально работать и заносить в него телефоны.
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
import shelve
class PhoneBook:
    def __init__(self, nameBook, dicRec={}):
        self.nameBook = nameBook
        self.dicRec = dicRec
    def loadBook(self):
        db = shelve.open(self.nameBook)
        self.dicRec = dict(db.items())
        db.close()
    def saveBook(self):
        db = shelve.open(self.nameBook)
        for (key, record) in self.dicRec.items():
            db[key] = record
        db.close()
 
    def createRec(self):
        print(self.nameBook)
        label = input('название записи: ')
        phone = input('телефон : ')
        print('ФИО,коммент. - Если нет, просто нажимайте Enter')
        familyName = input('ФИО: ')
        comment = input('Комментарий: ')
        if len(self.dicRec)>0:
            L = sorted(self.dicRec.items(), key=lambda item: item[0])
            keyRec = str(int(L[-1][0]) + 1)
        else:
            keyRec = "1"
        record = PhoneRec(keyRec, label, phone, familyName, comment)
        self.dicRec[keyRec] = record
    def delPhoneRec(self, key):
        del dicRec[key]
    def readPhoneRec(self):
        for key in t1.dicRec.keys():
            print("{:<3}- {:<25}- {:<20}- {:<30}- {:<30}".format(key, t1.dicRec[key].label, 
                                                                            t1.dicRec[key].phone, 
                                                                            t1.dicRec[key].familyName,  
                                                                            t1.dicRec[key].comment))
class PhoneRec:
    def __init__(self, keyRec, label, phone, familyName, comment):
        self.keyRec = keyRec
        self.label = label
        self.phone = phone
        self.familyName = familyName
        self.comment = comment
 
if __name__ == '__main__':
    t1 = PhoneBook("Телефоны")
    t1.loadBook()
    t1.createRec()
    t1.readPhoneRec()
 
    t1.saveBook()
 
    # Строка необходима пока нет графического интерфейса, 
    # что бы командное окно с информацией не закрывалось,
    # пока вы не нажмете Enter.
    input('ОКОНЧАНИЕ РАБОТЫ')
Добавлено через 25 минут
constantin_01, В принципе этот пример может служить шаблоном написания кода для двухуровневых структур. Таких как: магазин-товар, офис-работники, склад-содержимое склада и так далее. Вот только мне надо доделать этот пример, что бы он был более функционален и удобен для работы. И в первую очередь сделать графический интерфейс. В принципе я знаю как его сделать, используя пример у Лутца, но нужно найти время (хотя время у меня есть) и скорее желание этим заняться, так как придется оторваться от изучения Лутца.
1
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
25.06.2019, 17:09 13
constantin_01, Вот я к своему телефонному справочнику добавил графический интерфейс.
Можете этот код использовать в качестве примера при своих разработках. Правда я еще не написал функцию для поиска, поэтому пока без него.
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# файл *.pyw (расширение .pyw необходимо для подавления окна DOS)
 
from tkinter import *
import shelve
 
class PhoneBook:
    def __init__(self, nameBook, dicRec={}):
        self.nameBook = nameBook
        self.dicRec = dicRec
    def loadBook(self):
        db = shelve.open(self.nameBook)
        self.dicRec = dict(db.items())
        db.close()
    def saveBook(self):
        db = shelve.open(self.nameBook)
        for (key, record) in self.dicRec.items():
            db[key] = record
        db.close()
 
class PhoneRec:
    def __init__(self, keyRec, char, label, phone, familyName, comment, delR=''):
        self.keyRec = keyRec
        self.char = char
        self.label = label
        self.phone = phone
        self.familyName = familyName
        self.comment = comment
        self.delR = delR
 
fieldnamesRec = ('keyRec', 'char', 'label', 'phone', 'familyName', 'comment', 'delR')
activCh = 'А'
 
def makeWidgets():
    global entriesRec, entRec
    window = Tk()
    window.title('Телефонны')
    window.geometry('1260x600+0+0')
    form1 = Frame(window)
    form1.pack()
    alph = ["А", "Б", "В", "Г", "Д", "Е", "Ж", "З", "И", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т", 
            "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Э", "Ю", "Я"]
    for i in range(len(alph)):
        Button(form1, text=alph[i], command=(lambda x=alph[i]: fetch(x))).pack(side=LEFT)
    entFind = Entry(form1, width=27).pack(side=LEFT)
    Button(form1, text="Поиск", command=fetchFind).pack(side=LEFT)
 
    form2 = Frame(window)
    form2.pack()
    entriesRec = {}
    entRec = {}
    for (ix, label) in enumerate(fieldnamesRec):
        lab = Label(form2, text=label)
        lab.grid(row=2, column=ix)
    for i in range(1, 26):
        for (ix, label) in enumerate(fieldnamesRec):
            if label == 'keyRec' or label == 'char' or label == 'delR':
                ent = Entry(form2, state='normal', width=6)
            else:
                ent = Entry(form2, width=40)
            ent.grid(row=i+2, column=ix)
            entriesRec[label+str(i)] = ent
    Button(window, text="Сохранить", command=saveRec).pack(side=LEFT)
    labKeyRec = Label(window, text='keyRec').pack(side=LEFT)
    ent = Entry(window, width=10)
    ent.pack(side=LEFT)
    entRec['entKeyRec'] = ent
    Button(window, text="Удалить", command=delKeyRec).pack(side=LEFT)
    Button(window, text="Выход", command=lambda :window.destroy()).pack(side=RIGHT)
    return window
 
def clear_sheet():
    for i in range(1, 26):
        for field in fieldnamesRec:
            if field == 'keyRec' or field == '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 fetch(ch):
    global activCh
    clear_sheet()
    activCh = ch
    count = 1
    dicRe = t1.dicRec.copy()
    while count <= 25 and len(dicRe):
        for key in t1.dicRec.keys():
            if t1.dicRec[key].char == ch: #and t1.dicRec[key].delR=='':
                record = t1.dicRec[key]
                for field in fieldnamesRec:
                    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:
                    break
            else:
                dicRe.pop(key)
    return dicRe
 
def delKeyRec():
    # физическое удаление из базы данных
    key = entRec['entKeyRec'].get()
    del t1.dicRec[key]
    db = shelve.open(t1.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)
    # пометить как удаленную
#    key = entRec['entKeyRec'].get()
#    record = t1.dicRec[key]
#    setattr(record, 'delR', 'у')
#    print(t1.dicRec[key].delR)
#    entRec['entKeyRec'].delete(0, END)
def fetchFind():
    pass
def saveRec():
    for i in range(1, 26):
        key = entriesRec['keyRec'+str(i)].get()
        if entriesRec['delR'+str(i)].get() == 'у':
            continue
        elif key:
            record = t1.dicRec[key]
            for field in fieldnamesRec:
                setattr(record, field, entriesRec[field+str(i)].get())
            t1.dicRec[key] = record
        else:
            existRec = False
            for field in fieldnamesRec:
                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
                label = entriesRec['label'+str(i)].get()
                phone = entriesRec['phone'+str(i)].get()
                familyName = entriesRec['familyName'+str(i)].get()
                comment = entriesRec['comment'+str(i)].get()
                if len(t1.dicRec)>0:
                    L = sorted(t1.dicRec.items(), key=lambda item: int(item[0]))
                    keyRec = str(int(L[-1][0]) + 1)
                else:
                    keyRec = "1"
                record = PhoneRec(keyRec, char, label, phone, familyName, comment)
                t1.dicRec[keyRec] = record
    t1.saveBook()
    fetch(activCh)
 
if __name__ == '__main__':
 
    t1 = PhoneBook("Телефоны")
    t1.loadBook()
 
    window = makeWidgets()
    window.mainloop()
2
1 / 1 / 0
Регистрация: 30.04.2019
Сообщений: 89
25.06.2019, 19:12  [ТС] 14
Viktorrus, спасибо!

На самом деле я уже на следующий день почитал Лутца и разобрался в tkinter. Телефонный справочник собрал со всеми функциями
0
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
26.06.2019, 01:03 15
constantin_01, Все, сделал поиск. Теперь это полноценная телефонная книга. Запишу в нее все свои телефоны. И параллельно буду вносить мелкие усовершенствования, но которые не коснутся структуры записей, и поэтому вся занесенная информация останется не тронутой, и будет так же видна в усовершенствованной книге.
Поиск работает сразу на всю книгу , ища по всем буквам, ища по всем значащим полям (исключая поле ключей, поле букв и последнее служебное поле).
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# файл *.pyw (расширение .pyw необходимо для подавления окна DOS)
 
from tkinter import *
import shelve
 
class PhoneBook:
    def __init__(self, nameBook, dicRec={}):
        self.nameBook = nameBook
        self.dicRec = dicRec
    def loadBook(self):
        db = shelve.open(self.nameBook)
        self.dicRec = dict(db.items())
        db.close()
    def saveBook(self):
        db = shelve.open(self.nameBook)
        for (key, record) in self.dicRec.items():
            db[key] = record
        db.close()
 
class PhoneRec:
    def __init__(self, keyRec, char, label, phone, familyName, comment, delR=''):
        self.keyRec = keyRec
        self.char = char
        self.label = label
        self.phone = phone
        self.familyName = familyName
        self.comment = comment
        self.delR = delR
 
fieldnamesRec = ('keyRec', 'char', 'label', 'phone', 'familyName', 'comment', 'delR')
activCh = 'А'
 
def makeWidgets():
    global entriesRec, entRec
    entRec = {}
    window = Tk()
    window.title('Телефонны')
    window.geometry('1260x600+0+0')
    form1 = Frame(window)
    form1.pack()
    alph = ["А", "Б", "В", "Г", "Д", "Е", "Ж", "З", "И", "К", "Л", "М", "Н", "О", "П", "Р", "С", "Т", 
            "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Э", "Ю", "Я"]
    for i in range(len(alph)):
        Button(form1, text=alph[i], command=(lambda x=alph[i]: fetch(x))).pack(side=LEFT)
    ent = Entry(form1, width=27)
    ent.pack(side=LEFT)
    entRec['entFind'] = ent
    Button(form1, text="Поиск", command=fetchFind).pack(side=LEFT)
 
    form2 = Frame(window)
    form2.pack()
    entriesRec = {}
    for (ix, label) in enumerate(fieldnamesRec):
        lab = Label(form2, text=label)
        lab.grid(row=2, column=ix)
    for i in range(1, 26):
        for (ix, label) in enumerate(fieldnamesRec):
            if label == 'keyRec' or label == 'char' or label == 'delR':
                ent = Entry(form2, state='normal', width=6)
            else:
                ent = Entry(form2, width=40)
            ent.grid(row=i+2, column=ix)
            entriesRec[label+str(i)] = ent
    Button(window, text="Сохранить", command=saveRec).pack(side=LEFT)
    labKeyRec = Label(window, text='keyRec').pack(side=LEFT)
    ent = Entry(window, width=10)
    ent.pack(side=LEFT)
    entRec['entKeyRec'] = ent
    Button(window, text="Удалить", command=delKeyRec).pack(side=LEFT)
    Button(window, text="Выход", command=lambda :window.destroy()).pack(side=RIGHT)
    return window
 
def clear_sheet():
    for i in range(1, 26):
        for field in fieldnamesRec:
            if field == 'keyRec' or field == '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 fetch(ch):
    global activCh
    clear_sheet()
    activCh = ch
    count = 1
    dicRe = t1.dicRec.copy()
    while count <= 25 and len(dicRe):
        for key in t1.dicRec.keys():
            if t1.dicRec[key].char == ch: #and t1.dicRec[key].delR=='':
                record = t1.dicRec[key]
                for field in fieldnamesRec:
                    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:
                    break
            else:
                dicRe.pop(key)
    return dicRe
 
def delKeyRec():
    # физическое удаление из базы данных
    key = entRec['entKeyRec'].get()
    del t1.dicRec[key]
    db = shelve.open(t1.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)
    # пометить как удаленную
#    key = entRec['entKeyRec'].get()
#    record = t1.dicRec[key]
#    setattr(record, 'delR', 'у')
#    print(t1.dicRec[key].delR)
#    entRec['entKeyRec'].delete(0, END)
def fetchFind():
    clear_sheet()
    strF = entRec['entFind'].get()
    dicFind = {}
    for key in t1.dicRec.keys():
        record = t1.dicRec[key]
        for field in fieldnamesRec:
            if (field != 'keyRec' and field != 'char' and field != 'delR' and 
                getattr(record, field).find(strF) != -1):
                dicFind[key] = record
                break
    count = 1
    dicRe = dicFind.copy()
    while count <= 25 and len(dicRe):
        for key in dicFind.keys():
            record = dicFind[key]
            for field in fieldnamesRec:
                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:
                break
    return dicRe
 
def saveRec():
    for i in range(1, 26):
        key = entriesRec['keyRec'+str(i)].get()
        if entriesRec['delR'+str(i)].get() == 'у':
            continue
        elif key:
            record = t1.dicRec[key]
            for field in fieldnamesRec:
                setattr(record, field, entriesRec[field+str(i)].get())
            t1.dicRec[key] = record
        else:
            existRec = False
            for field in fieldnamesRec:
                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
                label = entriesRec['label'+str(i)].get()
                phone = entriesRec['phone'+str(i)].get()
                familyName = entriesRec['familyName'+str(i)].get()
                comment = entriesRec['comment'+str(i)].get()
                if len(t1.dicRec)>0:
                    L = sorted(t1.dicRec.items(), key=lambda item: int(item[0]))
                    keyRec = str(int(L[-1][0]) + 1)
                else:
                    keyRec = "1"
                record = PhoneRec(keyRec, char, label, phone, familyName, comment)
                t1.dicRec[keyRec] = record
    t1.saveBook()
    fetch(activCh)
 
if __name__ == '__main__':
 
    t1 = PhoneBook("Телефоны")
    t1.loadBook()
 
    window = makeWidgets()
    window.mainloop()
1
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
28.06.2019, 20:37 16
constantin_01, Сделал новую версию телефонного справочника. Серьезный недостаток предыдущей версии в том, что там для конкретной буквы количество записей ограничено, можно для одной буквы завести только 25 записей.
В новой версии количество записей не ограничено, и появилась возможность листать страницы. Это удалось сделать изменив структуру кода.
constantin_01, Там же по Вашему совету изменил расположение кнопок, которые внизу. Так как я графику пока еще серьезно не изучал, то сделал это примитивным способом, используя pack() и вставив пустые Label между кнопками. Когда изучу графику, то сделаю более профессионально.
Вот новый код Телефонной книги.
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# файл *.pyw (расширение .pyw необходимо для подавления окна DOS)
 
from tkinter import *
import shelve
 
class PhoneBook:
    def __init__(self, nameBook, dicRec={}):
        self.nameBook = nameBook
        self.dicRec = dicRec
    def loadBook(self):
        db = shelve.open(self.nameBook)
        self.dicRec = dict(db.items())
        db.close()
    def saveBook(self):
        db = shelve.open(self.nameBook)
        for (key, record) in self.dicRec.items():
            db[key] = record
        db.close()
 
class PhoneRec:
    def __init__(self, keyRec, char, label, phone, familyName, comment, delR=''):
        self.keyRec = keyRec
        self.char = char
        self.label = label
        self.phone = phone
        self.familyName = familyName
        self.comment = comment
        self.delR = delR
 
fieldnamesRec = ('keyRec', 'char', 'label', 'phone', 'familyName', 'comment', 'delR')
activCh = 'А'
dicRem = {}
 
def makeWidgets():
    global entriesRec, entRec
    entRec = {}
    window = Tk()
    window.title('Телефоны')
    window.geometry('1260x600+0+0')
    form1 = Frame(window)
    form1.pack()
    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
    Button(form1, text="Поиск", command=fetchFind).pack(side=LEFT)
 
    form2 = Frame(window)
    form2.pack()
    entriesRec = {}
    for (ix, label) in enumerate(fieldnamesRec):
        lab = Label(form2, text=label)
        lab.grid(row=2, column=ix)
    for i in range(1, 26):
        for (ix, label) in enumerate(fieldnamesRec):
            if label == 'keyRec' or label == 'char' or label == 'delR':
                ent = Entry(form2, state='normal', width=6)
            else:
                ent = Entry(form2, width=40)
            ent.grid(row=i+2, column=ix)
            entriesRec[label+str(i)] = ent
    form3 = Frame(window)
    form3.pack()
    Button(window, text="Следующая страница", command=fetchNext).pack()
    Label(window, text='      ', width=10).pack(side=LEFT)
    labKeyRec = Label(window, text='keyRec').pack(side=LEFT)
    ent = Entry(window, width=10)
    ent.pack(side=LEFT)
    entRec['entKeyRec'] = ent
    Button(window, text="Удалить", command=delKeyRec).pack(side=LEFT)
    Label(window, text='      ', width=20).pack(side=LEFT)
    btns = Button(window, text="Сохранить страницу", command=saveRec).pack(side=LEFT)
    Label(window, text='      ', width=40).pack(side=LEFT)
    Label(window, text='      ', width=10).pack(side=LEFT)
    Button(window, text="Выход", command=lambda :window.destroy()).pack(side=LEFT)
    return window
 
def clear_sheet():
    for i in range(1, 26):
        for field in fieldnamesRec:
            if field == 'keyRec' or field == '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):
    global activCh
    activCh = ch
    dicRecChr = {}
    for key in t1.dicRec.keys():
        if t1.dicRec[key].char == ch:
            dicRecChr[key] = t1.dicRec[key]
    fetch(dicRecChr)
def fetch(dicR):
    global dicRem
    clear_sheet()
    count = 1
    dicRe = dicR.copy()
    while count <= 25 and len(dicRe):
        for key in dicR.keys():
            record = dicR[key]
            for field in fieldnamesRec:
                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:
                break
    dicRem = dicRe.copy()
 
def fetchNext():
    fetch(dicRem)
 
def delKeyRec():
    # физическое удаление из базы данных
    key = entRec['entKeyRec'].get()
    del t1.dicRec[key]
    db = shelve.open(t1.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)
    # пометить как удаленную
#    key = entRec['entKeyRec'].get()
#    record = t1.dicRec[key]
#    setattr(record, 'delR', 'у')
#    print(t1.dicRec[key].delR)
#    entRec['entKeyRec'].delete(0, END)
def fetchFind():
    clear_sheet()
    strF = entRec['entFind'].get()
    dicFind = {}
    for key in t1.dicRec.keys():
        record = t1.dicRec[key]
        for field in fieldnamesRec:
            if (field != 'keyRec' and field != 'char' and field != 'delR' and 
                getattr(record, field).find(strF) != -1):
                dicFind[key] = record
                break
    fetch(dicFind)
def saveRec():
    for i in range(1, 26):
        key = entriesRec['keyRec'+str(i)].get()
        if entriesRec['delR'+str(i)].get() == 'у':
            continue
        elif key:
            record = t1.dicRec[key]
            for field in fieldnamesRec:
                setattr(record, field, entriesRec[field+str(i)].get())
            t1.dicRec[key] = record
        else:
            existRec = False
            for field in fieldnamesRec:
                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
                label = entriesRec['label'+str(i)].get()
                phone = entriesRec['phone'+str(i)].get()
                familyName = entriesRec['familyName'+str(i)].get()
                comment = entriesRec['comment'+str(i)].get()
                if len(t1.dicRec)>0:
                    L = sorted(t1.dicRec.items(), key=lambda item: int(item[0]))
                    keyRec = str(int(L[-1][0]) + 1)
                else:
                    keyRec = "1"
                record = PhoneRec(keyRec, char, label, phone, familyName, comment)
                t1.dicRec[keyRec] = record
    t1.saveBook()
    fetchChr(activCh)
 
if __name__ == '__main__':
 
    t1 = PhoneBook("Телефоны")
    t1.loadBook()
 
    window = makeWidgets()
    window.mainloop()
У кого будут замечания, буду рад их выслушать.
1
1 / 1 / 0
Регистрация: 30.04.2019
Сообщений: 89
28.06.2019, 21:14  [ТС] 17
Viktorrus, здорово!

Меня интересует в каком режиме Вы работали над книгой. Лично я за 3 дня сделал свою версию - в первый день 3-4 часа: чтение Лутца, изучение Tkinter; во-второй день 2-3 часа сама работа; на третий день 2-3 часа на отладку кода и оптимизацию.
0
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
28.06.2019, 22:00 18
constantin_01, Я не помню. Я телефонную книгу делаю не спеша, когда появляется желание. После того, как отрываюсь от изучения Лутца. На телефонной книге я отдыхаю, в отличие от изучения последних глав у Лутц М. Изучаем Python (4-е издание, 2011). Сейчас изучаю главу Управляемые атрибуты, в том числе дескрипторы.
0
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
01.07.2019, 01:32 19
constantin_01, Я думал, думал и все таки решил дать возможность телефоны, которые действующие, но вам вроде бы уже и не нужны, не удалять, так как они удаляются физически и их уже не восстановишь, а скрывать. Вдруг все таки еще когда нибудь понадобятся. Но что бы при этом не болтались перед глазами и не загружали телефонную книгу, усложняя поиск телефонов с которыми Вы работаете на текущий момент, их скрыть. При этом можно вывести скрытые телефоны и произвести среди них поиск. При необходимости скрытый телефон можно открыть.
И еще раз напоминаю, что перед уходом со страницы (любым способом), если Вы заносили какую либо информацию на этой странице, то перед переходом нужно обязательно сохранить страницу, иначе все изменения на ней пропадут. Исключением является только удаление записи, если вы ее удалите, то она удаляется физически с момента нажатия кнопки "Удалить", и ее уже никак не восстановить. Поэтиму советую не злоупотреблять удалением записей, а лучше их просто скрывать.
Вот обновленный код.
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# файл *.pyw (расширение .pyw необходимо для подавления окна DOS)
 
from tkinter import *
import shelve
 
class PhoneBook:
    def __init__(self, nameBook, dicRec={}):
        self.nameBook = nameBook
        self.dicRec = dicRec
    def loadBook(self):
        db = shelve.open(self.nameBook)
        self.dicRec = dict(db.items())
        db.close()
    def saveBook(self):
        db = shelve.open(self.nameBook)
        for (key, record) in self.dicRec.items():
            db[key] = record
        db.close()
 
class PhoneRec:
    def __init__(self, keyRec, char, label, phone, familyName, comment, delR=''):
        self.keyRec = keyRec
        self.char = char
        self.label = label
        self.phone = phone
        self.familyName = familyName
        self.comment = comment
        self.delR = delR
 
fieldnamesRec = ('keyRec', 'char', 'label', 'phone', 'familyName', 'comment', 'delR')
activCh = 'А'
typeRec = ''
dicRem = {}
 
def makeWidgets():
    global entriesRec, entRec
    entRec = {}
    window = Tk()
    window.title('Телефоны')
    window.geometry('1260x600+0+0')
    form1 = Frame(window)
    form1.pack()
    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
    Button(form1, text="Поиск", command=fetchFind).pack(side=LEFT)
 
    form2 = Frame(window)
    form2.pack()
    entriesRec = {}
    for (ix, label) in enumerate(fieldnamesRec):
        lab = Label(form2, text=label)
        lab.grid(row=2, column=ix)
    for i in range(1, 26):
        for (ix, label) in enumerate(fieldnamesRec):
            if label == 'keyRec' or label == 'char' or label == 'delR':
                ent = Entry(form2, state='normal', width=6)
            else:
                ent = Entry(form2, width=40)
            ent.grid(row=i+2, column=ix)
            entriesRec[label+str(i)] = ent
    form3 = Frame(window)
    form3.pack()
    Button(window, text="Следующая страница", command=fetchNext).pack()
    Label(window, text='      ', width=10).pack(side=LEFT)
    labKeyRec = Label(window, text='keyRec').pack(side=LEFT)
    ent = Entry(window, width=10)
    ent.pack(side=LEFT)
    entRec['entKeyRec'] = ent
    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=5).pack(side=LEFT)
    Button(window, text="Удалить", command=delKeyRec).pack(side=LEFT)
    Label(window, text='      ', width=30).pack(side=LEFT)
    btns = Button(window, text="Сохранить страницу", command=saveRec).pack(side=LEFT)
    Label(window, text='      ', width=20).pack(side=LEFT)
    Button(window, text="Выход", command=lambda :window.destroy()).pack(side=LEFT)
    return window
 
def clear_sheet():
    for i in range(1, 26):
        for field in fieldnamesRec:
            if field == 'keyRec' or field == '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):
    global activCh, typeRec
    typeRec = ''
    activCh = ch
    dicRecChr = {}
    for key in t1.dicRec.keys():
        if t1.dicRec[key].char == ch:
            dicRecChr[key] = t1.dicRec[key]
    fetch(dicRecChr)
def fetchHide():
    global typeRec
    typeRec = 'с'
    fetch(t1.dicRec)
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:
            if dicR[key].delR == typeRec:
                record = dicR[key]
                for field in fieldnamesRec:
                    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:
                    break
            else:
                dicRe.pop(key)
    dicRem = dicRe.copy()
 
def fetchNext():
    fetch(dicRem)
 
def delKeyRec():
    # физическое удаление из базы данных
    key = entRec['entKeyRec'].get()
    del t1.dicRec[key]
    db = shelve.open(t1.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)
def hideRec():
    # пометить как скрытую
    key = entRec['entKeyRec'].get()
    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()
    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)
 
def fetchFind():
    clear_sheet()
    strF = entRec['entFind'].get()
    dicFind = {}
    for key in t1.dicRec.keys():
        record = t1.dicRec[key]
        for field in fieldnamesRec:
            if (field != 'keyRec' and field != 'char' and field != 'delR' and 
                getattr(record, field).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 = t1.dicRec[key]
            for field in fieldnamesRec:
                setattr(record, field, entriesRec[field+str(i)].get())
            t1.dicRec[key] = record
        else:
            existRec = False
            for field in fieldnamesRec:
                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
                label = entriesRec['label'+str(i)].get()
                phone = entriesRec['phone'+str(i)].get()
                familyName = entriesRec['familyName'+str(i)].get()
                comment = entriesRec['comment'+str(i)].get()
                if len(t1.dicRec)>0:
                    L = sorted(t1.dicRec.items(), key=lambda item: int(item[0]))
                    keyRec = str(int(L[-1][0]) + 1)
                else:
                    keyRec = "1"
                record = PhoneRec(keyRec, char, label, phone, familyName, comment)
                t1.dicRec[keyRec] = record
    t1.saveBook()
    typeRec = ''
    fetchChr(activCh)
 
if __name__ == '__main__':
 
    t1 = PhoneBook("Телефоны")
    t1.loadBook()
 
    window = makeWidgets()
    window.mainloop()
0
1729 / 969 / 199
Регистрация: 22.02.2018
Сообщений: 2,694
Записей в блоге: 6
03.07.2019, 02:29 20
constantin_01, Начал заносить в книгу свои телефоны и понял, что сохранение страницы только при нахатии кнопки "Сохранить страницу", это очень не удобно. Иногда забываешь нажать и изменения на странице пропадают. Да и надоедает постоянно нажимать лишнюю кнопку. Поэтому сделал автоматическое сохранение при любом уходе со страницы.
Хотел было удалить кнопку "Сохранение", но потом решил оставить на случай, когда на странице сразу вводится большое количество записей. Тогда имеет смысл кнопкой периодически принудительно сохранять изменения на странице, на случай отключения электроэнергии. В стандартных базах данных, там вообще для каждой записи, как только мы уходим с записи, то она автоматически сохраняется. Но это я подумаю, может в будущем тоже так сделаю.
А пока, вот новая версия телефонной книги
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# файл *.pyw (расширение .pyw необходимо для подавления окна DOS)
 
from tkinter import *
import shelve
 
class PhoneBook:
    def __init__(self, nameBook, dicRec={}):
        self.nameBook = nameBook
        self.dicRec = dicRec
    def loadBook(self):
        db = shelve.open(self.nameBook)
        self.dicRec = dict(db.items())
        db.close()
    def saveBook(self):
        db = shelve.open(self.nameBook)
        for (key, record) in self.dicRec.items():
            db[key] = record
        db.close()
 
class PhoneRec:
    def __init__(self, keyRec, char, label, phone, familyName, comment, delR=''):
        self.keyRec = keyRec
        self.char = char
        self.label = label
        self.phone = phone
        self.familyName = familyName
        self.comment = comment
        self.delR = delR
 
fieldnamesRec = ('keyRec', 'char', 'label', 'phone', 'familyName', 'comment', 'delR')
activCh = 'А'
typeRec = ''
dicRem = {}
 
def makeWidgets():
    global entriesRec, entRec, lab1
    entRec = {}
    window = Tk()
    window.title('Телефоны')
    window.geometry('1260x600+0+0')
    form1 = Frame(window)
    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
    Button(form1, text="Поиск", command=fetchFind).pack(side=LEFT)
 
    form2 = Frame(window)
    form2.pack()
    entriesRec = {}
    for (ix, label) in enumerate(fieldnamesRec):
        lab = Label(form2, text=label)
        lab.grid(row=2, column=ix)
    for i in range(1, 26):
        for (ix, label) in enumerate(fieldnamesRec):
            if label == 'keyRec' or label == 'char' or label == 'delR':
                ent = Entry(form2, state='normal', width=6)
            else:
                ent = Entry(form2, width=40)
            ent.grid(row=i+2, column=ix)
            entriesRec[label+str(i)] = ent
    form3 = Frame(window)
    form3.pack()
    Button(window, text="Следующая страница", command=fetchNext).pack()
    Label(window, text='      ', width=10).pack(side=LEFT)
    labKeyRec = Label(window, text='keyRec').pack(side=LEFT)
    ent = Entry(window, width=10)
    ent.pack(side=LEFT)
    entRec['entKeyRec'] = ent
    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=5).pack(side=LEFT)
    Button(window, text="Удалить", command=delKeyRec).pack(side=LEFT)
    Label(window, text='      ', width=30).pack(side=LEFT)
    btns = Button(window, text="Сохранить", command=saveRec).pack(side=LEFT)
    Label(window, text='      ', width=20).pack(side=LEFT)
    Button(window, text="Выход", command=fin).pack(side=LEFT)
    return window
 
def clear_sheet():
    for i in range(1, 26):
        for field in fieldnamesRec:
            if field == 'keyRec' or field == '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):
    global activCh, typeRec, lab1
    saveRec()
    typeRec = ''
    activCh = ch
    lab1.config(text=activCh)
    dicRecChr = {}
    for key in t1.dicRec.keys():
        if t1.dicRec[key].char == ch:
            dicRecChr[key] = t1.dicRec[key]
    fetch(dicRecChr)
def fetchHide():
    global typeRec
    saveRec()
    typeRec = 'с'
    fetch(t1.dicRec)
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 fieldnamesRec:
                    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:
                    break
            else:
                dicRe.pop(key)
    dicRem = dicRe.copy()
 
def fetchNext():
    saveRec()
    fetch(dicRem)
 
def delKeyRec():
    # физическое удаление из базы данных
    key = entRec['entKeyRec'].get()
    del t1.dicRec[key]
    db = shelve.open(t1.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)
def hideRec():
    # пометить как скрытую
    key = entRec['entKeyRec'].get()
    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()
    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)
 
def fetchFind():
    saveRec()
    clear_sheet()
    strF = entRec['entFind'].get()
    dicFind = {}
    for key in t1.dicRec.keys():
        record = t1.dicRec[key]
        for field in fieldnamesRec:
            if (field != 'keyRec' and field != 'char' and field != 'delR' and 
                getattr(record, field).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 = t1.dicRec[key]
            for field in fieldnamesRec:
                setattr(record, field, entriesRec[field+str(i)].get())
            t1.dicRec[key] = record
        else:
            existRec = False
            for field in fieldnamesRec:
                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
                label = entriesRec['label'+str(i)].get()
                phone = entriesRec['phone'+str(i)].get()
                familyName = entriesRec['familyName'+str(i)].get()
                comment = entriesRec['comment'+str(i)].get()
                if len(t1.dicRec)>0:
                    L = sorted(t1.dicRec.items(), key=lambda item: int(item[0]))
                    keyRec = str(int(L[-1][0]) + 1)
                else:
                    keyRec = "1"
                record = PhoneRec(keyRec, char, label, phone, familyName, comment)
                t1.dicRec[keyRec] = record
    t1.saveBook()
 
def fin():
    saveRec()
    window.destroy()
 
if __name__ == '__main__':
 
    t1 = PhoneBook("Телефоны")
    t1.loadBook()
 
    window = makeWidgets()
    fetchChr('А')
    window.mainloop()
Добавлено через 6 минут
В ближайшее время код за комментирую, а то сам уже начинаю забывать, что к чему. И если все таки кто то захочет использовать этот код в качестве примера, то комментарии помогут ему разобраться с содержимым.
0
03.07.2019, 02:29
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
03.07.2019, 02:29
Помогаю со студенческими работами здесь

Класс "Телефонный справочник"
Я только начал изучать Python. Сам себе придумал задание и пытаюсь его сделать. Условие: ...

Телефонный номер
На различных сайтах часто требуется ввести номер телефона в определённом формате. Напиши программу,...

Телефонный номер
Здравствуйте, помогите пожалуйста с задачей, не могу понять как решается, спасибо! Дан...

Вывести телефонный номер с необходимыми разделителями
Помогите пожалуйста с задачей: С помощью re.sub написать код, который на вход получает номер...

Телефонный справочник
Помогите пожалуйста ! Реализуйте простой телефонный справочник (Имя-Телефон), хранящий данные в...

Телефонный асистент
Дано список номеров телефонов. Написать программу, которая при вводе первых цифр номера телефона...

Телефонный справочник
Напишите приложение &quot;Телефонный справочник&quot;, позволяющее создавать список абонентов, просматривать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Книги и учебные ресурсы по C#
InfoMaster 08.01.2025
Базовые учебники и руководства Одной из лучших книг для начинающих является "C# 10 и . NET 6 для начинающих" Эндрю Троелсена и Филиппа Джепикса . Книга последовательно раскрывает основные концепции. . .
Что такое NullReferenceEx­­­ception и как исправить?
InfoMaster 08.01.2025
NullReferenceException - одно из самых распространенных исключений, с которым сталкиваются разработчики на C#. Это исключение возникает при попытке обратиться к членам объекта (методам, свойствам или. . .
Что такое Null Pointer Exception (NPE) и как это исправить?
InfoMaster 08.01.2025
Null Pointer Exception (NPE) - это одно из самых распространенных исключений в Java, которое возникает при попытке использовать ссылку на объект, значение которой равно null. Это исключение относится. . .
Русский язык в консоли C++
InfoMaster 08.01.2025
При разработке программ на C++ одной из частых проблем, с которой сталкиваются русскоязычные программисты, является корректное отображение кириллицы в консольных приложениях. Эта проблема особенно. . .
Telegram бот на C#
InfoMaster 08.01.2025
Разработка ботов для Telegram стала неотъемлемой частью современной экосистемы мессенджеров. C# предоставляет мощный и удобный инструментарий для создания разнообразных ботов, от простых. . .
Использование GraphQL в Go (Golang)
InfoMaster 08.01.2025
Go (Golang) является одним из наиболее популярных языков программирования, используемых для создания высокопроизводительных серверных приложений. Его архитектурные особенности и встроенные. . .
Что лучше использовать при создании класса в Java: сеттеры или конструктор?
Alexander-7 08.01.2025
Вопрос подробнее: На вопрос: «Когда одновременно создаются конструктор и сеттеры в классе – это нормально?» куратор уточнил: «Ваш класс может вообще не иметь сеттеров, а только конструктор и геттеры. . .
Как работать с GraphQL на TypeScript
InfoMaster 08.01.2025
Введение в GraphQL и TypeScript В современной разработке веб-приложений GraphQL стал мощным инструментом для создания гибких и эффективных API. В сочетании с TypeScript, эта технология. . .
Счётчик на базе сумматоров + регистров и генератора сигналов согласования.
Hrethgir 07.01.2025
Создан с целью проверки скорости асинхронной логики: ранее описанного сумматора и предополагаемых fast регистров. Регистры созданы на базе ранее описанного, предполагаемого fast триггера. То-есть. . .
Как перейти с Options API на Composition API в Vue.js
BasicMan 06.01.2025
Почему переход на Composition API актуален В мире современной веб-разработки фреймворк Vue. js продолжает эволюционировать, предлагая разработчикам все более совершенные инструменты для создания. . .
Архитектура современных процессоров
inter-admin 06.01.2025
Процессор (центральный процессор, ЦП) является основным вычислительным устройством компьютера, которое выполняет обработку данных и управляет работой всех остальных компонентов системы. Архитектура. . .
История создания реляционной модели баз данных, правила Кодда
Programming 06.01.2025
Предпосылки создания реляционной модели В конце 1960-х годов компьютерная индустрия столкнулась с серьезными проблемами в области управления данными. Существовавшие на тот момент модели данных -. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru