why my tkinter scrollbar not working after adding scrollbar? - python

I have made a user interface but my scrollbar is not working. it is working if i add content statically but when i add frames from button click then it adds new frame but not scrolling to view bottom content or we can say the scroll bar is disabled.
Here is my code:
import tkinter as tk
from tkinter import *
from PIL import ImageTk, Image
root = tk.Tk()
root.grid_rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
root.title("Hello Python")
root.configure(bg="#010523")
root.iconbitmap('logo.ico')
root.geometry("400x500")
frame_main = tk.Frame(root, bg="#010523")
frame_main.grid(sticky='news')
# ********************header frame********************************
header_frame = LabelFrame(frame_main, bg="#010523", border=0, height=100)
header_frame.grid(row=0, column=0, columnspan=2, sticky='ew')
width =50
height =50
photo= Image.open("logo.png")
photo= photo.resize((width, height),Image.ANTIALIAS)
# create an object of PhotoImage
photoImg = ImageTk.PhotoImage(photo)
photo_label= Label(header_frame, image=photoImg, bg="#010523")
photo_label.grid(row=0, column=0, rowspan=2)
# Label
public_broadcast = Label(header_frame, text="Public broadcast",
font="bold", bg="#010523", fg="white")
public_broadcast.grid(row=0, column=1)
_id = Label(header_frame, text="MY ID: 0013A20041EFD12C",
font="10", bg="#010523", fg="grey")
_id.grid(row=1, column=1, padx=10)
# ********************end of header frame*************************
# label1 = tk.Label(frame_main, text="Label 1", fg="green")
# label1.grid(row=0, column=0, pady=(5, 0), sticky='nw')
# label2 = tk.Label(frame_main, text="Label 2", fg="blue")
# label2.grid(row=1, column=0, pady=(5, 0), sticky='nw')
# label3 = tk.Label(frame_main, text="Label 3", fg="red")
# label3.grid(row=3, column=0, pady=5, sticky='nw')
# Create a frame for the canvas with non-zero row&column weights
frame_canvas = tk.Frame(frame_main)
frame_canvas.grid(row=2, column=0, pady=(5, 0), sticky='nw')
frame_canvas.grid_rowconfigure(0, weight=1)
frame_canvas.grid_columnconfigure(0, weight=1)
# Set grid_propagate to False to allow 5-by-5 buttons resizing later
frame_canvas.grid_propagate(False)
# Add a canvas in that frame
canvas = tk.Canvas(frame_canvas, bg="yellow")
canvas.grid(row=0, column=0, sticky="news")
# Link a scrollbar to the canvas
vsb = tk.Scrollbar(frame_canvas, orient=VERTICAL, command=canvas.yview)
vsb.grid(row=0, column=1, sticky='ns')
canvas.configure(yscrollcommand=vsb.set)
# Create a frame to contain the buttons
frame_buttons = tk.Frame(canvas, bg="blue")
# Add 9-by-5 buttons to the frame
last_frame_row = 3
frame_canvas.config(width=400, height=300)
# Entering self msg frame with text
def add_msg_frame():
global last_frame_row
msg = "This is a test msg"
# msg = e.get()
# e.delete(0, END)
new_frame = Frame(frame_buttons, bg="#4857a8", borderwidth=0)
new_frame.grid(row=last_frame_row, column=1, columnspan=2, sticky='e', pady=5)
last_frame_row += 1
new_label = Label(new_frame, text=msg, font="10", bg="#4857a8", fg="white")
new_label.grid(row=0, column=0)
canvas.create_window((0, 0), window=frame_buttons, anchor='nw')
def add_reply_msg(device_id="0983ADFCD9827sd", msg="this is a sample message"):
global last_frame_row
new_frame = Frame(frame_buttons, bg="#1f243f", borderwidth=0)
new_frame.grid(row=last_frame_row, column=0, columnspan=2, sticky='w', pady=5)
last_frame_row += 1
new_label = Label(new_frame, text=device_id, bg="#1f243f", font="10", fg="#a6a6a6")
new_label.grid(row=0, column=0)
new_label2 = Label(new_frame, text=msg, font="10", bg="#1f243f", fg="white")
new_label2.grid(row=1, column=0)
# Update buttons frames idle tasks to let tkinter calculate buttons sizes
# for i in range(30):
# add_msg_frame()
add_reply_msg()
add_reply_msg()
add_msg_frame()
frame_buttons.update_idletasks()
# Set the canvas scrolling region
canvas.config(scrollregion=canvas.bbox("all"), yscrollcommand=vsb.set)
canvas.create_window((0, 0), window=frame_buttons, anchor='nw')
canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
# # Entry
eFrame = Frame(root, width=400, height=100)
eFrame.grid(row=1000, column=0)
e = Entry(eFrame, width=50)
e.grid(row=0, column=0)
ebtn = Button(eFrame, text="Send", bg="skyblue", command=add_msg_frame)
ebtn.grid(row=0, column=1)
# Launch the GUI
root.mainloop()
Please give me suggestions that how can i enable scrollbar when add a frame by clicking the send button.
Thank you.

