Tkinter Canvas create_window positioning issue - python
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()
Related
Python Tkinter:Frames are not going under each otheer
I was making a simple tkinter GUI which has scrolling frames in it but it is not being so perfect for me.At first I used only one frame, but however I found out that frames have a limit on the no. of widgets they can hold,so I started using multiple frames. However I got this problem:the frames are not going in the direction I wanted.I wanted the frames to go under the previous frame ,however the frames are going one above the other here is a screenshot of the same: (Frame 0 is the first Frame) Here is the code(I have only kept the important portion) i=0 image_no=0 for video in videos: u = urllib.request.urlopen(video["thumbnail"]["thumbnails"][0]["url"]) raw_data = u.read() u.close() im = Image.open(BytesIO(raw_data)) image = ImageTk.PhotoImage(im.resize((470,210))) a.append(image) tk.Label(fr[i], image=a[image_no]).pack() image_no+=1 tk.Label(fr[i], text=("Video:"+str(image_no)+" frame:"+str(i)),wraplength=470,font=("ariel",11,"bold"),bg="white").pack() tk.Label(fr[i], text=video["title"]["accessibility"]["accessibilityData"]['label'].replace(video["title"]["runs"][0]["text"],""),wraplength=470,font=("ariel",10),bg="white",fg="grey").pack(anchor="w") canvas.configure(yscrollcommand=scroll_y.set) canvas.configure(scrollregion=canvas.bbox("all")) print(image_no) print(video["title"]["runs"][0]["text"]) if image_no%10==0: time.sleep(3) if image_no%110==0: i+=1 if image_no%440==0: break Is there any way I could make it go downwards? Edit: Here is the screenshot of the frame limit the black area is of the canvas
Here is a link to question tkinter maximum canvas size? I've modified the code due to the possibility that the number of images may be responsible or the canvas may have some maximum height. This will now fill the entire canvas height with images, each with a 10 point space between. I've updated it for python 3.x and increased height to 100000! Works without problems. Choose your own image (gif or png) import tkinter as tk from tkinter import filedialog as fido root = tk.Tk() root.rowconfigure(0, weight = 1) root.columnconfigure(0, weight = 1) picture = fido.askopenfilename(title = "Pick a pic") iconimage = tk.PhotoImage(file = picture) wide, high = iconimage.width(), iconimage.height() frame = tk.LabelFrame(root, labelanchor = "s", text = "0|0") frame.grid(row = 0, column = 0, sticky = "nsew") frame.rowconfigure(0, weight = 1) frame.columnconfigure(0, weight = 1) cv = tk.Canvas( frame, width = 1200, height = 700, scrollregion = "0 0 2000 100000") cv.grid(row = 0, column = 0, sticky = "nsew") vscrollbar = tk.Scrollbar( frame, orient = "vertical", command = cv.yview) vscrollbar.grid(row = 0, column = 1, sticky = "ns") cv.config(yscrollcommand = vscrollbar.set) def rowcol(ev): frame["text"] = f"{cv.canvasx(ev.x)} | {cv.canvasy(ev.y)}" cv.bind("<Motion>", rowcol) root.update() testimage = [] for pos in range( 0, 100000 - high - 10, high + 10): testimage.append(cv.create_image(100, pos, anchor = "nw", image = iconimage)) print(f"Number of images = {len(testimage)}, width = {wide}, height = {high}") root.mainloop() So it doesn't seem to be a limitation of Canvas height or number of images displayed.
How do I put widgets inside a frame inside a window?
so I'm trying to put together an GUI divided up into multiple frames, and then have each frame have either labels or inputs, however, on the 'inputframe', whenever I add the label and try to place it, it just plops the label in the middle of the frame and I can't seem to move it anywhere. Is it possible for me to place labels inside a frame how I like? I'm doing this on VS Code, have made progress on every other problem I've run into so far but can't seem to solve this one. class Window1: def __init__(self): window = Tk() # Create a window window.title("Order Processing Application") # Set title of a window window.geometry('920x560') #set up window and import picture for the window photo = PhotoImage(file=r"C:\Users\Owner\Downloads\GWlogo.gif") logoFrame = Frame(window, width = 160, height = 160) logoFrame.grid(row = 0, column = 0) stepTitleFrame = Frame(window, width = 840, height = 160, bg = 'red') stepTitleFrame.grid(row = 0, column = 1) statusFrame = Frame(window, width = 320, height = 560, bg='green') statusFrame.grid(row = 1, column = 0) inputFrame = Frame(window, width = 840, height = 560) inputFrame.grid(row = 1, column = 1) #imports Glamping World logo into the logo frame logoPic = Label(logoFrame, image = photo) logoPic.grid(row = 0, column = 0) #Testing labels in the main input frame inputLabel1 = Label(inputFrame, text="Testing Label 1") inputLabel1.grid(row = 0, column = 1) I'm trying to get the label to appear in the inputFrame, row 0 column 0, but it will only appear in the middle of the inputFrame.
tkinter - Scrollbar will not show
I am having a developing a GUI in Python and there is no scrollbar that shows when I run it. It get an empty bar with arrows, but there is no scrollbar inside and the scrollbar does not work at all. #Scroll Functions def ScrollAll(event): self.topcanvas.config(scrollregion = self.topcanvas.bbox("all")) def on_mousewheel(event): self.topcanvas.yview('scroll',0, 'units') #topframe topframe = Frame(master, background = '#D9F7FE', width = 2100, height = 1700) topframe.place(x = 0, y = 0) #Top canvas self.topcanvas = Canvas(topframe, scrollregion = (0, 0, 1000, 1000)) self.topcanvas.pack(side = TOP, fill = BOTH, expand = TRUE) self.topcanvas.config(width = 2100, height =1700, background = '#D9F7FE') #scroll self.vbar = ttk.Scrollbar(master, orient = 'vertical', command = self.topcanvas.yview) #self.hbar = ttk.Scrollbar(master, orient = 'horizontal', command = self.topcanvas.xview) #self.topcanvas.config(xscrollcommand = self.hbar.set) self.topcanvas.config(yscrollcommand = self.vbar.set) #self.hbar.pack(side = "bottom", fill = "x") self.vbar.pack(side = "right", fill = "y") self.topcanvas.pack(side="left") self.topcanvas.bind_all("<MouseWheel>", on_mousewheel) #frame frame = Frame(self.topcanvas) frame.config(width = 2100, height = 1700,background = '#D9F7FE') self.topcanvas.create_window((0,0), window = frame, anchor = 'nw') frame.bind("<Configure>", ScrollAll)
My scroll region needed to be larger than the actual frame it was in. I increased my scroll region and my scroll bars worked.
When use image in tk Button, Button disappear
Here is my code, you can ignore most of them but only see the last part which have # import tkinter as tk from PIL import ImageTk, Image def bresize_and_load(path): global bwidth, bheight im = Image.open(path) bwidth,bheight = im.size resized = bresizemode(im, bwidth, bheight) width,height = resized.size return ImageTk.PhotoImage(resized) def bresizemode(im, width, height): if height / width >= ratio: return im.resize((int(round((width / height) * usable_height)), usable_height), Image.ANTIALIAS) if height / width < ratio: return im.resize((usable_width, (int(round((height / width) * usable_width)))), Image.ANTIALIAS) root = tk.Tk() root.state("zoomed") root.resizable(width=False, height=False) frame = tk.Frame(root) frame.grid(row = 0, column = 0, sticky = 'nsew') tk.Grid.rowconfigure(root, 0, weight=1) tk.Grid.columnconfigure(root, 0, weight=1) row = 4 column = 5 for ro in range(row): tk.Grid.rowconfigure(frame, ro, weight=1) for co in range(column): tk.Grid.columnconfigure(frame, co, weight=1) root.update() f_width = frame.winfo_width() f_height = frame.winfo_height() booklistbutton = [] for i in range(row): for e in range(column): bbutton = tk.Button(frame, height = int(f_height / row), width = int(f_width / column)) bbutton.grid(row = i, column = e) booklistbutton.append(bbutton) root.update() usable_width = booklistbutton[0].winfo_width() usable_height = booklistbutton[0].winfo_height() ratio = usable_height / usable_width #here is image path path = 'sample.jpg' imm = [] #if it is range(20)(just = row * column) or less than column(here is 5), it work fine for i in range(20): imm.append(bresize_and_load(path)) booklistbutton[i].config(image = imm[i]) root.mainloop() My question is, if you load image in button, but the number of imaged buttons is not less than column or equal row * column, the imaged buttons will disappear. When range equal row * column(20): When range is 6: This is weird for me, does anyone have any idea? Also, if you do not set button's width and height, they won't disappear. But buttons will little bigger than images.
(Posted solution on behalf of the OP). I find the problem by myself, the problem is when I set the Buttons' size, it is chr size, but when I load a image, it change to pixel size, and at the same size number, chr size is bigger and bigger than pixel size, so the imaged button become too small to show.
Make a Grid with Tkinter Rectangle
I am trying to simulate a grid like what would be used for a game board using tkinter rectangles being drawn onto a canvas, however I am having trouble making a loop that does so correctly. Pretty much I have a variable that contains a certain amount of rows for a grid and a variable for the amount of columns, and I need to create a grid of rectangles based off of those configurations which can change anytime the application is run, which is making it a bit tricky for me. Anyways, I currently have a function to draw a rectangle to the screen like so: def _place_empty_tiles(self): self._canvas.update() width = self._canvas.winfo_width() height = self._canvas.winfo_height() self.x = width / self._game.columns self.y = height / self._game.rows for i in range(self._game.columns): click_point = point.from_pixel(self.x, self.y, width, height) self._state.handle_click(click_point) self.x += 60 def _redraw_game_pieces(self)->None: '''Delete and redraw all the of game pieces''' self._canvas.delete(tkinter.ALL) canvas_width = self._canvas.winfo_width() canvas_height = self._canvas.winfo_height() for tile in self._state.all_tiles(): center_x, center_y = tile.center().pixel(canvas_width, canvas_height) radius_x = tile.radius_frac() * canvas_width radius_y = tile.radius_frac() * canvas_height self._canvas.create_rectangle( center_x - radius_x, center_y - radius_y, center_x + radius_x, center_y + radius_y, fill = '#006000', outline = '#000000') You may noticed I have some custom coordinate conversion methods going on to compensate for the screen re sizing. However, my problem is under the function _place_empty_tiles(self) in the for loop. Let's say the amount of columns is 4, it will currently print out on the canvas the following: However, it is actually making a row, and that is only one row. How can I make it so I can create a grid with a similar style given the amount of rows and columns are stored in self._game.columns and self._game.rows? UPDATE: Tried basing it off The tkinter Knight's Tour Demo I rewrote the function like so: def _place_empty_tiles(self): self._canvas.update() width = self._canvas.winfo_width() height = self._canvas.winfo_height() for r in range(self._game.rows -1,-1,-1): for c in range(self._game.columns): click_point = point.from_pixel(c*30+4, r*30+4, c*30+30, r*30+30) self._state.handle_click(click_point) self._redraw_game_pieces() which is close, but still getting some unexpected results:
The Tk demos include a Knight's Tour demo that draws a chessboard. Someone converted it for tkinter and you can examine the _draw_board function to see an example of how to create such a layout using canvas rectangles: def draw_board(canvas): # draw checkerboard for r in range(7, -1, -1): for c in range(8): if c&1 ^ r&1: fill = 'tan3' dfill = 'tan4' else: fill = 'bisque' dfill= 'bisque3' coords = (c*30+4, r*30+4, c*30+30, r*30+30) canvas.create_rectangle(coords, fill=fill, disabledfill=dfill, width=2, state='disabled')
Here's an example that draws a grid that fits the window as closely as possible. It is designed to redraw itself whenever the window resizes. If you don't want that behavior, you can hard-code the cell width and height. The cells are stored in a dictionary indexed by row and column, to make it easy to reference each tile. Clicking on a tile will toggle it between blue and red. Note that when the window resizes it won't remember which cells were previously clicked on. That's easy to fix if you want. import Tkinter as tk class App(tk.Tk): def __init__(self, *args, **kwargs): tk.Tk.__init__(self, *args, **kwargs) self.canvas = tk.Canvas(self, width=500, height=500, borderwidth=0, highlightthickness=0) self.canvas.pack(side="top", fill="both", expand="true") self.rows = 20 self.columns = 20 self.tiles = {} self.canvas.bind("<Configure>", self.redraw) self.status = tk.Label(self, anchor="w") self.status.pack(side="bottom", fill="x") def redraw(self, event=None): self.canvas.delete("rect") cellwidth = int(self.canvas.winfo_width()/self.columns) cellheight = int(self.canvas.winfo_height()/self.columns) for column in range(self.columns): for row in range(self.rows): x1 = column*cellwidth y1 = row * cellheight x2 = x1 + cellwidth y2 = y1 + cellheight tile = self.canvas.create_rectangle(x1,y1,x2,y2, fill="blue", tags="rect") self.tiles[row,column] = tile self.canvas.tag_bind(tile, "<1>", lambda event, row=row, column=column: self.clicked(row, column)) def clicked(self, row, column): tile = self.tiles[row,column] tile_color = self.canvas.itemcget(tile, "fill") new_color = "blue" if tile_color == "red" else "red" self.canvas.itemconfigure(tile, fill=new_color) self.status.configure(text="you clicked on %s/%s" % (row, column)) if __name__ == "__main__": app = App() app.mainloop()