简体   繁体   中英

Tkinter Canvas create_window positioning issue

I was trying to do a resizable scrollable canvas frame on tkinter. And the problem comes with the first iteration. I build a window and a canvas with an event binding to "<Configure>" to expand its size to the size of the window. I create a Frame and I use create_window to put it into the canvas, but for some reason, the parameters of the method don't work correctly or I don't know how it works.

I give it a size of 200 x 200 with the height and width parameters and the frame displays as it have 100x100. This is because the frame isn't displayed at x=0,y=0, it's displayed under this. And I have specified its position to 0,0.

I don't now why I am having this problem but it drives me crazy, I left my code here if someone can help me.

import sys
from tkinter import *
import tkinter as tk

#Function that initialise the main window
mainwindow = tk.Tk()
mainwindow.resizable(1,1)
mainwindow.title('Resizable Icons')
mainwindoww = 800
mainwindowh = 900
mainwindowws = mainwindow.winfo_screenwidth()
mainwindowhs = mainwindow.winfo_screenheight()
x = (mainwindowws/2) - (mainwindoww/2)
y = (mainwindowhs/2) - (mainwindowh/2)
mainwindow.geometry('%dx%d+%d+%d' % (mainwindoww, mainwindowh, x, y))
mainwindow.minsize(320,600)
frame = Frame(mainwindow,bg='white',width=mainwindoww,height=mainwindowh)
frame.pack()

label1 = Label(frame,text='Resize Proof')
label1.place(x=0,y=20,width=mainwindow.winfo_width())

label2 = Label(frame,text='This is a proof of a resizable elements inside a canvas.') 
label2.place(x=0,y=50,width=mainwindow.winfo_width())

iconframe = Canvas(mainwindow,bg='red', bd=0, highlightthickness=0, relief=FLAT)
iconframe.place(x=0,y=100,width=mainwindoww,height=mainwindowh-140)

iconframe.config(scrollregion=(0,0,320,1000))

'''

sbar = tk.Scrollbar(iconframe,orient='vertical')
sbar.config(command=iconframe.yview)
iconframe.config(yscrollcommand=sbar.set)
sbar.pack(side=RIGHT, fill=Y)

'''


element1 = Frame(iconframe,bg='green')
e1 = iconframe.create_window(0,0,window=(element1))

iconframe.itemconfig(e1,width=200,height=200)


def resizeevent(event):
    width=mainwindow.winfo_width()
    height=mainwindow.winfo_height()
    frame.configure(width=width,height=height)
    iconframe.place_configure(width=width)
    label1.place_configure(width=width)
    label2.place_configure(width=width)

mainwindow.bind("<Configure>",resizeevent)

mainwindow.mainloop()

I have found a way to make my responsive scrollable frame with canvas without positioning issues.

I took the code from this git page of a vertical scrolled frame. So, thanks to Eugene Bakin for do this. https://gist.github.com/EugeneBakin/76c8f9bcec5b390e45df .

So modify a little bit this snippet to adapt to my necessities.

Here's the code that works of my Scrollable Resizable Tkinter Frame.