You need to update the scrollregion whenever you add or modify things on the canvas.

frame_buttons will be resized when items are added to it, so you need to update the scrollregion of the canvas in this case via bind('<Configure>', ...). Also it is better to call canvas.create_window((0, 0), window=frame_buttons, anchor='nw') once outside the function add_msg_frame():
...
# Create a frame to contain the buttons
frame_buttons = tk.Frame(canvas, bg="blue")
# call canvas.create_window(...) once here
canvas.create_window((0, 0), window=frame_buttons, anchor='nw')
# update scrollregion of canvas whenever the frame is resized
frame_buttons.bind('<Configure>', lambda e: canvas.config(scrollregion=canvas.bbox('all')))
...

Related

How to add a Scrollbar on the main window when only Label and Button are used

I know how to add a scrollbar on a tkinter window, frame, canvas.
I also know how to do it on a listbox.
Problem is, I have a window that doesn't have any of those, and only use Label and Button:
from tkinter import *
test1 = 100
test2 = 100
test3 = 100
test4 = 100
root = Tk()
root.title("Program")
root.geometry('350x250')
# first group of labels & buttons
label = Label(root, text="test1")
label.grid(row=0, column=0, columnspan=2)
label = Label(root, text=test1)
label.grid(row=1, column=0, columnspan=2)
button = Button(root, text="Up")
button.grid(row=2, column=0)
button = Button(root, text="Down")
button.grid(row=2, column=1)
#
label = Label(root, text="test2")
label.grid(row=3, column=0, columnspan=2)
label = Label(root, text=test2)
label.grid(row=4, column=0, columnspan=2)
button = Button(root, text="Up")
button.grid(row=5, column=0)
button = Button(root, text="Down")
button.grid(row=5, column=1)
#
label = Label(root, text="test3")
label.grid(row=6, column=0, columnspan=2)
label = Label(root, text=test3)
label.grid(row=7, column=0, columnspan=2)
button = Button(root, text="Up")
button.grid(row=8, column=0)
button = Button(root, text="Down")
button.grid(row=8, column=1)
#
label = Label(root, text="test4")
label.grid(row=9, column=0, columnspan=2)
label = Label(root, text=test4)
label.grid(row=10, column=0, columnspan=2)
button = Button(root, text="Up")
button.grid(row=11, column=0)
button = Button(root, text="Down")
button.grid(row=11, column=1)
root.mainloop()
The above has a small window resolution on purpose, because, while it may work in maximizing the window, once there are too many Label's text or Button, then a Scrollbar will be needed. This is intended to test that.
How can I add a scrollbar to the above code?
You need a scrollable frame. See example here: https://gist.github.com/mp035/9f2027c3ef9172264532fcd6262f3b01
And for buttons and labels, instead of using root as parent, use the scrollable frame as parent. For example:
from tkinter import *
c1 = "#999999"
c2 = "#000000"
class ScrollFrame(Frame):
"""
A simple scrollable frame class for tkinter
Source: https://gist.github.com/mp035/9f2027c3ef9172264532fcd6262f3b01
"""
def __init__(self, parent):
# create a frame (self)
super().__init__(parent, background=c1)
# place canvas on self
self.canvas = Canvas(
self, bd=0, bg=c1, relief="flat", highlightthickness=0
)
# place a frame on the canvas, this frame will hold the child widgets
self.viewPort = Frame(self.canvas, background=c1)
self.viewPort.grid_columnconfigure(0, weight=1)
# place a scrollbar on self
self.vsb = Scrollbar(self, orient="vertical", command=self.canvas.yview)
# attach scrollbar action to scroll of canvas
self.canvas.configure(yscrollcommand=self.vsb.set)
# pack scrollbar to right of self
self.vsb.pack(side="right", fill="y")
# pack canvas to left of self and expand to fil
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas_frame = self.canvas.create_window(
(0, 0),
window=self.viewPort,
anchor="nw", # add view port frame to canvas
tags="self.viewPort",
)
# bind an event whenever the size of the viewPort frame changes.
self.viewPort.bind("<Configure>", self.onFrameConfigure)
self.canvas.bind("<Configure>", self.FrameWidth)
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
def _on_mousewheel(self, event):
self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
def FrameWidth(self, event):
canvas_width = event.width
self.canvas.itemconfig(self.canvas_frame, width=canvas_width)
def onFrameConfigure(self, event):
"""Reset the scroll region to encompass the inner frame"""
# whenever the size of the frame changes, alter the scroll region respectively.
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
tests = [100, 99, 98, 101]
root = Tk()
root.title("Program")
root.geometry('350x250')
scroll_frame = ScrollFrame(root)
for i, testi in enumerate(tests):
# grouping labels and buttons together in a subframe
# so that the row numbers of the labels and buttons
# are always 0 to 2 within the sub-frame
f1 = Frame(scroll_frame.viewPort)
# first group of labels & buttons
label = Label(f1, text=f"test{i}")
label.grid(row=0, column=0, columnspan=2)
label = Label(f1, text=testi)
label.grid(row=1, column=0, columnspan=2)
button = Button(f1, text="Up")
button.grid(row=2, column=0)
button = Button(f1, text="Down")
button.grid(row=2, column=1)
# defining this group to have 2 columns with equal weight
f1.grid_columnconfigure(0, weight=1)
f1.grid_columnconfigure(1, weight=1)
# expand this sub-frame horizontally to it's parent, sticking to West and East of parent frame
f1.grid(sticky="we", ipadx=2)
# adding a separator
Frame(f1, height=1, background=c2).grid(
sticky="we", pady=5, padx=5, columnspan=2
)
# expand the scroll_frame in all 4 directions to fill the parent frame, sticking to West, East, North and South of parent frame
scroll_frame.grid(sticky="wens", row=0, column=0)
# set root frame only has 1 column (filled by scroll_frame)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
I recently stumbled on an easier way to do that (also use less code to do so):
import tkinter as tk
root = tk.Tk()
text = tk.Text(wrap="none")
vsb = tk.Scrollbar(orient="vertical", command=text.yview)
text.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
text.pack(fill="both", expand=True)
for i in range(30):
test1 = "test" + str(i)
test2 = "Button" + str(i)
c = tk.Label(text=test1)
k = tk.Label(text=i)
b = tk.Button(text=test2)
d = tk.Button(text=test2)
text.window_create("end", window=c)
text.insert("end", "\n")
text.window_create("end", window=k)
text.insert("end", "\n")
text.window_create("end", window=b)
text.window_create("end", window=d)
text.insert("end", "\n")
text.configure(state="disabled")
root.mainloop()
This is based on this answer. It doesn't use a canvas.
There is also another similar answer to the one I accepted on this post, here.

