Scrollbar not building properly in tkinter - python

Can anybody please tell me what I am doing wrong? The scrollbar seems not to reflect the area of the widget it is bound to.
Many thanks.
from tkinter import *
import tkinter as tk
#panel1
root = tk.Tk()
frame1 = tk.Frame(master=root, width=900, height=800)
canvas = tk.Canvas(frame1, width=900, height= 900)
vsb = tk.Scrollbar(frame1, orient=VERTICAL)
canvas.configure(yscrollcommand=vsb.set,
scrollregion=canvas.bbox("all"))
vsb.configure(command=canvas.yview)
canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
vsb.pack(fill=Y, side=RIGHT, expand=FALSE)
# notebook.add(frame1, text="1")
frame1.pack(expand=True, fill=BOTH)
root.mainloop()

If canvas is empty then there is nothing to scroll. And scrollbar reflects it correctly.
You have to add something to Canvas to scroll it.
I put two Frames bigger than window's size and now you have somthing to scroll.
You have to use scrollregion= after you put items in canvas. Or you can use after() to use scrollregion= after tkinter shows window.
import tkinter as tk
#def resize():
# canvas.configure(scrollregion=canvas.bbox("all"))
root = tk.Tk()
frame1 = tk.Frame(root, width=900, height=800)
frame1.pack(expand=True, fill='both')
canvas = tk.Canvas(frame1, width=900, height= 900)
canvas.pack(side='left', fill='both', expand=True)
vsb = tk.Scrollbar(frame1, orient='vertical')
vsb.pack(fill='y', side='right', expand=False)
vsb.configure(command=canvas.yview)
item_1 = tk.Frame(canvas, bg='red', width=500, height=500)
canvas.create_window(0, 0, window=item_1, anchor='nw')
item_2 = tk.Frame(canvas, bg='green', width=500, height=500)
canvas.create_window(500, 500, window=item_2, anchor='nw')
canvas.configure(yscrollcommand=vsb.set, scrollregion=canvas.bbox("all"))
#root.after(100, resize)
root.mainloop()

Related

Why frame border / line appear after click text widget (the frame is inside canvas) tkinter

i've the problem for make an GUI apps with python tkinter.
here is my sample code
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry('300x300')
root.title('CSV Editor')
notebook = ttk.Notebook(root)
notebook.pack(pady=10, expand=True)
tab_home = ttk.Frame(notebook, width=300, height=300)
notebook.add(tab_home, text='Home')
fr_home = tk.Frame(tab_home, background="white")
fr_home.grid(row=0, column=0)
fr_home_container_canvas = tk.Frame(fr_home, background="red")
fr_home_container_canvas.grid(row=0, column=0, sticky='nw')
fr_home_container_canvas.grid_rowconfigure(0, weight=1)
fr_home_container_canvas.grid_columnconfigure(0, weight=1)
fr_home_container_canvas.grid_propagate(False)
canvas_home = tk.Canvas(fr_home_container_canvas)
canvas_home.grid(row=0, column=0, sticky="news")
vsb = tk.Scrollbar(fr_home_container_canvas, orient="vertical", command=canvas_home.yview)
vsb.grid(row=0, column=1, sticky='ns')
canvas_home.configure(yscrollcommand=vsb.set)
fr_home_widget_canvas = tk.Frame(canvas_home, background="yellow")
canvas_home.create_window((0, 0), window=fr_home_widget_canvas, anchor='nw')
fr_home_widget_canvas.config(width=300, height=300, padx=10)
fr_home_container_canvas.config(width=300, height=300)
canvas_home.config(scrollregion=canvas_home.bbox("all"))
text_widget = tk.Text(fr_home_widget_canvas, width = 30, height = 10)
text_widget.grid(column=0, row=0)
root.mainloop()
if i run this code, this is the preview
enter image description here
but when i click inside the text widget, in the frame appear line / border like this
enter image description here
What is that line / border? how to remove it?
thank you so much :)
It is the highlight background which can be removed by setting highlightthickness=0:
canvas_home = tk.Canvas(fr_home_container_canvas, highlightthickness=0)

How to apply a scrollbar in Tkinter GUI?