class VerticalScrolledFrame(Frame):
    """A pure Tkinter scrollable frame that actually works!
    * Use the 'interior' attribute to place widgets inside the scrollable frame
    * Construct and pack/place/grid normally
    * This frame only allows vertical scrolling

    """
    def __init__(self, parent, bg, *args, **kw):
        Frame.__init__(self, parent, *args, **kw)            

        # create a canvas object and a vertical scrollbar for scrolling it
        vscrollbar = Scrollbar(self, orient=VERTICAL)
        vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
        canvas = Canvas(self, bd=0, highlightthickness=0,
                    yscrollcommand=vscrollbar.set,bg=bg)
        canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
        vscrollbar.config(command=canvas.yview)

        # reset the view
        canvas.xview_moveto(0)
        canvas.yview_moveto(0)

        # create a frame inside the canvas which will be scrolled with it
        self.interior = interior = Frame(canvas,bg=bg)
        interior_id = canvas.create_window(0, 0, window=interior,
                                       anchor=NW)


        #This would create a frame that had actually the size of the whole window height
        #I have tested so much with options and haven't found a way to make it work correctly without this
        a = Frame(self.interior,height=10,bg='white')
        a.pack()

        # track changes to the canvas and frame width and sync them,
        # also updating the scrollbar
        def _configure_interior(event):
            # update the scrollbars to match the size of the inner frame
            size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
            canvas.config(scrollregion="0 0 %s %s" % size)
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the canvas's width to fit the inner frame
                canvas.config(width=interior.winfo_reqwidth())
        interior.bind('<Configure>', _configure_interior)

        def _configure_canvas(event):
            #With this piece of code, the "a" frame adapts its height to the elements inside. 
            a.configure(height=10)
            a.update()
            mylist = interior.winfo_children()
            for i in mylist:
                lasty=i.winfo_height()+i.winfo_y()
            a.configure(height=lasty)
            if interior.winfo_reqwidth() != canvas.winfo_width():
                # update the inner frame's width to fill the canvas
                canvas.itemconfigure(interior_id, width=canvas.winfo_width())
        canvas.bind('<Configure>', _configure_canvas)

#Function that initialise the main window
mainwindow = tk.Tk()
mainwindow.resizable(1,1)
mainwindow.title('Resizable Icons')
mainwindoww = 800
mainwindowh = 900
mainwindowws = mainwindow.winfo_screenwidth()
mainwindowhs = mainwindow.winfo_screenheight()
x = (mainwindowws/2) - (mainwindoww/2)
y = (mainwindowhs/2) - (mainwindowh/2)
mainwindow.geometry('%dx%d+%d+%d' % (mainwindoww, mainwindowh, x, y))
mainwindow.minsize(320,600)
style = ThemedStyle(mainwindow)
style.set_theme("radiance")
if getDarkModeState() == 0:
    mainwindow.configure(background='#000000')
else:
    mainwindow.configure(background='#ffffff')

frame = Frame(mainwindow,bg='white',width=mainwindoww,height=mainwindowh)
frame.pack()

label1 = Label(frame,text='Main Title',font=titlelightfont)
label1.place(x=0,y=20,width=mainwindow.winfo_width())

label2 = Label(frame,text='Title description',font=mainfont) 
label2.place(x=0,y=50,width=mainwindow.winfo_width())

iconframe = VerticalScrolledFrame(mainwindow,bg='white')
iconframe.place(x=0,y=100,width=mainwindoww,height=660)



#I made every single element different from another, with an icon, title and description
#The icon should be 60x60 to fit correctly into the frame
element1 = Frame(iconframe.interior,bg='white')
element1.place(relx=0.025,y=10,height=100,relwidth=0.30)
icon1image = PhotoImage(file='mainicons/user60.png')
icon1 = Label(element1,bg='white',image=icon1image)
icon1.place(x=10,width=60,height=60,y=10)
eltitle1 = Label(element1,bg='white',font=mainfont,text='First option')
eltitle1.place(x=75,y=10)
eldesc1 = Label(element1,bg='white',font=subdescfont,text='This is the first description of the element.',wraplength=155,justify=LEFT)
eldesc1.place(x=75,y=40)

element2 = Frame(iconframe.interior,bg='white')
element2.place(relx=0.350,y=10,height=100,relwidth=0.30)
icon2image = PhotoImage(file='mainicons/testglobal60.png')
icon2 = Label(element2,bg='white',image=icon2image)
icon2.place(x=10,width=60,height=60,y=10)
eltitle2 = Label(element2,bg='white',font=mainfont,text='Second option')
eltitle2.place(x=75,y=10)
eldesc2 = Label(element2,bg='white',font=subdescfont,text='This is the second description of the element.',wraplength=155,justify=LEFT)
eldesc2.place(x=75,y=40)