layout buttons within frame nested in tkk.Notebook

I can't properly layout buttons within frame nested in tkk.Notebook
In Main.py I create ttk.Notebook and attach mainTab instance
root = tk.Tk()
rootFrame = tk.Frame(root, width=600, height=300)
rootFrame.grid(columnspan=1, rowspan=2)
rootFrame.pack(expand=1, fill="both")
tabs = ttk.Notebook(rootFrame)
tabs.grid(column=0, row=1, columnspan=1, rowspan=1)
mainTab = ttk.Frame(tabs)
mainTab.grid(columnspan=3, rowspan=6)
tabs.add(mainTab, text="Main")
rootFrame.pack(expand=1, fill="both")
mainPane = MainTab(root,mainTab)
root.mainloop()
in mainTab.py I'm trying to insert buttonFrame and layout two buttons within it
class MainTab:
...
def __init__(self, root, mainTab) -> None:
self.root = root
buttonFrame = tk.Frame(mainTab, bg="white")
buttonFrame.grid(column=0, row=4, columnspan=3, rowspan=1)
self.start_btn = tk.Button(buttonFrame, text="Start", command=lambda:self.start_timer(), font=BUTTON_FONT, bg="green", fg="white") # , height=1, width=14
self.start_btn.grid(column=0, row=0, columnspan=2)
self.reset_btn = tk.Button(buttonFrame, text="X", command=lambda:self.reset_timer(), font=BUTTON_FONT, bg="green", fg="white") # , height=1, width=1
self.reset_btn.grid(column=2, row=0)
...
As a result start button is not properly placed in the grid
It looks like buttonFrame takes full parent frame width and buttons placed in the middle regardless of their grid settings.
How I can properly layout buttons within buttonFrame?
Here is the requested "minimal reproducible example" which also look not good
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Time Tracker")
root.iconbitmap('./assets/logoTransp4icon24.ico')
rootFrame = tk.Frame(root, width=600, height=300)
rootFrame.grid(columnspan=1, rowspan=2)
rootFrame.pack(expand=1, fill="both")
tabs = ttk.Notebook(rootFrame)
tabs.grid(column=0, row=1, columnspan=1, rowspan=1)
mainTab = ttk.Frame(tabs)
mainTab.grid(columnspan=3, rowspan=6)
buttonFrame = tk.Frame(mainTab, bg="white")
buttonFrame.grid(column=0, row=4, columnspan=3, rowspan=1)
start_btn = tk.Button(buttonFrame, text="Start", command=lambda:self.start_timer(), font="Arial", bg="green", fg="white") # , height=1, width=14
start_btn.grid(column=0, row=0, columnspan=2)
reset_btn = tk.Button(buttonFrame, text="X", command=lambda:self.reset_timer(), font="Arial", bg="green", fg="white") # , height=1, width=1
reset_btn.grid(column=2, row=0)
timerDisplay = tk.Label(mainTab, text="00:00:00", font="Arial")
timerDisplay.grid(columnspan=2, column=1, row=4)
tabs.add(mainTab, text="Main")
rootFrame.pack(expand=1, fill="both")
root.mainloop()
buttonFrame occupies column 0 to 2 and timerDisplay occupies column 1 to 2. So timerDisplay overlaps buttonFrame. Removing columnspan=3 in buttonFrame.grid(...) can fix the overlapping issue:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Time Tracker")
root.iconbitmap('./assets/logoTransp4icon24.ico')
rootFrame = tk.Frame(root, width=600, height=300)
#rootFrame.grid(columnspan=1, rowspan=2) # override by below line
rootFrame.pack(expand=1, fill="both")
tabs = ttk.Notebook(rootFrame)
tabs.grid(column=0, row=1, rowspan=1)
mainTab = ttk.Frame(tabs)
#mainTab.grid(columnspan=3, rowspan=6) # not necessary
buttonFrame = tk.Frame(mainTab, bg="white")
buttonFrame.grid(column=0, row=4, rowspan=1) # removed columnspan=3
start_btn = tk.Button(buttonFrame, text="Start", command=lambda:self.start_timer(), font="Arial", bg="green", fg="white") # , height=1, width=14
start_btn.grid(column=0, row=0, columnspan=2)
reset_btn = tk.Button(buttonFrame, text="X", command=lambda:self.reset_timer(), font="Arial", bg="green", fg="white") # , height=1, width=1
reset_btn.grid(column=2, row=0)
timerDisplay = tk.Label(mainTab, text="00:00:00", font="Arial")
timerDisplay.grid(columnspan=2, column=1, row=4)
tabs.add(mainTab, text="Main")
#rootFrame.pack(expand=1, fill="both") # already called above
root.mainloop()

