Tkinter Scrollbar position, yview_moveto() seems not working - python

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.

Related

How can I change the shape of the scrollbar in tkinter, python?

I use scrollbar widget and I want to change the shape of it.
Here's my questions below.
Can I use the image on the scroll bar?
How can I modify the color and shape with the options like relief, background, highlightbackground, highlightcolor or highlightthickness? I already tried but not a thing has changed.
from tkinter import *
root = Tk()
root.geometry("640x480")
frame = Frame(root)
frame.pack()
scrollbar = Scrollbar(frame, relief=RAISED, width=20, bd=5, activebackground="yellow", elementborderwidth=10, troughcolor="yellow", highlightbackground="red")
scrollbar.pack(side="right", fill="y")
listbox = Listbox(frame, selectmode="extended", height=10, bg="green", fg="white", yscrollcommand=scrollbar.set)
for i in range(1, 32):
listbox.insert(END, str(i) + "day")
listbox.pack()
scrollbar.config(command = listbox.yview) # scrollbar와 listbox를 mapping 해줌
root.mainloop()

Scrollbar issue in tkinter python

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

How to update tkinter scrollbar size for canvas size

So I want to have a vertical and horizontal scroll bar on the window that automatically updates for the size of the canvas. I got it partly there, and right now the code creates extra scroll bars for each update and the horizontal scroll bar doesn't span the length of the whole canvas. Here is a sample I created to illustrate this:
import tkinter
from tkinter import ttk
root = tkinter.Tk()
root.state("zoomed")
bigframe = tkinter.Frame(root)
bigframe.pack(fill="both", expand=1)
canvas = tkinter.Canvas(bigframe)
canvas.pack(side="left", fill="both", expand=1)
scrollbarv = ttk.Scrollbar(bigframe, orient="vertical", command=canvas.yview)
scrollbarh = ttk.Scrollbar(bigframe, orient="horizontal", command=canvas.xview)
scrollbarv.pack(side="right", fill="y")
scrollbarh.pack(side="bottom", fill="x")
canvas.configure(yscrollcommand=scrollbarv.set, xscrollcommand=scrollbarh.set)
canvas.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
mainframe = tkinter.Frame(canvas)
canvas.create_window((0, 0), window=mainframe, anchor="nw")
i = 1
text = "Hello World! "
def click():
global i
global text
for t in range(10):
i += 1
text += "Hello World! "
tkinter.Label(mainframe, text=text).pack()
scrollbar = ttk.Scrollbar(bigframe, orient="vertical", command=canvas.yview)
scrollbar.pack(side="right", fill="y")
button = tkinter.Button(mainframe, text="Click me!", command=click)
button.pack()
root.mainloop()
This is what happens when I click the button 4 times:
I believe the horizontal scrollbar being small is due to me saying canvas.pack(side="left", fill="both", expand=1), but if I say side="top then the vertical scroll bars don't span the height of the canvas.
Is there some specific piece of code that is causing the multiple scrollbars issue or the horizontal bar issue? And if so, how should I fix it?
You have to destroy the old scrollbar before you add a new one. Just add scrollbar.destroy() to your click function, like I did below:
def click():
global i
global text
for t in range(10):
i += 1
text += "Hello World! "
tkinter.Label(mainframe, text=text).pack()
scrollbar = ttk.Scrollbar(bigframe, orient="vertical", command=canvas.yview)
scrollbar.destroy()
scrollbar.pack(side="right", fill="y")
I made the following changes to your code. At first it doesn't work, however if I resize the window it works perfectly.
import tkinter
from tkinter import ttk
root = tkinter.Tk()
root.state("zoomed")
bigframe = tkinter.Frame(root)
bigframe.pack(fill="both", expand=1)
canvas = tkinter.Canvas(bigframe)
canvas.pack(side="left", fill="both", expand=1)
scrollbarv = ttk.Scrollbar(bigframe, orient="vertical",
command=canvas.yview)
scrollbarh = ttk.Scrollbar(root, orient="horizontal",
command=canvas.xview)
scrollbarv.pack(side="right", fill="y")
scrollbarh.pack(side="bottom", fill="x")
canvas.configure(yscrollcommand=scrollbarv.set,
xscrollcommand=scrollbarh.set)
canvas.bind("<Configure>", lambda e:
canvas.configure(scrollregion=canvas.bbox("all")))
mainframe = tkinter.Frame(canvas)
canvas.create_window((0, 0), window=mainframe, anchor="nw")
i = 1
text = "Hello World! "
def updateScrollRegion():
canvas.update_idletasks()
canvas.config(scrollregion=mainframe.bbox())
def click():
global i, scrollbarv, text
for t in range(10):
i += 1
text += "Hello World! "
tkinter.Label(mainframe, text=text).pack()
button = tkinter.Button(mainframe, text="Click me!", command=click)
button.pack()
root.mainloop()

Tkinter Scrolling Issues

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:

Tkinter: Placing the Labels one after another in Canvas relatively.

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()

Categories