Выпадающий список в Tkinter
15.07.2019, 20:50. Показов 12256. Ответов 4
Всем доброго времени суток. При написании маленькой программки для работы, столкнулся со сложность, которая не выдает ошибки. Есть два окна. Первое вызывает второе. Во-второй форме есть выпадающие списки. Если запускать вторую форму самостоятельно, то списки отображаются верно(рис.1). Если же запускать второе окно через первое(основное) окно программы, то списки не отображают выбранный вариант. При этом экземпляру класса StringVar передается выбранный вариант верно - через функцию print,get видно, что функционирует все нормально. На рис.2 выставлены те же параметры, что и на рис.1 и они считываются и записываются в БД корректно. Это баг Tkinter или есть подводные камни о которых я не знаю?
Не хотелось бы прибегать к костылям используя 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
| from tkinter import *
from tkinter.messagebox import showinfo,askquestion
from tkinter import filedialog
import shelve,os
import forms.def_main as def_main
#from datetime import *
def save_db(): #Фукнция сохранить БД
global road_db
main_theme='Устранение дефектов методом выборчного ремонта на секциях %s, %s-%s км, Ду %s мм.'%tuple(data_tube[i].get() for i in data)
if road_db=='':
save_as_db()
else:
try:
if road_db[-4:-3]=='.':
road_db=road_db[:road_db.rfind('.')] #если перезаписываем файл, то файл идет с расширением, убираем его.
db=shelve.open(road_db)
for i in data:
db[i]=data_tube[i].get()
showinfo(title='Сохранение!', message=main_theme)
finally:
db.close()
print('END!!!',road_db)
def save_as_db(): #Фукнция сохранить БД как...
global road_db
temp=filedialog.asksaveasfilename(filetypes=(("Data files","*.dat"),))
print('SAVE AS!!!',road_db)
if temp!='': #если открыли окно сохранения и закрыли его не выбрав файл, то путь становится пустым. Исключаем это.
road_db=temp
save_db()
def open_db(): #Фукнция открытия БД
global road_db
temp=filedialog.askopenfilename(filetypes=(("Data files","*.dat"),))[:-4]#если открыли окно "открытия" и закрыли его не выбрав файл, то путь становится пустым. Исключаем это.
if temp!='':
try:
road_db=temp
db=shelve.open(road_db)
for i in data:
data_tube[i].delete(0,END)
data_tube[i].insert(0,db[i])
print('OPEN!!!',road_db,)
finally:
db.close()
def import_form_def():
print(road_db)
print(def_db)
#akt_vh=[] #список с актами входного контроля
def_db=[] #данные посекциям с дефектами получаемые из формы def_form
road_db=''
akts_vh=[]
#-------------------------------------Основное окно
main_win=Tk()
main_win.title('Дефекты')
#--------------------------------------Меню в шапке главного окна
db_open_status=False #флаг, открыта ли БД
mainmenu=Menu(main_win) #создаем меню
main_win.config(menu=mainmenu)
filemenu=Menu(mainmenu, tearoff=0)
filemenu.add_command(label='Открыть...',command=open_db)
filemenu.add_command(label='Сохранить',command=save_db)
filemenu.add_command(label='Сохранить как...',command=save_as_db)
filemenu.add_separator()
filemenu.add_command(label='Выход',command=exit)
mainmenu.add_cascade(label='Файл', menu=filemenu)
mainmenu.add_command(label='Справка')
#---------------------------------------1. Поля ввода основных полей Frame_1
frame_1 = Frame(main_win, relief=RIDGE, borderwidth=4) #область ввода начальных значений
frame_1.grid(row=10,column=0)
Label(frame_1, text='1. Основное параметры').grid(row=1,column=1,columnspan=10,sticky=W) #надпись в теле формы
Label(frame_1, text='Труба:').grid(row=2,column=1)
Label(frame_1, text='Километры:').grid(row=3,column=1)
Label(frame_1, text='Диаметр, мм:').grid(row=4,column=1)
data=('tube','km_start','km_finish','dy_tube')
data_tube={}
for i in data:
data_tube[i]=Entry(frame_1,width=20)
data_tube[data[0]]['width']=40
data_tube[data[0]].grid(row=2,column=2,columnspan=2)
data_tube[data[1]].grid(row=3,column=2)
data_tube[data[2]].grid(row=3,column=3)
data_tube[data[3]].grid(row=4,column=2)
#--------------------------------------2. Кнопка открытия окна дефектов Frame_2
frame_2 = Frame(main_win, relief=RIDGE, borderwidth=4)
frame_2.grid(row=20,column=0,sticky=EW,pady=5)
Label(frame_2, text='2. Форма дефектов').pack(side=LEFT)
Button(frame_2,text='Тыц', command=lambda:def_main.def_form(def_db)).pack(fill=X)
#--------------------------------------3. Раздел формирования актов входного контроля Frame_3
frame_3 = Frame(main_win,relief=RIDGE, borderwidth=4)
frame_3.grid(row=30,column=0,ipadx=5)
Label(frame_3, text='3. Входной контроль').grid(row=0,column=0)
lbox=Listbox(frame_3,height=15) #листбокс сдобавленными актами входного контроля
lbox.grid(row=1,column=0,columnspan=2,rowspan=10)
scroll=Scrollbar(frame_3,command=lbox.yview)
scroll.grid(row=1,column=2,rowspan=10,sticky=NS)
lbox.config(yscrollcommand=scroll.set) #активация заполениями уже забитых форм в поля по щелчку в листбоксе
#lbox.bind('<<ListboxSelect>>',update_lbox)
Button(frame_3,text='+',width=5,command=lambda:add_s(def_sec=def_ent_sec.get())).grid(row=0,column=4) #кнопка добавления акта входного контроля в листбокс
Button(frame_3,text='-',width=5,command=import_form_def).grid(row=0,column=5) #кнопка удаления акта входного контроля из листбокса
#--------------------------------------выпадающий список материалов в Frame_3
materials={'':('','','','')}
mat_txt=open(os.getcwd()+'\\db\\materials.txt' ) #каталог запуска программы
try:
for i in mat_txt:
materials[i[:-1].split('#')[0]]=tuple(i[:-1].split('#'))
finally:
mat_txt.close()
print(materials)
#--------------------------------------остальные поля в Frame_3
Label(frame_3, text='Материал').grid(row=1,column=4,columnspan=2)
Label(frame_3, text='Дата').grid(row=2,column=4,columnspan=2)
Label(frame_3, text='Документация').grid(row=3,column=4,columnspan=2)
Label(frame_3, text='Количество').grid(row=4,column=4,columnspan=2)
var_mat=StringVar(value='')
OptionMenu(frame_3,var_mat,*materials).grid(row=1,column=6)
date_vh=Entry(frame_3,width=20)
doc_vh=Entry(frame_3,width=20)
kol_vh=Entry(frame_3,width=20)
date_vh.grid(row=2,column=6)
doc_vh.grid(row=3,column=6)
kol_vh.grid(row=4,column=6)
main_win.mainloop()
''''if db_open_status:db.close()
if __name__=='__main__':
def_fields=['#','sec','dist','lab','dl','sh','gl','type'] #поля параметров дефектов frame05
def_shablon_d={} #шаблон на дефекты
def_db=[] #главный список, в качестве БД''' |
|
Кликните здесь для просмотра всего текста
| 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
231
232
233
234
235
236
237
238
239
240
241
242
243
| from datetime import *
import random,os
from tkinter import *
from tkinter.messagebox import showerror
def def_form(db_from_start): #основное окно
def add_s(def_sec): #Добавление дефектной секции (в db_from_start)
db_from_start.append({'sec':def_sec,
'date':[None,None,None],
'dist':[0,None,None,None,None],
'km':0,
'dl_muft':0,
'rand_value':[None,None,None,None],
'defect':{}
})
l_box.insert(END,'%d. %s'%(len(db_from_start),def_sec))
for i in range(len(db_from_start)):
db_from_start[i]['rand_value'][0]=random.uniform(0.25,0.6) #Добавление рандомных велечин для котлована и изоляции
db_from_start[i]['rand_value'][1]=random.uniform(2.5,4.5) #Добавление рандомных велечин для котлована и изоляции
db_from_start[i]['rand_value'][2]=random.uniform(2.6,3.2) #ширина котлована
db_from_start[i]['rand_value'][3]=random.uniform(2.6,3.0) #глубина котлована
def_ent_sec.delete(0,END) #очищает строку ввода номера секции после введения(+)
def del_s(): #Удаление секции с дефектом (из db_from_start)
del(db_from_start[l_box.curselection()[0]])
re_num_s()
def re_num_s(): #обновление нумерации секций в списке
l_box.delete(0,END) #очищение виджета l_box перед заполнением
for i,j in enumerate(db_from_start): #обновление нумерации
l_box.insert(END,'%s. %s'%(i,db_from_start[i]['sec']))
def update_lbox(a): #обновление информации в frame03 по щелчку в listbox
try:
temp=l_box.curselection()[0]
label01['text']='Номер секции: '+db_from_start[temp]['sec'] #заголовок frame03
except IndexError:pass
if db_from_start[temp]['date'][0]!=None: #Если новая запись, то остается значени предыдщей записи, если есть - присваивается
def_ent_date.delete(0,END)
def_ent_date.insert(0,db_from_start[temp]['date'][0].strftime('%d.%m.%Y'))
def_ent_km.delete(0,END)
def_ent_km.insert(0,db_from_start[temp]['km'])
def_ent_dist.delete(0,END)
def_ent_dist.insert(0,db_from_start[temp]['dist'][0])
def_ent_dl_muft.delete(0,END)
def_ent_dl_muft.insert(0,db_from_start[temp]['dl_muft'])
if 'otv' in db_from_start[temp]: #Если новая запись, то остается значени предыдщей записи, если есть - присваивается
var_otv.set(db_from_start[temp]['otv'][2])
print(var_otv.get())
if 'contr' in db_from_start[temp]: #Если новая запись, то остается значени предыдщей записи, если есть - присваивается
var_contr.set(db_from_start[temp]['contr'][2])
if 'sk' in db_from_start[temp]: #Если новая запись, то остается значени предыдщей записи, если есть - присваивается
var_sk.set(db_from_start[temp]['sk'][2])
load_lbox_2()
def save_s(): #сохранение во временной БД (db_from_start)
temp=l_box.curselection()[0]
if def_ent_date.get()!='':
try:
temp_date=list(int(i) for i in (def_ent_date.get().split('.'))) #интерпритация и запись даты
db_from_start[temp]['date'][0]=date(temp_date[2],temp_date[1],temp_date[0])#интерпритация и запись даты
db_from_start[temp]['date'][1]=db_from_start[temp]['date'][0]
for i in db_from_start[temp]['defect']:
if '1' in db_from_start[temp]['defect'][i]['type']: #флаг, муфта П1 или нет
db_from_start[temp]['date'][1]=db_from_start[temp]['date'][0]+dday
break
db_from_start[temp]['date'][2]=db_from_start[temp]['date'][1]+dday
except ValueError:showerror('Не сохранено!','Правильный формат:01.01.2019')
db_from_start[temp]['km']=def_ent_km.get() #запись километра
if def_ent_dist.get()!='':
try:
db_from_start[temp]['dist'][0]=float(def_ent_dist.get()) #запись дистанции
db_from_start[temp]['dist'][1]=round(db_from_start[temp]['dist'][0]-db_from_start[temp]['rand_value'][0],2) #начало изоляиии
db_from_start[temp]['dist'][2]=round(db_from_start[temp]['dist'][0]+db_from_start[temp]['rand_value'][0],2) #конец изоляции
db_from_start[temp]['dist'][3]=round(db_from_start[temp]['dist'][1]-db_from_start[temp]['rand_value'][1],2) #начало котлована
db_from_start[temp]['dist'][4]=round(db_from_start[temp]['dist'][2]+db_from_start[temp]['rand_value'][1],2) #конец котлована
except ValueError:showerror('Не сохранено!','Правильный формат:12345.64')
try:
db_from_start[temp]['dl_muft']=float(def_ent_dl_muft.get()) #запись длинны устанавливаемой муфты
except ValueError:showerror('Не сохранено!','Правильный формат:1.5')
db_from_start[temp]['otv']=all_otv[var_otv.get()] #запись людей
db_from_start[temp]['contr']=all_control[var_contr.get()] #запись людей
db_from_start[temp]['sk']=all_sk[var_sk.get()] #запись людей
print(db_from_start)
def up_s(): #переместить секцию вверх по списку lbox
temp=l_box.curselection()[0]
db_from_start.insert(temp-1,db_from_start.pop(temp))
re_num_s()
def down_s(): #переместить секцию вниз по списку lbox
temp=l_box.curselection()[0]
db_from_start.insert(temp+1,db_from_start.pop(temp))
re_num_s()
def add_d(): #Добавляет/обновляет дефекты в frame04
curent_s=l_box.curselection()[0]
if def_shablon_d['#'].get() not in db_from_start[curent_s]['defect']:
db_from_start[curent_s]['defect'][def_shablon_d['#'].get()]={}
l_box_2.insert(END,def_shablon_d['#'].get())
for field in def_fields[1:]:
db_from_start[curent_s]['defect'][def_shablon_d['#'].get()][field]=def_shablon_d[field].get()
for field in ('#','dist','dl','sh','gl'):
def_shablon_d[field].delete(0,END)
def del_d(): #удаляет дефекты в frame04
temp=l_box_2.curselection()
del(db_from_start[l_box.curselection()[0]]['defect'][l_box_2.get(temp)])
l_box_2.delete(temp)
def update_lbox_2(a): #обновление информации в frame04 по щелчку в listbox_2
print(a)
temp=l_box_2.get(l_box_2.curselection())
for field in def_fields:
def_shablon_d[field].delete(0,END)
if field=='#':
def_shablon_d[field].insert(0,temp)
else:
def_shablon_d[field].insert(0,db_from_start[l_box.curselection()[0]]['defect'][temp][field])
def load_lbox_2(): #внесение в listbox_2 списка дефектов из бд по щелчку в listbox(1)
l_box_2.delete(0,END)
for field in def_fields:
def_shablon_d[field].delete(0,END)
if db_from_start[l_box.curselection()[0]]['defect']!={}:
for i in db_from_start[l_box.curselection()[0]]['defect']:
l_box_2.insert(END,i)
all_otv={'':('','','')} #для выпадающего списка с ответственными + пустая запись(если отсутствует)
all_control={'':('','','')} #для выпадающего списка с контролирующими лицами + пустая запись(если отсутствует)
all_sk={'':('','','')} #для выпадающего списка с строительным контролем + пустая запись(если отсутствует)
dday=timedelta(days=1)
def_fields=['#','sec','dist','lab','dl','sh','gl','type'] #поля параметров дефектов frame05
def_shablon_d={} #шаблон на дефекты
#road_db=os.getcwd()+'\\db\\' #путь к папке db при запуске из Start
print(road_db)
for (i,j) in zip(('otv.txt','control.txt','sk.txt'),(all_otv,all_control,all_sk)): #Чтение ответственных из файлов с людьми
try:
f=open(road_db+i)
for x in f:
j[x[:-1].split('#')[2]]=x[:-1].split('#')
finally:
f.close()
#print(road_db)
#print(all_otv)
form_def=Tk()
form_def.title('Форма дефектов')
#form_def.geometry("780x600")
#------------------Меню дефектов
frame01_def = Frame(form_def, relief=RIDGE, borderwidth=2)
frame01_def.grid(row=0,column=0,columnspan=2,sticky=W)
Button(frame01_def,text='+',width=5,command=lambda:add_s(def_sec=def_ent_sec.get())).grid(row=0,column=0)
Button(frame01_def,text='-',width=5,command=del_s).grid(row=0,column=1)
Label(frame01_def, text='№ секции').grid(row=0,column=2)
def_ent_sec=Entry(frame01_def,width=20)
def_ent_sec.grid(row=0,column=3)
frame02_def = Frame(form_def, relief=RIDGE, borderwidth=2)
frame02_def.grid(row=1,column=0,sticky=NW,rowspan=2)
l_box=Listbox(frame02_def,height=25,exportselection=0)
l_box.grid(row=0,column=0,columnspan=2)
scroll_1=Scrollbar(frame02_def,command=l_box.yview)
scroll_1.grid(row=0,column=2,sticky=NS)
l_box.config(yscrollcommand=scroll_1.set)
l_box.bind('<<ListboxSelect>>',update_lbox)
Button(frame02_def,text='вверх',width=5,command=up_s).grid(row=1,column=0,sticky=EW)
Button(frame02_def,text='вниз',width=5,command=down_s).grid(row=1,column=1,sticky=EW)
#!!!-----------------!Frame03!
frame03_def=Frame(form_def,relief=RIDGE, borderwidth=3)
frame03_def.grid(row=1,column=1,sticky=NW,ipadx=5,columnspan=2)
label01=Label(frame03_def, text='Номер секции:')
label01.grid(row=20,column=0,columnspan=2,sticky=W)
#------------------Дата дефекта в Frame03
Label(frame03_def, text='Дата:').grid(row=30,column=0)
def_ent_date=Entry(frame03_def,width=20)
def_ent_date.grid(row=30,column=1)
#------------------Километр дефекта в Frame03
Label(frame03_def, text='Км:').grid(row=35,column=0)
def_ent_km=Entry(frame03_def,width=20)
def_ent_km.grid(row=35,column=1)
#------------------Дистанция главного дефекта в Frame03
Label(frame03_def, text='Дистанция:').grid(row=36,column=0)
def_ent_dist=Entry(frame03_def,width=20)
def_ent_dist.grid(row=36,column=1)
#------------------Дистанция главного дефекта в Frame03
Label(frame03_def, text='Длинна муфты:').grid(row=37,column=0)
def_ent_dl_muft=Entry(frame03_def,width=20)
def_ent_dl_muft.grid(row=37,column=1)
#------------------Меню ответственных по работам в Frame03
Label(frame03_def, text='Производитель работ:').grid(row=50,column=0)
Label(frame03_def, text='Контролирующее лицо:').grid(row=60,column=0)
Label(frame03_def, text='СК:').grid(row=70,column=0)
var_otv=StringVar(value='')
#variable_otv.set('')
var_contr=StringVar(value='')
var_sk=StringVar(value='')
OptionMenu(frame03_def,var_otv,*all_otv).grid(row=50,column=1)
OptionMenu(frame03_def,var_contr,*all_control).grid(row=60,column=1)
OptionMenu(frame03_def,var_sk,*all_sk).grid(row=70,column=1)
Button(frame03_def,text='Сохранить',command=save_s).grid(row=200,column=0)
#!!!-----------------!Frame04!
frame04_def=Frame(form_def,relief=RIDGE, borderwidth=3)
frame04_def.grid(row=2,column=1,sticky=NW)
#--------------------Лист бокс дефектов секции
l_box_2=Listbox(frame04_def,height=12)
l_box_2.pack(side=LEFT)
scroll_2=Scrollbar(frame04_def,command=l_box_2.yview)
scroll_2.pack(side=LEFT,fill=Y)
l_box_2.config(yscrollcommand=scroll_2.set)
l_box_2.bind('<<ListboxSelect>>',update_lbox_2)
#!!!-----------------!Frame05!
frame05_def=Frame(form_def,relief=RIDGE, borderwidth=3)
frame05_def.grid(row=2,column=2,sticky=NW,ipadx=30,ipady=7)
#------------------Параметры конкретного дефекта в Frame05
Button(frame05_def,text='+',width=5,command=add_d).grid(row=0,column=0)
Button(frame05_def,text='-',width=5,command=del_d).grid(row=0,column=1)
Label(frame05_def, text='Номер дефекта:').grid(row=10,column=0,columnspan=2)
Label(frame05_def, text='Номер секции:').grid(row=20,column=0,columnspan=2)
Label(frame05_def, text='Дистанция:').grid(row=30,column=0,columnspan=2)
Label(frame05_def, text='Описание дефекта:').grid(row=40,column=0,columnspan=2)
Label(frame05_def, text='Длинна:').grid(row=50,column=0,columnspan=2)
Label(frame05_def, text='Ширина:').grid(row=60,column=0,columnspan=2)
Label(frame05_def, text='Глубина:').grid(row=70,column=0,columnspan=2)
Label(frame05_def, text='Метод устранения:').grid(row=80,column=0,columnspan=2)
j=10
for i in def_fields:
def_shablon_d[i]=Entry(frame05_def,width=30)
def_shablon_d[i].grid(row=j,column=3)
j+=10
form_def.mainloop()
if __name__=='__main__':
road_db=os.getcwd()[:-5]+'db\\' #путь к папке db
db_from_start=[] #главный список, в качестве БД
def_form(db_from_start)
else:
road_db=os.getcwd()+'\\db\\' |
|
0
|