Tkinter, alignment - the endless question

Since some days I'll try to align these two items inside a Tkinter frame:
The pink part should be on the left and the green button on the right. With HtmlDivs and CSS a question of seconds, with TKinter a pain in the ...
Here is my python code:
import tkinter as tk
root = tk.Tk()
root.geometry("400x200")
buttons = tk.Frame(root)
buttons.pack(side="top", expand=True, fill='both')
label = tk.Label(buttons, text="Hello, world", anchor='w', background='pink')
b2 = tk.Button(buttons, text="EXIT", background='green')
label.grid(row=0, column=1, sticky='w', ipadx = '20', padx = '20')
b2.grid(row=0, column=3, sticky='e', ipadx = '20', padx = '20')
root.mainloop()
The final app will be running fullscreen on a 7" touch display.
The simplest solution is to use pack instead of grid, since you only have a single row of widgets inside of buttons. pack's strength is arranging things in a single row or a single column.
Just remove these two lines:
label.grid(row=0, column=1, sticky='w', ipadx = '20', padx = '20')
b2.grid(row=0, column=3, sticky='e', ipadx = '20', padx = '20')
... and replace them with this:
label.pack(side='left')
b2.pack(side='right')
Also, since you appear to be creating a toolbar, you want to leave expand as False and set fill to just "x", otherwise the toolbar will expand to fill the entire window:
buttons.pack(side="top", expand=False, fill='x')
Thx for your tips,
this is just a testcode to update my maincode.
Its not good to mix .pack and .grid, right ? If i do, the script crashes completely,
so ill have to re-do my mainscript i think.
This is what i need:
row: 1/2: label (it will be a real time clock) left 2/2: exit button (exit fullscreen) right
row: 1/3: image (weather), 2/3: weather data (label), 3/3: calendar
row: 4 buttons: 1. lightoff 2. light25%, 3.light50% 4.light100&
Thats it basically all is working, it just need to align it (im a coding hero g)
Since i have the frame from the code above, i thought i can easily add 2. & 3. row with another frames, but that does not seem to work ??
Preview:
https://i.stack.imgur.com/KzoqV.png
My (main)Code so far
root = Tk()
root.title('Model Definition')
root.config(background = "deepskyblue4")
root.attributes('-fullscreen',True)
root.bind('<Escape>',lambda e: root.destroy())
def currenttime():
string = strftime("%A, %d.%B.%Y %H:%M:%S")
lbl.config(text = string, background = 'deepskyblue4', fg='white', font=("colibri", 30))
lbl.after(1000, currenttime)
def light400():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 401'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
def light425():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 425'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
def light450():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 450'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
def light475():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 500'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
# Main frames
top_frame = Frame(root, bg='deepskyblue4', width=450, height=90, pady=3)
center = Frame(root, bg='deepskyblue2', width=50, height=40, padx=3, pady=3)
btm_frame = Frame(root, bg='deepskyblue4', width=450, height=20, pady=3)
btm_frame2 = Frame(root, bg='deepskyblue4', width=450, height=60, pady=3)
# layout all of the main containers
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
top_frame.grid(row=0, sticky="e", padx=(10, 0))
center.grid(row=1, sticky="nsew", pady=(10, 50))
btm_frame.grid(row=3, sticky="ew")
btm_frame2.grid(row=4, sticky="ew", padx=(10, 50))
# create the widgets for the top frame
lbl = Label(top_frame, background = 'deepskyblue4', anchor=W, justify=LEFT)
lbl.pack()
currenttime()
actionbutton = Button(top_frame, text="X", width=5, height=2, bg="deepskyblue4", fg="white", command=root.destroy)
hdr_left = Frame(top_frame, bg='deepskyblue4', width=100, height=190)
hdr_right = Frame(top_frame, bg='deepskyblue4', width=400, height=190, padx=3, pady=3)
# layout the widgets in the top frame
lbl.grid(row=0, column=1, sticky="w")
actionbutton.grid(row=0, column=2, sticky="e")
# create the center widgets
center.grid_rowconfigure(0, weight=1)
center.grid_columnconfigure(1, weight=1)
ctr_left = Frame(center, bg='deepskyblue2', width=100, height=190)
ctr_mid = Frame(center, bg='deepskyblue2', width=150, height=190, padx=3, pady=3)
ctr_right = Frame(center, bg='deepskyblue2', width=400, height=190, padx=3, pady=3)
ctr_left.grid(row=0, column=0, sticky="ns")
ctr_mid.grid(row=0, column=1, sticky="nsew")
ctr_right.grid(row=0, column=2, sticky="ns")
path = "icons/rain.png"
img = ImageTk.PhotoImage(Image.open(path))
panel = Label(ctr_left, image = img, bg="deepskyblue2")
panel.grid(row=0, columnspan=3)
#imgag = panel.pack(top_frame)
#CENTER ctr_mid
if x["cod"] != "404":
y = x["main"]
y2 = x["wind"]
currenttemp = y["temp"]
currentpressure = y["pressure"]
currenthumidiy = y["humidity"]
z = x["weather"]
weather_description = z[0]["description"]
currentwind = y2["speed"]
label1 = Label(ctr_mid,text='Karlsruhe', font = ('calibri', 30), background = 'deepskyblue2')
label2 = Label(ctr_mid,text='Temperatur: '+str(round(currenttemp-272.15))+' °C', font = ('calibri', 20), background = 'deepskyblue2')
label3 = Label(ctr_mid,text='Beschreibung: '+str(weather_description),font = ('calibri', 20), background = 'deepskyblue2')
label4 = Label(ctr_mid,text='Druck: '+str(currentpressure)+' hPa', font = ('calibri', 20), background = 'deepskyblue2')
label5 = Label(ctr_mid,text='Feuchtigkeit: '+str(currenthumidiy)+' %',font = ('calibri', 20), background = 'deepskyblue2')
label6 = Label(ctr_mid,text='Wind: '+str(currentwind)+' m/Sek',font = ('calibri', 20), background = 'deepskyblue2')
label1.grid(row=0, column=0, sticky="nw")
label2.grid(row=1, column=0, sticky="nw")
label3.grid(row=2, column=0, sticky="nw")
label4.grid(row=3, column=0, sticky="nw")
label5.grid(row=4, column=0, sticky="nw")
label6.grid(row=5, column=0, sticky="nw")
# btm_frame2 widgets
licht = Label(btm_frame2, text='Licht:', width=5, height=1, bg="deepskyblue4", fg='white', font=("colibri", 20))
button = Button(btm_frame2, command=light400, text="AUS", width=5, height=1, bg="deepskyblue2", fg="white")
button2 = Button(btm_frame2, text="25 %", command=light425, width=5, height=1, bg="deepskyblue2", fg="white")
button3 = Button(btm_frame2, text="50%", command=light450, width=5, height=1, bg="deepskyblue2", fg="white")
button4 = Button(btm_frame2, text="100%", command=light475, width=5, height=1, bg="deepskyblue2", fg="white")
licht.grid(row=0, column=0, sticky="nw")
button.grid(row=0, column=1, sticky="nw")
button2.grid(row=0, column=2, sticky="nw")
button3.grid(row=0, column=3, sticky="nw")
button4.grid(row=0, column=4, sticky="nw")
actionbutton.grid(row=0, column=6, sticky="nw")
root.mainloop()

