Я написал программу, которая обеспечивает создание и перемещение объектов по экрану (планировщик помещения). Каждый объект активируется для движения нажатием левой кнопки мыши на него. Есть несколько проблем. После активации объекта двигаться начинает не он, а объект, созданный перед ним (имеющий порядковый номер, который я сделал тегом, на единицу меньше), а если сохранить положение фигур и снова открыть файл, то смещение произведенное предметом с меньшим тегом, будет отображено как смещение предмета, который я и активировал. Есть еще проблема с функцией изменения положения объекта в пространстве (с горизонтального в вертикальное и обратно), в данном случае виджет может как не двигаться, так и совершить одно действие и прекратить в принципе реагировать на команды, при этом перестают реагировать все виджеты. Код указан ниже. В чем здесь проблема?
from tkinter import *
import tkinter.ttk as ttk
from time import sleep
from tkinter.filedialog import *
import fileinput
from tkinter.messagebox import *
import os
import sqlite3
#список с параметрами виджетов
spisok_widget=[]
#имя файла для автоматического сохранения
name_save=''
tag=0
zvet='white'
figura='прямоугольник'
#открытие базы данных с сохраненными параметрами объектов
def _open():
okno_sozd=Tk()
okno_sozd.title('')
okno_sozd.geometry('+0+0')
l = Listbox(okno_sozd,height=9,width=33)
scroll=Scrollbar(okno_sozd, command=l.yview)
l.configure(yscrollcommand=scroll.set)
l.grid(row=0,column=0)
scroll.grid(row=0,column=1)
for i in os.listdir():
if i[len(i)-2:len(i)]=='db':
l.insert(END, i)
def zakritie(event):
okno_sozd.destroy()
def obnovlen(event):
index=l.curselection()
dannie_widget=l.get(index)
okno_sozd.destroy()
#определяем имя файла для автоматического сохранения
global name_save
name_save=dannie_widget
con=sqlite3.connect(dannie_widget)
cur=con.cursor()
cur.execute('SELECT*FROM perechen')
b=cur.fetchall()
con.commit()
cur.close()
con.close()
global spisok_widget
for elem in b:
spisok_widget.append(list(elem))
if elem[6]=='прямоугольник':
widget=c.create_rectangle(elem[1],elem[2],elem[1]+elem[3],
elem[2]+elem[4],fill=elem[5],outline='black',tag=elem[0])
if elem[6]=='овал':
widget=c.create_oval(elem[1],elem[2],elem[1]+elem[3],
elem[2]+elem[4],fill=elem[5],outline='black',tag=elem[0])
c.tag_bind(widget,'<Button-1>',identifikacia)
ramka=Frame(okno_sozd)
ramka.grid(row=1,column=0)
knopka_da=Button(ramka,text='Открыть')
knopka_net=Button(ramka,text='Отменить')
knopka_da.pack(side=LEFT)
knopka_net.pack(side=RIGHT)
knopka_da.bind('<Button-1>',obnovlen)
knopka_net.bind('<Button-1>',zakritie)
#сохранение параметров объектов в создаваемом файле
def _save_kak():
okno_sozd=Tk()
okno_sozd.title('')
okno_sozd.geometry('+0+0')
#okno_sozd.overrideredirect(1)
vvod_text=Label(okno_sozd,text='Введите наименование файла')
st=StringVar()
pole=Entry(okno_sozd,textvariable=st)
ramka=Frame(okno_sozd)
vvod_text.pack()
pole.pack()
ramka.pack()
knopka_da=Button(ramka,text='Сохранить')
knopka_net=Button(ramka,text='Отменить')
knopka_da.pack(side=LEFT)
knopka_net.pack(side=RIGHT)
def zakritie(event):
okno_sozd.destroy()
def obnovlen(event):
name=pole.get()+'.db'
#определяем имя файла для автоматического сохранения
global name_save
name_save=name
okno_sozd.destroy()
con = sqlite3.connect(name)
cur = con.cursor()
sql='''CREATE TABLE perechen(tag INTEGER PRIMARY KEY AUTOINCREMENT,
x INTEGER, y INTEGER, razmer1 INTEGER,razmer2 INTEGER,zvet TEXT,figura TEXT)'''
cur.executescript(sql)
cur.close()
con.close()
con=sqlite3.connect(name)
cur=con.cursor()
global spisok_widget
for elem in spisok_widget:
a=tuple(elem)
sql_a='INSERT INTO perechen VALUES(?,?,?,?,?,?,?)'
cur.execute(sql_a,a)
con.commit()
cur.close()
con.close()
knopka_da.bind('<Button-1>',obnovlen)
knopka_net.bind('<Button-1>',zakritie)
#сохранение параметров объектов в последний используемый файл
def _save():
if name_save!='':
con=sqlite3.connect(name_save)
cur=con.cursor()
cur.execute('SELECT*FROM perechen')
b=cur.fetchall()
global spisok_widget
for elem in spisok_widget:
a=tuple(elem)
n=0
for elem in b:
if a[0]==elem[0]:
n=1
if n!=1:
sql_a='INSERT INTO perechen VALUES(?,?,?,?,?,?,?)'
cur.execute(sql_a,a)
elif n==1:
cur.execute('UPDATE perechen SET x=? WHERE tag=?',\
(a[1],a[0]))
cur.execute('UPDATE perechen SET y=? WHERE tag=?',\
(a[2],a[0]))
cur.execute('UPDATE perechen SET razmer1=? WHERE tag=?',\
(a[3],a[0]))
cur.execute('UPDATE perechen SET razmer2=? WHERE tag=?',\
(a[4],a[0]))
cur.execute('UPDATE perechen SET zvet=? WHERE tag=?',\
(a[5],a[0]))
cur.execute('UPDATE perechen SET figura=? WHERE tag=?',\
(a[6],a[0]))
con.commit()
cur.close()
con.close()
#создание функций меню
def close_win ():
#def quit():
if askyesno("Выход", "Желаете выйти"):
root.destroy()
def new_proekt():
if askyesno("Новый проект", "Желаете создать новый проект"):
root.destroy()
def about():
showinfo("О программе", '''Программа предоставляет возможность
спроектировать расстановку различных предметов(в том числе мебели)
в помещении''')
#создание окна, холста, меню, виджетов для ввода информации
root=Tk()
root.title('Планировка помещения')
m = Menu(root)
root.config(menu=m)
fm = Menu(m)
m.add_cascade(label="Меню",menu=fm)
fm.add_command(label="Открыть",command=_open)
fm.add_command(label="Сохранить",command=_save)
fm.add_command(label="Сохранить как...",command=_save_kak)
fm.add_command(label="Новый проект",command=new_proekt)
fm.add_command(label="Выход",command=close_win)
hm = Menu(m)
m.add_cascade(label="Помощь",menu=hm)
hm.add_command(label="О программе",command=about)
#масштаб 1 пиксель - 1 см
c = Canvas(width=1000,height=700,bg='white')
ramka=Frame(root,width=200,height=700)
c.pack(side=LEFT)
ramka.pack(side=RIGHT)
c.focus_set()
nadp_predmet=Label(ramka,text='Выбор объекта')
nadp_predmet.pack()
spisok_predmet=ttk.Combobox(ramka,height=5,values=['комната','окно','дверь',
'мебель','другой предмет'])
forma_predmet=ttk.Combobox(ramka,height=2,values=['прямоугольник','овал'])
spisok_predmet.pack()
forma_predmet.pack()
spisok_predmet.set('комната')
forma_predmet.set('прямоугольник')
nadp_predmet=Label(ramka,text='Размеры объекта')
nadp_predmet.pack()
ramka_razmer=Frame(ramka)
ramka_razmer.pack()
dk=IntVar()
razmer1_komnata=Entry(ramka_razmer,width=4,textvariable=dk)
nadp_razmer1=Label(ramka_razmer,text='см',width=2)
sk=IntVar()
razmer2_komnata=Entry(ramka_razmer,width=4,textvariable=sk)
nadp_razmer2=Label(ramka_razmer,text='см',width=2)
knopka_vvoda=Button(ramka,text='Ввод данных')
knopka_vvoda.pack()
razmer1_komnata.grid(row=0,column=0)
nadp_razmer1.grid(row=0,column=1)
razmer2_komnata.grid(row=0,column=2)
nadp_razmer2.grid(row=0,column=3)
def obnovl_predmet(e=None):
global tag
global zvet
global figura
global spisok_widget
predmet=spisok_predmet.get()
figura=forma_predmet.get()
if predmet=='комната':
tag=0;zvet='white'
else:
tag=spisok_widget[-1][0]+1
if predmet=='окно':
zvet='gray80'
elif predmet=='дверь' or predmet=='другой предмет':
zvet='black'
elif predmet=='мебель':
zvet='gray'
spisok_predmet.bind('<<ComboboxSelected>>', obnovl_predmet)
forma_predmet.bind('<<ComboboxSelected>>', obnovl_predmet)
#создание объектов
x=20
y=20
def dannie_komnata(event):
global tag
global zvet
global figura
global spisok_widget
razmer1=float(razmer1_komnata.get())
razmer2=float(razmer2_komnata.get())
if figura=='прямоугольник':
widget_komnata=c.create_rectangle(x,y,x+razmer1,y+razmer2,
fill=zvet,outline='black',tag=tag)
elif figura=='овал':
widget_komnata=c.create_oval(x,y,x+razmer1,y+razmer2,
fill=zvet,outline='black',tag=tag)
elem_spisok_widget=[tag,x,y,razmer1,razmer2,zvet,figura]
spisok_widget.append(elem_spisok_widget)
c.tag_bind(widget_komnata,'<Button-1>',identifikacia)
knopka_vvoda.bind('<Button-1>',dannie_komnata)
#создание функций движения объектов
def sdvig_vverch(event):
global tag
global spisok_widget
c.move(tag,0,-2)
for elem in spisok_widget:
if elem[0]==tag:
elem[2]=elem[2]-2
c.update()
sleep(0.02)
def sdvig_vniz(event):
global tag
global spisok_widget
c.move(tag,0,2)
for elem in spisok_widget:
if elem[0]==tag:
elem[2]=elem[2]+2
c.update()
sleep(0.02)
def sdvig_vpravo(event):
global tag
global spisok_widget
c.move(tag,2,0)
for elem in spisok_widget:
if elem[0]==tag:
elem[1]=elem[1]+2
c.update()
sleep(0.02)
def sdvig_vlevo(event):
global tag
global spisok_widget
c.move(tag,-2,0)
for elem in spisok_widget:
if elem[0]==tag:
elem[1]=elem[1]-2
c.update()
sleep(0.02)
#функция изменения положения фигуры с горизонтального в вертикальное и обратно
def izmen_polozhenie(event):
global tag
global spisok_widget
c.delete(tag)
for elem in spisok_widget:
if elem[0]==tag:
elem[3],elem[4]=elem[4],elem[3]
if elem[6]=='прямоугольник':
widget=c.create_rectangle(elem[1],elem[2],elem[1]+elem[3],
elem[2]+elem[4],fill=elem[5],outline='black',tag=elem[0])
elif elem[6]=='овал':
widget=c.create_oval(elem[1],elem[2],elem[1]+elem[3],
elem[2]+elem[4],fill=elem[5],outline='black',tag=elem[0])
#идентификация виджета по тегу
def identifikacia(event):
c.focus_set()
global tag
item=c.find_closest(event.x,event.y)
tag=int(c.gettags(item)[0])
c.bind('<Up>',sdvig_vverch)
c.bind('<Down>',sdvig_vniz)
c.bind('<Right>',sdvig_vpravo)
c.bind('<Left>',sdvig_vlevo)
c.bind('s',izmen_polozhenie)
root.mainloop()