element3 = Frame(iconframe.interior,bg='white')
element3.place(relx=0.675,y=10,height=100,relwidth=0.30)
icon3image = PhotoImage(file='mainicons/label60.png')
icon3 = Label(element3,bg='white',image=icon3image)
icon3.place(x=10,width=60,height=60,y=10)
eltitle3 = Label(element3,bg='white',font=mainfont,text='Third option')
eltitle3.place(x=75,y=10)
eldesc3 = Label(element3,bg='white',font=subdescfont,text='This is the third description of the element.',wraplength=155,justify=LEFT)
eldesc3.place(x=75,y=40)

element4 = Frame(iconframe.interior,bg='white')
element4.place(relx=0.025,y=120,height=100,relwidth=0.30) 
icon4image = PhotoImage(file='mainicons/testind60.png')
icon4 = Label(element4,bg='white',image=icon4image)
icon4.place(x=10,width=60,height=60,y=10)
eltitle4 = Label(element4,bg='white',font=mainfont,text='Fourth option')
eltitle4.place(x=75,y=10)
eldesc4 = Label(element4,bg='white',font=subdescfont,text='This is the fourth description of the element.',wraplength=155,justify=LEFT)
eldesc4.place(x=75,y=40)

element5 = Frame(iconframe.interior,bg='white')
element5.place(relx=0.350,y=120,height=100,relwidth=0.30)
icon5image = PhotoImage(file='mainicons/philipsdriver60.png')
icon5 = Label(element5,bg='white',image=icon5image)
icon5.place(x=10,width=60,height=60,y=10)
eltitle5 = Label(element5,bg='white',font=mainfont,text='Fifth option')
eltitle5.place(x=75,y=10)
eldesc5 = Label(element5,bg='white',font=subdescfont,text='This is the fifth description of the element.',wraplength=155,justify=LEFT)
eldesc5.place(x=75,y=40)

element6 = Frame(iconframe.interior,bg='#dfdfdf')
element6.place(relx=0.675,y=120,height=100,relwidth=0.30)
icon6image = PhotoImage(file='mainicons/results60.png')
icon6 = Label(element6,bg='#dfdfdf',image=icon6image)
icon6.place(x=10,width=60,height=60,y=10)
eltitle6 = Label(element6,bg='#dfdfdf',font=mainfont,text='Sixth option')
eltitle6.place(x=75,y=10)
eldesc6 = Label(element6,bg='#dfdfdf',font=subdescfont,text='This is the sixth description of the element.',wraplength=155,justify=LEFT)
eldesc6.place(x=75,y=40)

element7 = Frame(iconframe.interior,bg='white')
element7.place(relx=0.025,y=230,height=100,relwidth=0.30)
icon7image = PhotoImage(file='mainicons/luminary60.png')
icon7 = Label(element7,bg='white',image=icon7image)
icon7.place(x=10,width=60,height=60,y=10)
eltitle7 = Label(element7,bg='white',font=mainfont,text='Seventh option')
eltitle7.place(x=75,y=10)
eldesc7 = Label(element7,bg='white',font=subdescfont,text='This is the seventh description of the element.',wraplength=155,justify=LEFT)
eldesc7.place(x=75,y=40)

element8 = Frame(iconframe.interior,bg='white')
element8.place(relx=0.350,y=230,height=100,relwidth=0.30)
icon8image = PhotoImage(file='mainicons/settings60.png')
icon8 = Label(element8,bg='white',image=icon8image)
icon8.place(x=10,width=60,height=60,y=10)
eltitle8 = Label(element8,bg='white',font=mainfont,text='Eighth option')
eltitle8.place(x=75,y=10)
eldesc8 = Label(element8,bg='white',font=subdescfont,text='This is the eighth description of the element.',wraplength=155,justify=LEFT)
eldesc8.place(x=75,y=40)