The idea of this python program is to scrape recipes from a food website and output the recipes in a tkinter GUI when clicking the button. I have already applied the scrollbar to the GUI but it is not working as it should. I have already tried many ways but I did not succeed so I decided to ask help from the stack overflow community. I am new to tkinter so sorry for asking help for possibly a silly problem.
The code so far:
import tkinter as tk
from tkinter import Scrollbar
root = tk.Tk()
root.title('Italian-recipes')
height=600
width=895
canvas = tk.Canvas(root, height=height, width=width)
canvas.pack()
background_image = tk.PhotoImage(file='food.png')
background_label = tk.Label(root, image=background_image)
background_label.place(relwidth=1, relheight=1)
lower_frame = tk.Frame(root, bg='#80c1ff', bd=5)
lower_frame.place(relx=0.5, rely=0.25, relwidth=0.75, relheight=0.6, anchor='n')
frame = tk.Frame(root, bg='#AFF9A9', bd=5)
frame.place(relwidth=0.75, relheight=0.1, relx=0.5, rely=0.1, anchor='n')
button = tk.Button(frame, text='Enter food or ingredient', font=40, command=lambda:
test_function(entry.get()))
button.place(relx=0.55, relwidth=0.45, relheight=1)
entry = tk.Entry(frame, font=40)
entry.place(relwidth=0.5, relheight=1)
listbox = tk.Listbox(lower_frame, justify='left', bd=4)
listbox.place(relwidth=1, relheight=1)
label = tk.Label(listbox, anchor='nw', justify='left', bd=4)
label.place(relwidth=1, relheight=1)
scrollbar = Scrollbar(listbox, orient="vertical")
scrollbar.pack( side = 'right', fill = 'y' )
root.mainloop()
I did it with a textfield, that you can see how it work. Change it back to your listbox
import tkinter as tk
from tkinter import Scrollbar
root = tk.Tk()
root.title('Italian-recipes')
height=600
width=895
canvas = tk.Canvas(root, height=height, width=width)
canvas.pack()
lower_frame = tk.Frame(root, bg='#80c1ff', bd=5)
lower_frame.place(relx=0.5, rely=0.25, relwidth=0.75, relheight=0.6, anchor='n')
frame = tk.Frame(root, bg='#AFF9A9', bd=5)
frame.place(relwidth=0.75, relheight=0.1, relx=0.5, rely=0.1, anchor='n')
scrollbar = Scrollbar(lower_frame, orient="vertical")
scrollbar.pack( side = 'right', fill = 'y' )
listbox = tk.Text(lower_frame, yscrollcommand=scrollbar.set, bd=4)
listbox.pack(fill="both", expand="yes")
scrollbar.configure(command=listbox.yview)
root.mainloop()

Why can't I set the background of a ttk Frame?

This is my code:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.protocol("WM_DELETE_WINDOW", lambda: on_closing(root, btn))
frame1 = tk.Frame(root, bg=root['background'])
frame1.pack(expand="YES")
canvas = tk.Canvas(frame1, width=200, height=300, relief="sunken", bd=0, bg=root['background'])
scroll_y = tk.Scrollbar(frame1, orient="vertical", command=canvas.yview, bg=canvas['background'])
scroll_y.pack(side="right", fill='y')
canvas.pack(side="top", expand='YES', fill='both')
canvas.configure(yscrollcommand=scroll_y.set)
# canvas.update_idletasks()
# canvas.yview_moveto('1.0')
s = ttk.Style()
s.configure("new.TFrame", background=canvas['background'], width=canvas.winfo_width(), height=canvas.winfo_height())
msgFrame = ttk.Frame(canvas, style="new.TFrame")
msgFrame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
canvas.create_window((0, 0), window=msgFrame, anchor="nw")
Why won't the frame change its color? Or its width/height?
If you'd like to put some strings in the frame:
for i in range (50):
lbl = tk.Label(msgFrame, text="example").pack()
First using same background color for all the widgets is hard to see the effect. For debug purpose, use different background colors for different widgets.
Second you cannot set the width and height of a ttk::Frame using style.configure(), specify them in ttk::Frame(...).
Below is an modified example based on your code:
import tkinter as tk
from tkinter import ttk
def on_closing(root):
root.destroy()
root = tk.Tk()
root.geometry("400x400")
root.config(bg="cyan")
root.protocol("WM_DELETE_WINDOW", lambda: on_closing(root))
frame1 = tk.Frame(root, bg="red")
frame1.pack(expand="YES")
canvas = tk.Canvas(frame1, width=200, height=300, relief="sunken", bd=0, bg="green")
scroll_y = tk.Scrollbar(frame1, orient="vertical", command=canvas.yview, bg=canvas['background'])
scroll_y.pack(side="right", fill='y')
canvas.pack(side="top", expand='YES', fill='both')
canvas.configure(yscrollcommand=scroll_y.set)
s = ttk.Style()
s.configure("new.TFrame", background="blue")
msgFrame = ttk.Frame(canvas, style="new.TFrame", width=100, height=200) # set width and height
msgFrame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
canvas.create_window((0, 0), window=msgFrame, anchor="nw")
root.mainloop()
And the output:

How get a ScrollBar to work on Only Left Frame Using Canvas?

I am trying to get the ScrollBar to apply only to the LeftFrame.
When I use the Canvas setup the ScrollBar applies to the whole window.
Is there better way to setup a selectable long-list table?
Should I be using a listbox instead?
import tkinter as tk
root = tk.Tk()
root.geometry("1000x600")
# root.resizable(width=False, height=False)
def printname(event, i):
print ("my name is", i)
namelabel.configure(text="test" + str(i))
def onFrameConfigure(canvas):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
leftFrame = tk.Frame(canvas, background="#ffffff", width=700, height=500)
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="left", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((1,1), window=leftFrame, anchor="ne")
rightFrame = tk.Frame(root, background="#ffffff", width=300)
# vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
# canvas.configure(yscrollcommand=vsb.set)
# vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((1,2), window=rightFrame, anchor="nw")
# rightFrame = tk.Frame(root, width=400)
# rightFrame.pack()
leftFrame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
textlabel = tk.Label(leftFrame, text="Player List")
textlabel.grid(row=0)
for i in range(50):
if (i % 2):
w = tk.Text(leftFrame, height=1, fg="white", bg="black")
else:
w = tk.Text(leftFrame, height=1, fg="black", bg="white")
w.insert(1.0, "test" + str(i))
w.configure(relief="flat")
w.configure(state="disabled")
w.bind("<Button-1>", lambda event, a=i: printname(event, a))
w.grid(row=7+i)
namelabel = tk.Label(rightFrame, text="Test", fg="white", bg="black")
namelabel.grid(row=1)
root.mainloop()
The short answer is that if you don't want something to scroll, don't put it in the canvas. Scrolling a canvas means every item added to the canvas will scroll. There's no way to avoid that. You can't scroll half of a widget.
Is there better way to setup a selectable long-list table?
Probably, though it depends on the data you're wanting to show. If it's a list of short strings, a Listbox is probably a better choice. If it's blocks of text, a single text widget with some tags and custom bindings might be better than multiple widgets.

canvas on top of a grid tkinter

I want to put a canvas on top of a larger sized grid so that I can create buttons at the bottom of the canvas. Right now I have this:
class Canvas(Frame):
def __init__(self, root):
Frame.__init__(self, root)
self.display = Canvas(root, width=500, height=500, borderwidth=5, background='white')
self.display.pack()
root = Tk()
board = Canvas(root)
root.mainloop()
This creates a 500x500 white canvas. Now let's say I want to add something like a 500x600 grid to go under it. How would I do that?
You can just pack another frame under it, with height=100 and pack it with fill=X. Then you can put the Buttons in this new frame any way you want.
import Tkinter as tk
root = tk.Tk()
display = tk.Canvas(root, width=500, height=500, borderwidth=5, background='white')
display.pack()
button_frame = tk.Frame(root, height=100)
button_frame.pack(fill=tk.X)
button1 = tk.Button(button_frame, text='button1')
button1.pack(side=tk.LEFT)
button2 = tk.Button(button_frame, text='button2')
button2.pack(side=tk.LEFT)
root.mainloop()
Or, if you really want a grid, you can use the following code to place the Frame under the Canvas
display = tk.Canvas(root, width=500, height=500, borderwidth=5, background='white')
display.grid(column=0, row=0)
button_frame = tk.Frame(root, height=100)
button_frame.grid(column=0, row=1, sticky=tk.W+tk.E)
But if you place the Canvas with pack, don't try to put the frame in with grid. Use only one layout manager in root.

Categories

Resources