How can I insert label in a scrollable canvas?

The scroll don't work at all. What's wrong in the code?
I'm using Python 2.7.16
I read that listbox and text widgets are used only for text. As I want to use labels, I'm trying to insert the labels in a frame, but as a Frame didn't scroll I decided to use a canvas. But I couldn't get it to work.
from Tkinter import *
root = Tk()
frame = Frame(root, width=300, height=200)
frame.grid(row=0, column=0)
canvas=Canvas(frame, bg='#FFFFFF', width=300, height=200, scrollregion=(0,0,500,500))
vbar = Scrollbar(frame, orient=VERTICAL)
vbar.pack(side=RIGHT, fill=Y)
canvas.config(width=300, height=250)
canvas.pack(side=LEFT, expand=True, fill=BOTH)
mylist = Frame(canvas, width=100)
for x in range(10):
texto = Label(mylist, text='CODE', bd=2, width=7, relief=RIDGE)
texto.grid(row=x, column=0)
texto1 = Label(mylist, text='EQUIPAMENT', bd=2, width=20, relief=RIDGE)
texto1.grid(row=x, column=1)
mylist.place(x=0, y=0)
vbar.config(command=canvas.yview)
canvas.config(yscrollcommand=vbar.set)
mainloop()

Scrollbars on canvas in tkinter does not work

Yes there are many stackoverflow questions regarding this, i saw everything but could not get this working so i am asking a new question with my code:
Basically i want to create a table in tkinter with 4 columns. But i want to be able to scroll this because the rows will be later taken from the mysql database. but i cannot get the scroll working.
Here is my code :
from tkinter import *
root = Tk()
root.geometry("700x600")
frame_canvas = Frame(root)
frame_canvas.rowconfigure(0, weight=1)
frame_canvas.columnconfigure(0, weight=1)
frame_canvas.grid(row=0, column=0, sticky="news")
canvas = Canvas(frame_canvas)
canvas.grid(row=0, column=0, sticky="news")
vsb = Scrollbar(frame_canvas, orient="vertical", command=canvas.yview)
vsb.grid(row=0, column=1, sticky='ns')
canvas.configure(yscrollcommand=vsb.set)
for i in range(0, 50):
for j in range(0, 4):
canvas.columnconfigure(j, minsize=150)
Label(canvas, text="hello"+str(i)+str(j)).grid(row=i, column=j)
canvas.config(scrollregion=canvas.bbox("all"))
app = root
root.mainloop()
How to i get the canvas to scroll ? Is there another way to create a table ? Also later if i want to add a row to the bottom of the table, how is it possible ? or do i have to clear the whole canvas and re-render it or something ?
EDIT
Have added a frame window to the canvas. Still scroll won't work. That could be the issue now ?
from tkinter import *
root = Tk()
root.geometry("700x600")
frame_canvas = Frame(root)
frame_canvas.rowconfigure(0, weight=1)
frame_canvas.columnconfigure(0, weight=1)
frame_canvas.grid(row=0, column=0, sticky="news")
canvas = Canvas(frame_canvas, height=600, width=500)
canvas.grid(row=0, column=0, sticky="news")
vsb = Scrollbar(frame_canvas, command=canvas.yview, orient="vertical")
vsb.grid(row=0, column=1, sticky='ns')
canvas.configure(yscrollcommand=vsb.set)
frame2 = Frame(canvas, bg="powder blue", height=600, width=700)
canvas.create_window((0, 0), anchor="nw", height=600, width=600, window=frame2)
for i in range(0, 50):
for j in range(0, 4):
frame2.columnconfigure(j, minsize=120)
Label(frame2, bg="powder blue", text="hello"+str(i)+str(j)).grid(row=i, column=j)
canvas.config(scrollregion=frame2.bbox("all"))
app = root
root.mainloop()

Categories

Resources