I have issue dealing with scrollbar in tkinter.
I enclosed Treeview and Scrollbar widgets inside a frame for easier grouping. The problem is that when I update the Treeview to display a table with many columns, the scroll bar suddenly disappears (scroll bar retains only when at most 3 columns are displayed).
window = tk.Tk()
window.minsize(800, 700)
window.geometry("800x700")
...
middle = tk.Frame(window)
middle.pack(fill='x', side='top')
#red background for visualizing only
middle.configure(background='red')
displayTable = ttk.Treeview(middle, show='headings', selectmode="browse")
displayTable.pack(side=tk.LEFT)
#style for the table
style = ttk.Style()
style.theme_use("clam")
style.map("Treeview")
style.configure("Treeview.Heading", font=("Consolas", 12))
style.configure("Treeview", rowheight=30)
tabScroll = ttk.Scrollbar(middle, orient=tk.VERTICAL, command=displayTable.yview)
displayTable.configure(yscrollcommand=tabScroll.set)
tabScroll.pack(side=tk.RIGHT, fill='y')
I want that the scroll bar widget will not disappear whenever I display tables with cols > 3. Any idea where is the issue? I dont want to use grid() since the main window is resizable.
Table with 2 columns:
Table with 6 columns:
Note: data in table are fictitious
EDIT: as requested, below are the two variants for the working example:
Table with 2 rows:
import tkinter as tk
from tkinter import ttk
window = tk.Tk()
window.minsize(800, 700)
window.geometry("800x700")
middle = tk.Frame(window)
middle.pack(fill='x', side='top')
#red background for visualizing only
middle.configure(background='red')
displayTable = ttk.Treeview(middle, show='headings', selectmode="browse")
displayTable.pack(side=tk.LEFT)
#headings
columns = ("id", "name")
displayTable['column'] = columns
displayTable.heading("# 1",text="id")
displayTable.heading("# 2",text="name")
#rows
for n in range(1, 100):
displayTable.insert('', tk.END, values=(n, f"Row entry{n}"))
#style for the table
style = ttk.Style()
style.theme_use("clam")
style.map("Treeview")
style.configure("Treeview.Heading", font=("Consolas", 12))
style.configure("Treeview", rowheight=30)
tabScroll = ttk.Scrollbar(middle, orient=tk.VERTICAL, command=displayTable.yview)
displayTable.configure(yscrollcommand=tabScroll.set)
tabScroll.pack(side=tk.RIGHT, fill='y')
window.mainloop()
Table with 4 rows:
import tkinter as tk
from tkinter import ttk
window = tk.Tk()
window.minsize(800, 700)
window.geometry("800x700")
middle = tk.Frame(window)
middle.pack(fill='x', side='top')
#red background for visualizing only
middle.configure(background='red')
displayTable = ttk.Treeview(middle, show='headings', selectmode="browse")
displayTable.pack(side=tk.LEFT)
#headings
columns = ("id", "name", "job", "number")
displayTable['column'] = columns
displayTable.heading("# 1",text="id")
displayTable.heading("# 2",text="name")
displayTable.heading("# 3",text="job")
displayTable.heading("# 4",text="number")
#rows
for n in range(1, 100):
displayTable.insert('', tk.END, values=(n, f"Row entry{n}", f"Job{n}", f"09-{n}"))
#style for the table
style = ttk.Style()
style.theme_use("clam")
style.map("Treeview")
style.configure("Treeview.Heading", font=("Consolas", 12))
style.configure("Treeview", rowheight=30)
tabScroll = ttk.Scrollbar(middle, orient=tk.VERTICAL, command=displayTable.yview)
displayTable.configure(yscrollcommand=tabScroll.set)
tabScroll.pack(side=tk.RIGHT, fill='y')
window.mainloop()
My goal is that to not suppress the scrollbar when the table displays more than 3 columns (in that specific window dimensions). Hope this helps.
Related
I am trying to color my tkinter treeview using tags but it doesn't work even tho I have followed a few tutorials and I think I am doing everything the right way.
self.sidebar_button_event()
self.ultimo = "Inventario"
self.cajas_frame = customtkinter.CTkTabview(self, height=250)
self.cajas_frame.add("Cajas")
self.cajas_frame.tab("Cajas").grid_columnconfigure(0, weight=1)
self.cajas_frame.tab("Cajas").grid_rowconfigure(0, weight=1)
self.cajas_frame.grid(row=0, column=1, padx=(20, 20), pady=(20, 20), sticky="new", columnspan=3)
self.setTablaCajas()
n = 0
for f in self.inventario.datosCajas():
if n % 2 == 0:
self.cajas.insert(parent='', index='end', iid=n, values=f, tags=('par',))
else:
self.cajas.insert(parent='', index='end', iid=n, values=f, tags=('impar',))
self.cajas.bind("<<TreeviewSelect>>", self.clickCajas)
n += 1
n = 0
self.cajas.tag_configure('par', background='orange', )
self.cajas.tag_configure('impar', background='purple')
Could it be because of me using customtkinter and tkinter?
PS: I already tried using Style.configure and it does change it's appearance, but it doesn't seem to work this way and I want odd and even rows to have a different color.
I used a working example to explain the color tag function for the rows:
# Source for base treeview https://www.pythontutorial.net/tkinter/tkinter-treeview/
# extendet with style and color line 11 to 13, 24, 33 to 38 and 60,61
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showinfo
root = tk.Tk()
root.title('Treeview demo')
root.geometry('620x200')
# style the widget
s = ttk.Style()
s.theme_use('clam')
# define columns
columns = ('first_name', 'last_name', 'email')
tree = ttk.Treeview(root, columns=columns, show='headings')
# define headings
tree.heading('first_name', text='First Name')
tree.heading('last_name', text='Last Name')
tree.heading('email', text='Email')
s.configure('Treeview.Heading', background="green3")
# generate sample data
contacts = []
for n in range(1, 100):
contacts.append((f'first {n}', f'last {n}', f'email{n}#example.com'))
# add data to the treeview AND tag the row color
i = 1
for contact in contacts:
i += 1
if i%2:
tree.insert('', tk.END, values=contact, tags = ('oddrow',))
else:
tree.insert('', tk.END, values=contact, tags = ('evenrow',))
def item_selected(event):
for selected_item in tree.selection():
item = tree.item(selected_item)
record = item['values']
# show a message
showinfo(title='Information', message=','.join(record))
tree.bind('<<TreeviewSelect>>', item_selected)
tree.grid(row=0, column=0, sticky='nsew')
# add a scrollbar
scrollbar = ttk.Scrollbar(root, orient=tk.VERTICAL, command=tree.yview)
tree.configure(yscroll=scrollbar.set)
scrollbar.grid(row=0, column=1, sticky='ns')
# style row colors
tree.tag_configure('oddrow', background='lightgrey')
tree.tag_configure('evenrow', background='white')
# run the app
root.mainloop()
Output:
I have the following code that generates a template using tkinter.
import os
from tkinter import *
from tkinter import ttk
from PIL import Image,ImageTk
root = Tk()
root.title("Template viewer")
root.geometry("1000x600")
root.resizable(False, False)
# Create A Main frame
main_frame = Frame(root)
main_frame.pack(fill=BOTH,expand=1)
#main_frame.configure(root,background='red') #overlapped with canvas so background color doesnt work
# Create Frame for X Scrollbar
sec = Frame(main_frame)
sec.pack(fill=X,side=BOTTOM)
# Create A Canvas inside the main frame
my_canvas = Canvas(main_frame,background='blue')
my_canvas.pack(side=LEFT,fill=BOTH,expand=1)
# Add A Scrollbars to Canvas
x_scrollbar = ttk.Scrollbar(sec,orient=HORIZONTAL,command=my_canvas.xview)
x_scrollbar.pack(side=BOTTOM,fill=X)
y_scrollbar = ttk.Scrollbar(main_frame,orient=VERTICAL,command=my_canvas.yview)
y_scrollbar.pack(side=RIGHT,fill=Y)
# Configure the canvas
my_canvas.configure(xscrollcommand=x_scrollbar.set)
my_canvas.configure(yscrollcommand=y_scrollbar.set)
my_canvas.bind("<Configure>",lambda e: my_canvas.config(scrollregion= my_canvas.bbox(ALL)))
# Create Another Frame INSIDE the Canvas
second_frame = Frame(my_canvas)
# Add that New Frame a Window In The Canvas
my_canvas.create_window((0,0),window= second_frame, anchor="nw")
lbltwo=Label(my_canvas, text="this is a template", fg='black', bg = 'red', font=("Helvetica", 16))
lbltwo.place(x=0, y=100, anchor = SW)
##add table to the frame
# Create an object of Style widget
style = ttk.Style()
style.theme_use('clam')
# Add a Treeview widget
tree = ttk.Treeview(my_canvas, column=("FName", "LName"), show='headings', height=5)
tree.column("# 1", anchor=CENTER, stretch=NO, width=490)
tree.heading("# 1", text="Column1")
tree.column("# 2", anchor=CENTER, stretch=NO, width=490)
tree.heading("# 2", text="Column2")
# Insert the data in Treeview widget
tree.insert('', 'end', text="1", values=('Entry1', 'file1'))
tree.insert('', 'end', text="1", values=('Entry2', 'file2'))
tree.place(x=0, y=250)
#add image path
img= (Image.open("/path/to/image/file/"))
resized_image= img.resize((500,400)) #Resize the Image using resize method
new_image= ImageTk.PhotoImage(resized_image)
my_canvas.create_image(500,900,anchor=CENTER, image=new_image) #Add image to the Canvas Items
#Add new rectangles to the canvas items
b1 = my_canvas.create_rectangle(0,600,1000,1100, outline="black")
root.mainloop()
It works well without any label or table widgets. But, as I add them they seem to scroll with the canvas and not fixed at their position (top of the page). This makes them overlap the stuff on the bottom of the page. Can anyone suggest how to make these added widgets fixed at specific positions?
I have a problem that I could not solve, thanks to many of you I was able to order the tree with the scrollbar, the problem now is that the scrollbar is always maximized, it does not calculate the amount of data that is inside.
frame = customtkinter.CTkFrame(self.wind, corner_radius=5)
frame.pack(expand="true")
button_llegue = customtkinter.CTkButton(master=frame, corner_radius=8,fg_color="IndianRed3",hover_color="IndianRed4", text='Llegue',command=self.add_fecha)
button_llegue.grid(row = 0, column = 0,pady=(20,10),padx=(15,15))
button_sali = customtkinter.CTkButton(master=frame, corner_radius=8,fg_color="PaleGreen3",hover_color="PaleGreen4", text='Me Voy',command=self.add_fecha)
button_sali.grid(row = 0, column = 1,pady=(20,10),padx=(15,15))
self.tree = ttk.Treeview(master=frame,height = 10, selectmode="browse")
self.tree.grid(row = 1,column=0,pady=(10,20),columnspan=2,sticky="NWSE",padx=(15,15))
self.tree.heading('#0', text = 'Ultimos registros', anchor = CENTER)
scrollbar = ttk.Scrollbar(frame,orient='vertical',command=self.tree.yview)
scrollbar.grid(row = 1, column=0, sticky="NSE",pady=(10,20),columnspan=2,padx=(0,15))
self.get_fechas()
Using command=self.tree.yview you send information from scrollbar to treeview - and it will scroll treeview when you will move scrollbar.
But you need also
self.tree.config(yscrollcommand=scrollbar.set)
to send information from treeview to scrollbar - and it will change size and position of scrollbar when you will add elements to treeview or when you will scroll treeview directly (using mouse wheel).
Minimal working code
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
tree = ttk.Treeview(root, selectmode="browse")
tree.pack(side='left', fill='both', expand=True)
scrollbar = tk.Scrollbar(root, orient='vertical', command=tree.yview)
scrollbar.pack(side='right', fill='y')
tree.config(yscrollcommand=scrollbar.set)
for x in range(1, 21):
print(tree.insert('', 'end', text=str(x)))
root.mainloop()
I want to put the horizontal and vertical scrollbars at the edge of the yellow canvas using Python tkinter, but whatever I do, it does not move and just stay inside the perimeter of the canvas. Why? Below is the image:
Below is the code:
def render_gui(self):
self.main_window = tk.Tk()
self.main_window.geometry("1000x600")
self.main_window.title("Damaged Text Document Virtual Restoration")
self.main_window.resizable(True, True)
self.main_window.configure(background="#d9d9d9")
self.main_window.configure(highlightbackground="#d9d9d9")
self.main_window.configure(highlightcolor="black")
self.main_canvas = tk.Canvas(self.main_window, bg = "yellow")
self.main_canvas.pack(expand = True, fill = "both")
vsb = tk.Scrollbar(self.main_canvas, orient="vertical", command=self.main_canvas.yview)
hsb = tk.Scrollbar(self.main_canvas, orient="horizontal", command=self.main_canvas.xview)
vsb.grid(row=1, column=50,columnspan = 20, sticky='ns')
hsb.grid(row=20, column=1,rowspan = 20,sticky = 'wes')
self.main_canvas.configure(yscrollcommand=vsb.set,xscrollcommand=hsb.set)
self.main_window.mainloop()
Please help.
The problem is that you are putting the scrollbars inside the canvas, and you've put nothing else in the canvas.
When you use grid to put something inside another widget, rows and columns that are empty have a size of zero. Thus, even though you put the vertical scrollbar in column 50, columns 0 and 2-49 have a width of zero so column 50 appears on the left. (Column 1 is the width of the horizontal scrollbar.)
The same is true for the horizontal scrollbar - you're putting it in row 20, but rows 0 and 2-19 have a height of zero, so row 20 appears near the top.
Normally it's not a good idea to put scrollbars inside the canvas, since anything you draw on the canvas might be hidden or partially hidden by the scrollbars. If you want them to appear to be in the canvas, the simplest solution is to put both the canvas and the scrollbars inside a frame. You can then turn the border off on the canvas and turn the border on for the frame.
Example:
import tkinter as tk
class Example():
def render_gui(self):
self.main_window = tk.Tk()
self.main_window.geometry("1000x600")
self.main_window.title("Damaged Text Document Virtual Restoration")
self.main_window.resizable(True, True)
self.main_window.configure(background="#d9d9d9")
self.main_window.configure(highlightbackground="#d9d9d9")
self.main_window.configure(highlightcolor="black")
canvas_container = tk.Frame(self.main_window, bd=1, relief='sunken')
canvas_container.pack(expand = True, fill = "both")
self.main_canvas = tk.Canvas(canvas_container, bg = "yellow")
vsb = tk.Scrollbar(canvas_container, orient="vertical", command=self.main_canvas.yview)
hsb = tk.Scrollbar(canvas_container, orient="horizontal", command=self.main_canvas.xview)
self.main_canvas.configure(yscrollcommand=vsb.set,xscrollcommand=hsb.set)
vsb.grid(row=0, column=1, sticky="ns")
hsb.grid(row=1, column=0, sticky="ew")
self.main_canvas.grid(row=0, column=0, sticky="nsew")
canvas_container.grid_rowconfigure(0, weight=1)
canvas_container.grid_columnconfigure(0, weight=1)
self.main_window.mainloop()
e = Example()
e.render_gui()
The code has the canvas as the parent to the scrollbars.
Setting the scrollbars to have the same parent as the canvas, and changing a few placement things around, renders something workable:
import tkinter as tk
class test:
def __init__(self):
self.render_gui()
def render_gui(self):
self.main_window = tk.Tk()
self.main_window.geometry("1000x600")
self.main_window.title("Damaged Text Document Virtual Restoration")
self.main_window.resizable(True, True)
self.main_window.configure(background="#d9d9d9")
self.main_window.configure(highlightbackground="#d9d9d9")
self.main_window.configure(highlightcolor="black")
self.main_canvas = tk.Canvas(self.main_window, bg = "yellow")
vsb = tk.Scrollbar(self.main_window, orient="vertical", command=self.main_canvas.yview)
hsb = tk.Scrollbar(self.main_window, orient="horizontal", command=self.main_canvas.xview)
hsb.pack(side = "bottom", fill = "x")
vsb.pack(side = "right", fill = "y")
self.main_canvas.pack(expand = True, fill = "both")
self.main_canvas.configure(yscrollcommand=vsb.set,xscrollcommand=hsb.set)
self.main_window.mainloop()
t = test()
from tkinter import *
from tkinter import scrolledtext
janela = Tk()
scroll_x = Scrollbar(janela, orient="horizontal")
text = scrolledtext.ScrolledText(janela, wrap=NONE)
text.config(xscrollcommand=scroll_x.set)
scroll_x.configure(command=text.xview)
text.pack(fill=X)
scroll_x.pack(fill=X)
janela.mainloop()
I am working on this table in tkinter made from a bunch of treeveiw widgets. The idea is to get a table where I can add lines, select lines and edit them. In the code below you can add lines to the table by pushing the button. I now want to control the height of each row by configuring the style. However, when I use style the alignment of the treeview widgets is messed up, see attached picture. Any suggestions how to fix this?
EDIT: The problem is the added space between the widgets.
The code for the table is:
from tkinter import *
from tkinter import ttk
class MyApp(Tk):
def __init__(self):
super(MyApp, self).__init__()
self.geometry('950x500+100+100')
self.NewTree = []
label = Label(self,text='Table with some data', font=("Arial Bold", 25))
label.pack()
self.addLine()
master_frame = Frame(self, bd=3, relief=RIDGE)
master_frame.pack(side=BOTTOM)
# Create a frame for the canvas and scrollbar(s).
frame2 = Frame(master_frame)
frame2.pack(side = BOTTOM)
# Add a canvas in that frame.
self.canvas = Canvas(frame2)
self.canvas.grid(row=0, column=0)
# Create a vertical scrollbar linked to the canvas.
vsbar = Scrollbar(frame2, orient=VERTICAL, command=self.canvas.yview)
vsbar.grid(row=0, column=1, sticky=NS)
self.canvas.configure(yscrollcommand=vsbar.set)
# Create a frame on the canvas to contain the buttons.
self.table_frame = Frame(self.canvas)
# Create canvas window to hold the buttons_frame.
self.canvas.create_window((0,0), window=self.table_frame, anchor=NW)
def addLine(self):
#Make button for adding step
bt = Button(self,text='Add Line',command=lambda: self.addLineMethod())
bt.config(width=9, height=1)
bt.pack()
def addLineMethod(self):
lineNumber = int(len(self.NewTree)/5)
for index in range(5):
s = ttk.Style()
s.configure('MyStyle.Treeview', rowheight=25)
self.NewTree.append(ttk.Treeview(self.table_frame, height=1,show="tree",columns=("0"),style='MyStyle.Treeview'))
#Works fine when using this line instead of those above
#self.NewTree.append(ttk.Treeview(self.table_frame, height=1,show="tree",columns=("0")))
self.NewTree[index+5*lineNumber].grid(row=lineNumber, column=index+1)
self.NewTree[index+5*lineNumber]['show'] = ''
item = str(index+5*lineNumber)
self.NewTree[index+5*lineNumber].column("0", width=180, anchor="w")
self.NewTree[index+5*lineNumber].insert("", "end",item,text=item,values=('"Text text text"'))
self.table_frame.update_idletasks() # Needed to make bbox info available.
bbox = self.canvas.bbox(ALL) # Get bounding box of canvas with Buttons.
# Define the scrollable region as entire canvas with only the desired
# number of rows and columns displayed.
self.canvas.configure(scrollregion=bbox, width=925, height=200)
app = MyApp()
app.mainloop()
Her is a picture of the table with some lines.
Put the style configuration in the __init__() function and the effect will go away. I'm not clear as to why this works.
def __init__(self):
...
s = ttk.Style()
s.configure('MyStyle.Treeview', rowheight=20)