Найти - Пользователи
Полная версия: Проблема с идентификацией тега в Canvas tkinter
Начало » Python для новичков » Проблема с идентификацией тега в Canvas tkinter
1
Konstantin1984+
Я пишу программу “менеджер папок”. Виджеты папок и файлов отображаются в 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()

FishHook
Konstantin1984+
Давно не попадалось столь хорошего кода, вы молодец
Konstantin1984+
Спасибо! А ответ на мой вопрос у Вас есть?
PEHDOM
Konstantin1984+
Спасибо! А ответ на мой вопрос у Вас есть?
Ага, есть, нужно документацию читать:
http://www.effbot.org/tkinterbook/canvas.htm
там ведь английскими буквами по белому написано:
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)
вот и получаете , что полотно у вас сместилось, а координаты у вас непойми какие(относительно окна), вот оно и берет с за item непойми что..
Konstantin1984+
Спасибо! Заработало, честно говоря подобный код я уже видел, но мне казалось, что он, по сути, идентичен моему.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB