How can I insert label in a scrollable canvas? - python

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

Related

why my tkinter scrollbar not working after adding scrollbar?

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')))
...

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

Centering button using grid() in tkinter

I am simply trying to center some buttons in Python and it won't work even after looking at other a dozen threads.
This is my code at the moment:
import tkinter as tk
HEIGHT = 600
WIDTH = 1000
root = tk.Tk()
canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
canvas.pack()
frame = tk.Frame(root, bg='#000A01')
frame.place(relwidth=1, relheight=1)
button0 = tk.Button(frame, text="LEFT", relief='flat', justify='center', bg='#000A01', fg='#00A010', padx='35', width='0', font=('Monofonto', 18))
button0.grid(row=0, column=0)
button1 = tk.Button(frame, text="CENTER", relief='flat', justify='center', bg='#000A01', fg='#00A010', padx='35', width='0', font=('Monofonto', 18))
button1.grid(row=0, column=1)
button2 = tk.Button(frame, text="RIGHT", relief='flat', justify='center', bg='#000A01', fg='#00A010', padx='35', width='0', font=('Monofonto', 18))
button2.grid(row=0, column=2)
root.mainloop()
this is the output
outputofabovecode
I want all buttons to be centered in the middle of the window and if I were to add more buttons in the same row it would add more to the center.
To center a button using place:
place(relx=0.5, rely=0.5, anchor=CENTER).

How to make a widget occupy the same width as that of its master frame when using columnspan?

Given the following grid layout configuration:
It was generated through code:
from Tkinter import *
master = Tk()
frame1 = Frame(master, width=100, height=100, bg="red")
frame1.grid(sticky="nsew", columnspan=4)
frame2 = Frame(master, width=100, height=100, bg="blue")
frame2.grid()
frame3 = Frame(master, width=100, height=100, bg="green")
frame3.grid(row=1, column=1)
frame4 = Frame(master, width=100, height=100, bg="yellow")
frame4.grid(row=1, column=2)
frame4 = Frame(master, width=100, height=100, bg="purple")
frame4.grid(row=1, column=3)
master.mainloop()
I tried to insert a Entry in frame1 so it extends to the whole frame1 width with the following code:
e1 = Entry(frame1)
e1.grid(sticky="we", columnspan=4)
However, I have got the following result:
How can I make the Entry widget occupy the same width as the frame1?
The entry is inside frame1, so the grid it is in is completely unrelated to the grid in the root window.
Since you didn't tell tkinter what to do with extra space inside frame1, it left it unused. If you want the entry widget which is in column 0 to fill the frame, you need to give its column a weight.
frame1.grid_columnconfigure(0, weight=1)
If this is the only widget going in frame1, you might want to consider using pack since you can do it all in one line of code:
e1.pack(side="top", fill="x", expand=True)

Scrollbars for a .jpg image on a Tkinter Canvas in Python

I'm trying to make a jpeg on a canvas scrollable but I can't seem to get my scrollbars to work. Here's some example code:
from Tkinter import *
import Image, ImageTk
root = Tk()
frame = Frame(root, bd=2, relief=SUNKEN)
frame.grid_rowconfigure(0, weight=1)
frame.grid_columnconfigure(0, weight=1)
xscrollbar = Scrollbar(frame, orient=HORIZONTAL)
xscrollbar.grid(row=1, column=0, sticky=E+W)
yscrollbar = Scrollbar(frame)
yscrollbar.grid(row=0, column=1, sticky=N+S)
canvas = Canvas(frame, bd=0, xscrollcommand=xscrollbar.set, yscrollcommand=yscrollbar.set)
canvas.grid(row=0, column=0, sticky=N+S+E+W)
File = "jpg filepath here"
img = ImageTk.PhotoImage(Image.open(File))
canvas.create_image(0,0,image=img, anchor="nw")
xscrollbar.config(command=canvas.xview)
yscrollbar.config(command=canvas.yview)
frame.pack()
root.mainloop()
You need to tell the canvas what part of the drawing space to scroll. Use something like:
canvas.config(scrollregion=canvas.bbox(ALL))
More information can be found here: http://effbot.org/tkinterbook/canvas.htm#coordinate-systems

Categories

Resources