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

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

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 in Tkinter

I tried many things to do 2 things :
center my content (horizontal)
have a scrollbar right and bottom
Here my code :
# encoding: utf8
from tkinter import *
from tkinter import ttk
class Program:
def __init__(self):
# Tk.__init__(self)
# Fill the content of the window
self.window = Tk()
self.window.geometry("1080x720")
self.createFrameWithScrollbar()
self.content()
def createFrameWithScrollbar(self):
# Create a Main Frame
self.mainFrame = Frame(self.window)
self.mainFrame.pack(fill=BOTH, expand=True)
# Create a canvas
self.canvas = Canvas(self.mainFrame)
self.canvas.pack(side=LEFT, fill=BOTH, expand=True)
# Add a scrobar
yScrollbar = ttk.Scrollbar(self.mainFrame, orient=VERTICAL, command=self.canvas.yview)
yScrollbar.pack(side=RIGHT, fill=Y)
xScrollbar = ttk.Scrollbar(self.mainFrame, orient=HORIZONTAL, command=self.canvas.xview)
xScrollbar.pack(side=BOTTOM, fill=X)
# Configure the canvas
self.canvas.configure(yscrollcommand=yScrollbar.set)
self.canvas.configure(xscrollcommand=xScrollbar.set)
self.canvas.bind('<Configure>', lambda e: self.canvas.configure(scrollregion = self.canvas.bbox("all")))
self.frame = Frame(self.canvas)
self.canvas.create_window((0,0), window=self.frame, anchor="nw")
self.currentFrame = Frame(self.frame)
self.currentFrame.configure(bg="red")
self.currentFrame.pack(fill=BOTH, expand=1)
def content(self):
label_title = Label(self.currentFrame, text="Title")
label_title.grid(column=0, row=0, sticky=NSEW)
label_description = Label(self.currentFrame, text="Title")
label_description.grid(column=0, row=1, sticky=NSEW)
label_version = Label(self.currentFrame, text="0.2 beta [Novembre 2020]")
label_version.grid(column=0, row=2, sticky=NSEW)
# Lauch the program
app = Program()
app.window.mainloop()
So the result is the following :
So any suggestion ?
The bottom sidebar is so small ! I don't know why.
Are regarding the text, it's not center at all ;(
I want to have it center and changing position if I rezize the window
Thanks a lot
pack works by allocating space along an entire empty side of the master, so the order of when you call pack matters. When you pack the canvas before packing the scrollbar, the canvas takes up the entire left side from top to bottom.
The simple solution is to pack the scrollbars before you pack the canvas.
yScrollbar.pack(side=RIGHT, fill=Y)
xScrollbar.pack(side=BOTTOM, fill=X)
self.canvas.pack(side=LEFT, fill=BOTH, expand=True)
To make the UI look a bit more professional, grid is usually a better choice when laying out scrollbars. With pack, either one edge of the horizontal scrollbar will be below the vertical scrollbar, or the edge of the vertical scrollbar will be directly beside the horizontal one. That, or you have to add a little bit of padding so the scrollbars don't seem to overlap.
When I have a scrollable widget, I almost always put it and the one or two scrollbars together in a frame using grid. Then, I can treat them all as if they were a single widget when adding them to the rest of the UI.
In a comment you ask about how to do it in a grid. You simply need to place the widgets in the appropriate rows and columns, and make sure that the row and column with the scrollable widget has a non-zero weight so any extra space is allocated to it.
self.mainFrame.grid_rowconfigure(0, weight=1)
self.mainFrame.grid_columnconfigure(0, weight=1)
yScrollbar.grid(row=0, column=1, sticky="ns")
xScrollbar.grid(row=1, column=0, sticky="ew")
self.canvas.grid(row=0, column=0, sticky="nsew")

scrollbar in Top level canvas

scrollbar in Top level window created for a canvas is not working and how do I get region of canvas. where canvas size varies with number of buttons in it
I have created frame in tk(root) and one widget in a frame creates Top level window , which has multiple Buttons in a Frame.Number of Button varies with list. That Frame(which has buttons in it) exists in a canvas. My problem is that after putting scroll widget canvas do not moves
from tkinter import *
root = Tk()
root.geometry("500x200")
my_app= Frame(root)
my_app.pack()
my_window = Toplevel(my_app, bg='brown')
my_window.geometry("500x200+300+500")
top_window = Frame(my_window, bd=2, relief=SUNKEN)
top_window.grid_columnconfigure(0, weight=1)
yscrollbar = Scrollbar(top_window)
yscrollbar.grid(row=0, column=1, sticky=N+S)
canvas = Canvas(top_window, bd=0, yscrollcommand=yscrollbar.set)
canvas.config(scrollregion=(0, 0, 500, 1000))
canvas.grid(row=0, column=0, sticky=N+S+E+W)
yscrollbar.config( command = canvas.yview)
top_window.pack()
my_f = Frame(canvas)
def ins_ind(m):
print(m)
results =
["one","two","three","four","five","six","seven","eight","nine","ten"]
ins_list=[]
for ind, result in enumerate(results):
ins=str(result)
ins_list.append(ind)
ins_list[ind] = Button(my_f, text = ins, font='Times 12 bold',
bg='sandy brown',anchor=E, fg="black", command = lambda m=ins:
ins_ind(m) )
ins_list[ind].pack()
my_f.pack()
root.mainloop()
Scroll bar do no moves
For the buttons to move when you scroll the canvas you must put the buttons on the canvas.
Your code puts the buttons on the frame my_f. To put the buttons on the canvas you should use: canvas.create_window(x, y, window=button).

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:

How to add two widgets in a tk.Frame located inside a tk.Canvas?

I'm trying to do a scrollable application with two buttons. Pressing one of those buttons should be put a new button in the Frame, and scroll the widgets inside the frame.
My question is how to put the two buttons in the frame?
when I try to put in the same Frame only I can see one button and only a small part of the other.
How to solve this?
from tkinter import * # from x import * is bad practice
global y
y=0
def _configure_interior(event):
print("hola")
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
canvas.config(scrollregion="0 0 %s %s" % size)
def newbutton():
buttons=Button(interior, text="Button ")
buttons.pack()
#b2.place(y=50)
root =Tk()
#configuring the Scrollbars
vscrollbar = Scrollbar(root, orient=VERTICAL)
vscrollbar.pack(fill=Y, side=RIGHT)
hscrollbar = Scrollbar(root, orient=HORIZONTAL)
hscrollbar.pack(fill=X, side=BOTTOM)
#setting canvas with scrollbar
canvas = Canvas(root,height=500, width=500, bg="blue",
yscrollcommand=vscrollbar.set,xscrollcommand=hscrollbar.set)
canvas.propagate(0)
vscrollbar.config(command=canvas.yview)
hscrollbar.config(command=canvas.xview)
canvas.pack()
#making a interior scrolleable frame
interior = Frame(canvas,bg='black',height=600,width=600)
interior.pack(side="top", fill="both", expand=True)
#adding some widgets to the Frame
b=Button(interior, text="Button 2",command=newbutton)
b.pack()
b2=Button(interior, text="Button 2",command=newbutton)
b2.pack()
b2.place(x=50,y=50)
interior_id = canvas.create_window(30,30, window=interior,
anchor=NW)
interior.bind('<Configure>', _configure_interior)
root.mainloop()
You have also used pack() to place the interior frame on the canvas, which does not work. I've commentet that line out in the code below. Also I've commented out the b2.place() as you should not use more tham one geometry manager in a frame.
#making a interior scrolleable frame
interior = Frame(canvas,bg='black',height=600,width=600)
#interior.pack(side="top", fill="both", expand=True)
interior_id = canvas.create_window(30,30, window=interior,
anchor=NW)
#adding some widgets to the Frame
b=Button(interior, text="Button 2",command=newbutton)
b.pack()
b2=Button(interior, text="Button 2",command=newbutton)
b2.pack()
#b2.place(x=50,y=50)
The new buttons are now packed into interior.

Categories