Форум сайта python.su
Я пишу программу “менеджер папок”. Виджеты папок и файлов отображаются в Canvas, в окне используется скроллинг. Папка открывается при нажатии на нее левой клавишей мыши или через меню, появляющееся при нажатии правой кнопки мыши. При нажатии на виджет левой или правой кнопкой мыши должен определяться тег, который является наименованием папки. Но проблема в том, что данная функция работает только на первых виджетах, попадающих в первоначальные рамки Canvas. Нажатие на виджеты, появляющиеся при скроллинге, тег не идентифицирует, в качестве наименования папки выводится или часть наименования предыдущей папки или пустота. В чем тут проблема?
Работаю в Ubuntu 16.04. Код указан ниже.
from tkinter import * import os from os import path import shutil from PIL import ImageTk,Image root=Tk() root.geometry('+100+100') put='/home/konstantin/Рабочий стол' spisok_puti=put.split('/') root.title('{0} ({1})'.format(spisok_puti[-1],put)) #создание новой папки, вставка скопированной папки def new_papka(event): #определяем координаты курсора на экране x = root.winfo_pointerx() y = root.winfo_pointery() item=canvas.find_closest(event.x,event.y) naimenovanie_kortezh=canvas.gettags(item) naimenovanie=' '.join(naimenovanie_kortezh[:-1]) print(naimenovanie) print('В папке') zapusk=True for elem in spisok_elem: if naimenovanie==elem: zapusk=False if zapusk: okno_pravka=Toplevel(root) okno_pravka.geometry('+{}+{}'.format(x,y)) okno_pravka.overrideredirect(1) okno_pravka.title('') knopka_sozdanie=Button(okno_pravka,text='Создать',height=1,width=10) knopka_vstavka=Button(okno_pravka,text='Вставить',height=1,width=10) knopka_otmena=Button(okno_pravka,text='Отменить',height=1,width=10,fg='red') knopka_sozdanie.pack() knopka_vstavka.pack() knopka_otmena.pack() def sozd(event): okno_pravka.destroy() okno_sozd=Tk() okno_sozd.title('') okno_sozd.geometry('+{}+{}'.format(x,y+50)) #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): naimenovanie_new=pole.get() okno_sozd.destroy() os.mkdir(naimenovanie_new) canvas.destroy() papka() knopka_da.bind('<Button-1>',obnovlen) knopka_net.bind('<Button-1>',zakritie) def vstavka(event): okno_pravka.destroy() global put_kopir global put_delete if tip=='Папка': os.mkdir(bufer) elif tip=='Файл' and put_kopir!='': shutil.copy2('{0}/{1}'.format(put_kopir,bufer),bufer) if put_delete!='': if tip=='Папка': os.rmdir('{0}/{1}'.format(put_delete,bufer)) elif tip=='Файл': shutil.move('{0}/{1}'.format(put_delete,bufer),bufer) canvas.destroy() papka() put_delete='' def zakritie(event): okno_pravka.destroy() knopka_sozdanie.bind('<Button-1>',sozd) knopka_vstavka.bind('<Button-1>',vstavka) knopka_otmena.bind('<Button-1>',zakritie) #открытие папки левой клавишей мыши def open_papka(event): item=canvas.find_closest(event.x,event.y) naimenovanie_kortezh=canvas.gettags(item) naimenovanie=' '.join(naimenovanie_kortezh[:-1]) print(item) print(naimenovanie) a=os.path.isdir(naimenovanie) b=os.path.isfile(naimenovanie) print(a,b) global put global spisok_puti if a: put=put+'/'+naimenovanie spisok_puti=put.split('/') root.title('{0} ({1})'.format(spisok_puti[-1],put)) canvas.destroy() papka() #выход из папки def vichod_iz_papki(event): global put global spisok_puti if spisok_puti[-1]!='home': spisok_puti=spisok_puti[:-1] put='/'.join(spisok_puti) root.title('{0} ({1})'.format(spisok_puti[-1],put)) canvas.destroy() papka() #появление меню с перечнем возможных действий def identifikacia(event): #определяем координаты курсора на экране x = root.winfo_pointerx() y = root.winfo_pointery() #abs_coord_x = root.winfo_pointerx() - root.winfo_rootx() #abs_coord_y = root.winfo_pointery() - root.winfo_rooty() item=canvas.find_closest(event.x,event.y) naimenovanie_kortezh=canvas.gettags(item) naimenovanie=' '.join(naimenovanie_kortezh[:-1]) print(naimenovanie) a=os.path.isdir(naimenovanie) b=os.path.isfile(naimenovanie) okno_pravka=Toplevel(root) okno_pravka.geometry('+{}+{}'.format(x,y)) okno_pravka.overrideredirect(1) okno_pravka.title('') knopka_open=Button(okno_pravka,text='Открыть',height=1,width=10) knopka_virez=Button(okno_pravka,text='Вырезать',height=1,width=10) knopka_kopir=Button(okno_pravka,text='Копировать',height=1,width=10) knopka_delete=Button(okno_pravka,text='Удалить',height=1,width=10) knopka_pereimenov=Button(okno_pravka,text='Переименовать',height=1,width=10) knopka_otmena=Button(okno_pravka,text='Отменить',height=1,width=10,fg='red') knopka_open.pack() knopka_virez.pack() knopka_kopir.pack() knopka_delete.pack() knopka_pereimenov.pack() knopka_otmena.pack() def otkritie(event): okno_pravka.destroy() global put global spisok_puti if a: put=put+'/'+naimenovanie spisok_puti=put.split('/') root.title('{0} ({1})'.format(spisok_puti[-1],put)) canvas.destroy() papka() def virez(event): okno_pravka.destroy() global bufer global put_delete global tip global put_kopir put_kopir='' put_delete=put bufer=naimenovanie if a: tip='Папка' if b: tip='Файл' def kopir(event): okno_pravka.destroy() global bufer global put_delete global tip global put_kopir put_kopir=put put_delete='' bufer=naimenovanie if a: tip='Папка' if b: tip='Файл' def zakritie(event): okno_pravka.destroy() def new_name(event): okno_pravka.destroy() okno_name=Tk() okno_name.title('') okno_name.geometry('+{}+{}'.format(x,y+50)) #okno_name.overrideredirect(1) if a: vvod_text=Label(okno_name,text='Введите новое наименование папки') elif b: vvod_text=Label(okno_name,text='Введите новое наименование файла') st=StringVar() pole=Entry(okno_name,textvariable=st) ramka=Frame(okno_name) 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_name.destroy() def obnovlen(event): naimenovanie_new=pole.get() okno_name.destroy() os.rename(naimenovanie,naimenovanie_new) canvas.destroy() papka() knopka_da.bind('<Button-1>',obnovlen) knopka_net.bind('<Button-1>',zakritie) def udalenie(event): okno_pravka.destroy() okno_name=Tk() okno_name.title('') okno_name.geometry('+{}+{}'.format(x,y+50)) #okno_name.overrideredirect(1) if a: vvod_text=Label(okno_name,text='Удалить папку?') if b: vvod_text=Label(okno_name,text='Удалить файл?') ramka=Frame(okno_name) vvod_text.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_name.destroy() def obnovlen(event): okno_name.destroy() if a: os.rmdir(naimenovanie) canvas.destroy() papka() if b: os.remove(naimenovanie) canvas.destroy() papka() knopka_da.bind('<Button-1>',obnovlen) knopka_net.bind('<Button-1>',zakritie) def oznakomlen(event): okno_pravka.destroy() knopka_open.bind('<Button-1>',otkritie) knopka_virez.bind('<Button-1>',virez) knopka_kopir.bind('<Button-1>',kopir) knopka_delete.bind('<Button-1>',udalenie) knopka_pereimenov.bind('<Button-1>',new_name) knopka_otmena.bind('<Button-1>',zakritie) #загрузка изображений папки и файла pilImage = Image.open('Папка.png') image1 = ImageTk.PhotoImage(pilImage) pilImage = Image.open('Файл.png') image2 = ImageTk.PhotoImage(pilImage) #создание кнопки для выхода из папки ramka_kn=Frame(root,bg='gray') stroka=Label(root,text='') ramka_kn.grid(row=0,column=0) stroka.grid(row=1,column=0) knopka_nazad=Button(ramka_kn,text='<',font='Roman 14',bg='gray') nadpis=Label(ramka_kn,text='Возврат в предыдущую папку',anchor="w", justify=CENTER,bg='gray') knopka_nazad.grid(row=0,column=0) nadpis.grid(row=0,column=1) knopka_nazad.bind('<Button-1>',vichod_iz_papki) #отображение холста и элементов на нем def papka(): global canvas canvas = Canvas(root,width=500,height=500) #canvas.minsize(width=500,height=500) scr = Scrollbar(root,command=canvas.yview) canvas.configure(yscrollcommand=scr.set) canvas.grid(row=2,column=0) scr.grid(row=2,column=1) os.chdir(put) global spisok_elem spisok_elem=os.listdir() x=40;y=40 for elem in spisok_elem: a=os.path.isdir(elem) b=os.path.isfile(elem) if a: image=image1 if b: image=image2 if len(elem)>10: text_nadp='' for n in range(len(elem)//10): text_nadp=text_nadp+'\n'+elem[n*10:(n+1)*10] text_nadp=text_nadp+'\n'+elem[(n+1)*10:len(elem)] elif len(elem)<=10: text_nadp=elem kartinka=canvas.create_image(x,y,image=image,tag=elem) nadp=canvas.create_text(x-35,y+80,text=text_nadp,anchor="w", font='Roman 8',justify=CENTER, fill='black',tag=elem) canvas.tag_bind(kartinka,'<Button-3>',identifikacia) canvas.tag_bind(nadp,'<Button-3>',identifikacia) canvas.tag_bind(kartinka,'<Button-1>',open_papka) x=x+100 if x>500: x=40 y=y+160 canvas.bind('<Button-3>',new_papka) papka() root.mainloop()
Офлайн
Konstantin1984+
Давно не попадалось столь хорошего кода, вы молодец
Офлайн
Спасибо! А ответ на мой вопрос у Вас есть?
Офлайн
Konstantin1984+Ага, есть, нужно документацию читать:
Спасибо! А ответ на мой вопрос у Вас есть?
find_closest(x, y, halo=None, start=None)а вы что ему скармливаете?
Returns the item closest to the given position. Note that the position is given in canvas coordinates…
….
To convert from window coordinates to canvas coordinates, use the canvasx and canvasy methods:
def callback(event):
canvas = event.widget
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)
print canvas.find_closest(x, y)
item=canvas.find_closest(event.x,event.y)
[code python][/code]
Отредактировано PEHDOM (Май 14, 2020 20:57:07)
Офлайн
Спасибо! Заработало, честно говоря подобный код я уже видел, но мне казалось, что он, по сути, идентичен моему.
Офлайн