element9 = Frame(iconframe.interior,bg='white')
element9.place(relx=0.675,y=230,height=100,relwidth=0.30)
icon9image = PhotoImage(file='mainicons/misc60.png')
icon9 = Label(element9,bg='white',image=icon9image)
icon9.place(x=10,width=60,height=60,y=10)
eltitle9 = Label(element9,bg='white',font=mainfont,text='Ninth')
eltitle9.place(x=75,y=10)
eldesc9 = Label(element9,bg='white',font=subdescfont,text='This is the ninth description of the element.',wraplength=155,justify=LEFT)
eldesc9.place(x=75,y=40)

element10 = Frame(iconframe.interior,bg='white')
element10.place(relx=0.025,y=340,height=100,relwidth=0.30)
icon10image = PhotoImage(file='mainicons/help60.png')
icon10 = Label(element10,bg='white',image=icon10image)
icon10.place(x=10,width=60,height=60,y=10)
eltitle10 = Label(element10,bg='white',font=mainfont,text='Tenth option')
eltitle10.place(x=75,y=10)
eldesc10 = Label(element10,bg='white',font=subdescfont,text='This is the tenth description of the element.',wraplength=155,justify=LEFT)
eldesc10.place(x=75,y=40)


def resizeevent(event):
    width=mainwindow.winfo_width()
    height=mainwindow.winfo_height()
    frame.configure(width=width,height=height)
    label1.place_configure(width=width)
    label2.place_configure(width=width)

    #Ajuste de rejilla por ancho de ventana
    if width < 370:
        iconframe.place_configure(x=0,width=width,height=height-140)
        eldesc1.configure(wraplength=245)
        eldesc2.configure(wraplength=245)
        eldesc3.configure(wraplength=245)
        eldesc4.configure(wraplength=245)
        eldesc5.configure(wraplength=245)
        eldesc6.configure(wraplength=245)
        eldesc7.configure(wraplength=245)
        eldesc8.configure(wraplength=245)
        eldesc9.configure(wraplength=245)
        eldesc10.configure(wraplength=245)
    elif width > 370 and width < 480:
        iconframe.place_configure(x=0,width=width,height=height-140)
        eldesc1.configure(wraplength=300)
        eldesc2.configure(wraplength=300)
        eldesc3.configure(wraplength=300)
        eldesc4.configure(wraplength=300)
        eldesc5.configure(wraplength=300)
        eldesc6.configure(wraplength=300)
        eldesc7.configure(wraplength=300)
        eldesc8.configure(wraplength=300)
        eldesc9.configure(wraplength=300)
        eldesc10.configure(wraplength=300)
    elif width > 480 and width < 600:
        iconframe.place_configure(x=0,width=width,height=height-140)
        element1.place_configure(relx=0,y=10,height=90,relwidth=1,rely=0,relheight=0)
        element2.place_configure(relx=0,y=90,height=90,relwidth=1,rely=0,relheight=0)
        element3.place_configure(relx=0,y=180,height=90,relwidth=1,rely=0,relheight=0)
        element4.place_configure(relx=0,y=270,height=90,relwidth=1,rely=0,relheight=0)
        element5.place_configure(relx=0,y=360,height=90,relwidth=1,rely=0,relheight=0)
        element6.place_configure(relx=0,y=450,height=90,relwidth=1,rely=0,relheight=0)
        element7.place_configure(relx=0,y=540,height=90,relwidth=1,rely=0,relheight=0)
        element8.place_configure(relx=0,y=630,height=90,relwidth=1,rely=0,relheight=0)
        element9.place_configure(relx=0,y=720,height=90,relwidth=1,rely=0,relheight=0)
        element10.place_configure(relx=0,y=810,height=90,relwidth=1,rely=0,relheight=0)

        eldesc1.configure(wraplength=400)
        eldesc2.configure(wraplength=400)
        eldesc3.configure(wraplength=400)
        eldesc4.configure(wraplength=400)
        eldesc5.configure(wraplength=400)
        eldesc6.configure(wraplength=400)
        eldesc7.configure(wraplength=400)
        eldesc8.configure(wraplength=400)
        eldesc9.configure(wraplength=400)
        eldesc10.configure(wraplength=400)
    elif width > 600 and width < 850:
        #Layout 5x2
        iconframe.place_configure(x=0,width=width,height=height-140)
        element1.place_configure(relx=0.033,relwidth=0.45,y=10,height=100)
        element2.place_configure(relx=0.516,relwidth=0.45,y=10,height=100)
        element3.place_configure(relx=0.033,relwidth=0.45,y=120,height=100)
        element4.place_configure(relx=0.516,relwidth=0.45,y=120,height=100)
        element5.place_configure(relx=0.033,relwidth=0.45,y=230,height=100)
        element6.place_configure(relx=0.516,relwidth=0.45,y=230,height=100)
        element7.place_configure(relx=0.033,relwidth=0.45,y=340,height=100)
        element8.place_configure(relx=0.516,relwidth=0.45,y=340,height=100)
        element9.place_configure(relx=0.033,relwidth=0.45,y=450,height=100)
        element10.place_configure(relx=0.516,relwidth=0.45,y=450,height=100)

        eldesc1.configure(wraplength=180)
        eldesc2.configure(wraplength=180)
        eldesc3.configure(wraplength=180)
        eldesc4.configure(wraplength=180)
        eldesc5.configure(wraplength=180)
        eldesc6.configure(wraplength=180)
        eldesc7.configure(wraplength=180)
        eldesc8.configure(wraplength=180)
        eldesc9.configure(wraplength=180)
        eldesc10.configure(wraplength=180) 
    elif width > 851 and width < 1100:
        #Layout 3x4
        iconframe.place_configure(x=0,width=width,height=height-140)
        element1.place_configure(relx=0.025,relwidth=0.30,y=10,height=100)
        element2.place_configure(relx=0.350,relwidth=0.30,y=10,height=100)
        element3.place_configure(relx=0.675,relwidth=0.30,y=10,height=100)
        element4.place_configure(relx=0.025,relwidth=0.30,y=120,height=100)
        element5.place_configure(relx=0.350,relwidth=0.30,y=120,height=100)
        element6.place_configure(relx=0.675,relwidth=0.30,y=120,height=100)
        element7.place_configure(relx=0.025,relwidth=0.30,y=230,height=100)
        element8.place_configure(relx=0.350,relwidth=0.30,y=230,height=100)
        element9.place_configure(relx=0.675,relwidth=0.30,y=230,height=100)
        element10.place_configure(relx=0.025,relwidth=0.30,y=340,height=100)
    elif width > 1100:
        #Layout 4x3
        iconframe.place_configure(x=(width/2)-540,y=100,width=1080,height=height-140)
        element1.place_configure(relx=0.020,relwidth=0.225,y=10,height=100)
        element2.place_configure(relx=0.265,relwidth=0.225,y=10,height=100)
        element3.place_configure(relx=0.510,relwidth=0.225,y=10,height=100)
        element4.place_configure(relx=0.755,relwidth=0.225,y=10,height=100)
        element5.place_configure(relx=0.020,relwidth=0.225,y=120,height=100)
        element6.place_configure(relx=0.265,relwidth=0.225,y=120,height=100)
        element7.place_configure(relx=0.510,relwidth=0.225,y=120,height=100)
        element8.place_configure(relx=0.755,relwidth=0.225,y=120,height=100)
        element9.place_configure(relx=0.020,relwidth=0.225,y=230,height=100)
        element10.place_configure(relx=0.265,relwidth=0.225,y=230,height=100)

mainwindow.bind("<Configure>",resizeevent)


mainwindow.mainloop()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM