I am trying to create a product list using a grid view in Tkinter, but I am totally confused about that why the scrollbar thing is not working, I have checked so many tutorials to fix the scrollbar.
first of all, I thought it was because of pack() or grid(), but after using pack() instead of grid things become worse,
please help me solve this issue
frame_main = Frame(root, bg="gray")
frame_main.pack(fill='both', expand=1)
my_canvas = Canvas(frame_main, bg="red")
my_canvas.pack(fill=Y, expand=1)
vsb = Scrollbar(frame_main, orient="vertical", command=my_canvas.yview)
vsb.pack(side='right', fill=Y)
my_canvas.configure(yscrollcommand=vsb.set)
my_canvas.bind('<Configure>', lambda e: my_canvas.configure(
scrollregion=my_canvas.bbox("all")))
inner_frame = Frame(my_canvas).pack(fill=Y, expand=1)
my_canvas.create_window((0, 0), window=inner_frame, anchor="nw")
img = ImageTk.PhotoImage(Image.open(
'images/apple--600.png').resize((200, 200), Image.ANTIALIAS))
for i in range(4):
for j in range(3):
label = Label(inner_frame, anchor="center", image=img, bg="green")
label.grid(column=j, row=i)
label_txt = Label(inner_frame, anchor="center",
text="item1 \n Price - $20.00", bg="white")
label_txt.grid(column=j, row=i, sticky='WES')
j += 1
i += 2
Related
i only get one picture at the bottom but theres supposed to be 10 all in a vertical tower any idea? also was wondering if the tkinter scrollbar command could have images inside it if not is there any other way to have a scrollbar for lables?
def show_data(self):
print('------------------------------------------------------------------------')
print('data OK')
for i in range(10):
self.image = Image.open(self.data[i][7] + '.jpg')
self.photo = ImageTk.PhotoImage(self.image)
#result0 = Label(self.frame, text=self.data[i][0])
#result0.grid(row=i+3, column=1, sticky=W)
#result1 = Label(self.frame, text=self.data[i][1])
#result1.grid(row=i+3, column=2, sticky=W)
#result2 = Label(self.frame, text=self.data[i][2])
#result2.grid(row=i+3, column=3, sticky=W)
#result3 = Label(self.frame, text=self.data[i][3])
#result3.grid(row=i+3, column=4, sticky=W)
#result4 = Label(self.frame, text=self.data[i][4])
#result4.grid(row=i+3, column=5, sticky=W)
#result5 = Label(self.frame, text=self.data[i][5])
#result5.grid(row=i+3, column=6, sticky=W)
#result6 = Label(self.frame, text=self.data[i][6])
#result6.grid(row=i+3, column=7, sticky=W)
result7 = Label(self.frame, image=self.photo)
result7.grid(row=i + 3, column=8, sticky=W)
In order to keep the image used in label from being destroyed, you need to keep a reference to the image:
def show_data(self):
print('------------------------------------------------------------------------')
print('data OK')
for i in range(10):
photo = ImageTk.PhotoImage(file=self.data[i][7]+'.jpg')
result7 = Label(self.frame, image=photo)
result7.image = photo # keep a reference of the image
result7.grid(row=i + 3, column=8, sticky=W)
To have a scrollbar for the labels inside a frame, the most common way is to put the frame inside a canvas and then create a scrollbar to scroll the view region of the canvas:
# create a canvas and put it as the left side of window
canvas = Canvas(self.master, width=200, height=600) # assume self.master is Tk()
canvas.pack(side='left')
# create an vertical scrollbar and put it at the right side of window
scrollbar = Scrollbar(self.master, orient='vertical', command=canvas.yview)
scrollbar.pack(side='right', fill='y')
# configure the scrollbar to scroll the canvas in vertical direction
canvas.configure(yscrollcommand=scrollbar.set)
# create the frame as child of canvas to hold the labels
self.frame = Frame(canvas)
canvas.create_window((0,0), window=self.frame, anchor='nw')
# make sure to update the scrolling region if the frame is resized
self.frame.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox('all')))
I am trying to put a scrollbar on my listbox but because the items I am inserting are so long, but the scrollbar does not scroll all the way. If you run the code below, you will see what I am talking about and notice that the horizontal scroll bar can not scroll all the way to the right. Does anyone know how I can fix this? Same problem occurs for the vertical scroll bar when you add a few more entries.
import tkinter
lista=[11111111111111111111111111111111111111111111111,22222222222222222222222222222222222222222222222222,
33333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444467,4444444444444444,
5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555556]
master = tkinter.Tk()
master.geometry("400x250")
frame = tkinter.Frame(master, borderwidth=1, highlightthickness=1,
highlightbackground="black", highlightcolor="black")
frame.place(bordermode=tkinter.INSIDE, height=240, width=300, y=0, x=30)
LIST = tkinter.Listbox(frame)
LIST.place(bordermode=tkinter.INSIDE, height=237, width=296)
Scroll_Bar_x = tkinter.Scrollbar(frame, orient=tkinter.HORIZONTAL)
Scroll_Bar_x.config(command=LIST.xview)
Scroll_Bar_x.pack(fill=tkinter.X, side=tkinter.BOTTOM)
LIST.config(xscrollcommand=Scroll_Bar_x.set)
Scroll_Bar_y = tkinter.Scrollbar(frame, orient=tkinter.VERTICAL)
Scroll_Bar_y.config(command=LIST.yview)
Scroll_Bar_y.pack(fill=tkinter.Y, side=tkinter.RIGHT)
LIST.config(yscrollcommand=Scroll_Bar_y.set)
for x in lista:
LIST.insert(0, x)
master.mainloop()
You are having issues with overlapping your scroll bars on the placed listbox. Most of the time place() is not what you want to use.
Instead try grid() this will help keep everything in order and sized correctly.
import tkinter
lista=[11111111111111111111111111111111111111111111111,22222222222222222222222222222222222222222222222222,
33333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444467,4444444444444444,
5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555556]
master = tkinter.Tk()
master.geometry("400x250")
frame = tkinter.Frame(master, height=240, width=300, borderwidth=1, highlightthickness=1, highlightbackground="black", highlightcolor="black")
frame.grid(row=0, column=0)
frame.rowconfigure(0, weight=1)
frame.columnconfigure(0, weight=1)
LIST = tkinter.Listbox(frame)
LIST.grid(row=0, column=0, sticky="nsew")
frame.grid_propagate(False)
Scroll_Bar_x = tkinter.Scrollbar(frame, orient=tkinter.HORIZONTAL)
Scroll_Bar_x.config(command=LIST.xview)
Scroll_Bar_x.grid(row=1, column=0, sticky="ew")
LIST.config(xscrollcommand=Scroll_Bar_x.set)
Scroll_Bar_y = tkinter.Scrollbar(frame, orient=tkinter.VERTICAL)
Scroll_Bar_y.config(command=LIST.yview)
Scroll_Bar_y.grid(row=0, column=1, sticky="ns")
LIST.config(yscrollcommand=Scroll_Bar_y.set)
for x in lista:
LIST.insert(0, x)
master.mainloop()
Results:
Consider the following example:
from tkinter import *
startingWin = Tk()
canvas = Canvas(startingWin, height=600)
canvas.grid(row=0, column=0,sticky="nsew")
canvasFrame = Frame(canvas)
canvas.create_window(0, 0, window=canvasFrame, anchor='nw')
for i in range(70):
element = Button(canvasFrame, text='Button %s ' % i)
element.grid(row=i, column=0)
yscrollbar = Scrollbar(startingWin, orient=VERTICAL)
yscrollbar.config(command=canvas.yview)
canvas.config(yscrollcommand=yscrollbar.set)
yscrollbar.grid(row=0, column=1, sticky="ns")
canvas.yview_moveto(0.5)
canvasFrame.bind("<Configure>", lambda event: canvas.configure(scrollregion=canvas.bbox("all")))
startingWin.mainloop()
Expected output: Scrollbar in the middle.
However, I get the Scrollbar always on the top, regardless of the value I give to yview_moveto() like the following:
How can I fix this?
You shouldn't call canvas.yview_moveto(0.5) until after the scrollregion has been defined.
I have a canvas in a frame
photoFrame = Frame(centerFrame, width=250, height=190, bg="#EBEBEB")
photoFrame.grid(row=0, column=1, sticky="nsew")
photoCanvas = Canvas(photoFrame, bg="#EBEBEB")
photoCanvas.grid(row=0, column=0, sticky="nsew")
and I try to put a scrollbar to my canvas with this
photoScroll = Scrollbar(photoFrame, orient=VERTICAL)
photoScroll.config(command=photoCanvas.yview)
photoCanvas.config(yscrollcommand=photoScroll.set)
photoScroll.grid(row=0, column=1, sticky="ns")
The scrollbar appears but it's disabled. Can you help me please ?
Sorry for my bad english.
In a for loop I add lots of Image button with this code
element = Button(photoCanvas, image = listPhotos[i], borderwidth=0, height = 200, width = 200, bg="#EBEBEB")
element.grid(row=rowPhoto, column=columnPhoto, padx=5, pady=5, sticky="nsew")
Finnally I have this
root = Tk()
photoFrame = Frame(root, width=250, height=190, bg="#EBEBEB")
photoCanvas = Canvas(photoFrame, bg="#EBEBEB")
photoCanvas.grid(row=0, column=0, sticky="nsew")
for i in range(0, len(listPhotos), 1):
element = Button(photoCanvas, image = listPhotos[i], borderwidth=0, height = 200, width = 200, bg="#EBEBEB")
element.grid(row=rowPhoto, column=columnPhoto, padx=5, pady=5, sticky="nsew")
photoScroll=Scrollbar(photoFrame,orient=VERTICAL)
photoScroll.config(command=photoCanvas.yview)
photoCanvas.config(yscrollcommand=photoScroll.set)
photoScroll.grid(row=0, column=1, sticky="ns")
in my app, the purple rectangle is the next frame and I need a vertical scrollbar
Say if you have some questions
One way to scroll a group of widgets is to put them (with grid of pack) inside a frame and put this frame inside a canvas.
The two key elements (besides connecting the scrollbar to the canvas) for the scrolling to work are:
Use canvas.create_window(x, y, window=frame) to put the frame inside the canvas so that it is treated like a canvas item.
Update the canvas scrollregion each time the size of the frame changes (for instance after adding a new widget) with canvas.configure(scrollregion=canvas.bbox('all')).
Here is an adaptation of the code of the question Python Tkinter scrollbar for frame, but using the widgets name from the OP's question and grid instead of pack:
import tkinter as tk
def update_scrollregion(event):
photoCanvas.configure(scrollregion=photoCanvas.bbox("all"))
root = tk.Tk()
photoFrame = tk.Frame(root, width=250, height=190, bg="#EBEBEB")
photoFrame.grid()
photoFrame.rowconfigure(0, weight=1)
photoFrame.columnconfigure(0, weight=1)
photoCanvas = tk.Canvas(photoFrame, bg="#EBEBEB")
photoCanvas.grid(row=0, column=0, sticky="nsew")
canvasFrame = tk.Frame(photoCanvas, bg="#EBEBEB")
photoCanvas.create_window(0, 0, window=canvasFrame, anchor='nw')
for i in range(10):
element = tk.Button(canvasFrame, text='Button %i' % i, borderwidth=0, bg="#EBEBEB")
element.grid(padx=5, pady=5, sticky="nsew")
photoScroll = tk.Scrollbar(photoFrame, orient=tk.VERTICAL)
photoScroll.config(command=photoCanvas.yview)
photoCanvas.config(yscrollcommand=photoScroll.set)
photoScroll.grid(row=0, column=1, sticky="ns")
canvasFrame.bind("<Configure>", update_scrollregion)
root.mainloop()
I would like to arrange the Labels in the canvas one after another. But placement is not coming out as desired.
Below is the function that inserts the labels in the canvas. But the ones in the for loop overlaps. Reason - some labels are larger in size than the other. Hence, I assume that largest size be 80 and do the placements respectively. I would like to change this type of approach. Rather I want the labels to be placed relatively one after the other.
def calculate(*args):
try:
ttk.Label(canvas, text="Result:").place(x=20, y=20)
ttk.Label(canvas, text="Topic:").place(x=20, y=80)
ttk.Label(canvas, textvariable=topic).place(x=200, y=80)
ttk.Label(canvas, text="Environment:").place(x=20, y=120)
ttk.Label(canvas, textvariable=environment).place(x=200, y=120)
ttk.Label(canvas, text="Event Results:").place(x=20, y=160)
inputValue=TextArea.get("1.0","end-1c")
len_max=0
result={}
for s in inputValue.splitlines():
data = MainInstance.searchWithPayload(s)
result[s]=data
if len(s+data) > len_max:
len_max = len(s+data)
i = 190
for key in result.keys():
print(key)
print(result[key])
ttk.Label(canvas, text=key+"\n\n"+result[key], wraplength=800).place(x=20,y = i)
i = i + 80
except ValueError:
pass
Below is the code that integrates the canvas widget. And the calculate button calls the calculate function.
ttk.Button(page2, text="Exit",command=page1.quit).grid(column=2, row=8)
ttk.Button(page2, text="Calculate", command=calculate).grid(column=3, row=8)
canvas = Canvas(root, width=900, height=universal_height)
canvas.grid(column=1, row=0)
root.mainloop()
Actually, there are two parts of the question:
How can I relatively place the label to stop the overlapping?
I tried adding the scroll to the canvas. But the application does not respond and does not pop up.
Code for adding the scrollbar:
canvas=Canvas(root,bg='#FFFFFF',width=300,height=300,scrollregion=
(0,0,500,500))
hbar=Scrollbar(root,orient=HORIZONTAL)
hbar.pack(side=BOTTOM,fill=X)
hbar.config(command=canvas.xview)
vbar=Scrollbar(root,orient=VERTICAL)
vbar.pack(side=RIGHT,fill=Y)
vbar.config(command=canvas.yview)
canvas.config(width=300,height=300)
canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
canvas.pack(side=LEFT,expand=True,fill=BOTH)
This is the output that I am getting, wherein the first two labels are getting overlapped.
If you want to scroll the widgets that you put inside the canvas, you need to use canvas.create_window(x, y, window=label) instead of label.place(...).
I suggest you to create a frame, grid all you labels inside it so that you won't have overlapping issues and put the frame inside the canvas using create_window to be able to scroll it:
import tkinter as tk
from tkinter import ttk
def on_resize(event):
"""Resize canvas scrollregion when the canvas is resized."""
canvas.configure(scrollregion=canvas.bbox('all'))
root = tk.Tk()
root.geometry('100x100')
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
canvas = tk.Canvas(root)
frame = ttk.Frame(canvas)
# create and grid the labels
for i in range(3):
for j in range(3):
ttk.Label(frame, text="Label %i-%i" % (i, j)).grid(row=i, column=j, padx=10, pady=10)
# put the frame in the canvas
canvas.create_window(0, 0, anchor='nw', window=frame)
# add the scrollbars
vbar = ttk.Scrollbar(root, orient='vertical', command=canvas.yview)
hbar = ttk.Scrollbar(root, orient='horizontal', command=canvas.xview)
canvas.configure(xscrollcommand=hbar.set,
yscrollcommand=vbar.set,
scrollregion=canvas.bbox('all'))
canvas.grid(row=0, column=0, sticky='eswn')
vbar.grid(row=0, column=1, sticky='ns')
hbar.grid(row=1, column=0, sticky='ew')
canvas.bind('<Configure>', on_resize)
root.mainloop()