I have a Tkinter Treeview with a header row. I am using the following style to style the header.
style = tk.ttk.Style()
style.theme_use('clam')
style.configure('Treeview.Heading', font=('Calibri', 10,'bold'))
style.map('Treeview', background=[('selected', 'blue')])
But I want the table to have just a title saying "INVOICES" and I do not want the separators in the header separating the columns, as seen in the photo below.
Is there a way to get rid of these separators?
Bonus points if you you can help me get the scrollbar to actually look like a scrollbar instead of being full (there are over 100 records in this test table).
Here is the rest of the code to place the treeview into a frame.
self.invoice_frame = tk.Frame(self, border=1, relief=tk.GROOVE, bg='white')
self.invoice_frame.place(relx=0.3, rely=row_3_top, relwidth=0.3425, relheight=0.3)
self.invoice_tree = tk.ttk.Treeview(self.invoice_frame, column=('c1', 'c2', 'c3'), show='headings')
self.invoice_tree.pack(side='left', fill='both', expand=True)
tree_scrollbar = tk.ttk.Scrollbar(self.invoice_frame, orient='vertical', command=self.invoice_tree.yview)
tree_scrollbar.pack(side='right', fill='y')
self.invoice_tree.column('c1', minwidth=40, width=100, anchor=tk.CENTER)
self.invoice_tree.heading('c1', text='')
self.invoice_tree.column('c2', minwidth=40, width=100, anchor=tk.CENTER)
self.invoice_tree.heading('c2', text='INVOICES')
self.invoice_tree.column('c3', minwidth=40, width=100, anchor=tk.CENTER)
self.invoice_tree.heading('c3', text='')
# adding random info
contacts = []
for n in range(1,100):
contacts.append((f'first {n}', f'last {n}', f'test{n}'))
for contact in contacts:
self.invoice_tree.insert('', tk.END, values=contact)
Thanks
You can set the relief style option to none to remove the separators.
style.configure('Treeview.Heading', font=('Calibri', 10,'bold'), relief='none')
For the scrollbar issue, you need to configure yscrollcommand option of the treeview:
self.invoice_tree.config(yscrollcommand=tree_scrollbar.set)
Related
I want to make a window to display data stored inside dictionaries. I have created a canvas, scrollbar and a frame inside the canvas to place my Text widgets to display the information. When I execute my code the layout is just as I want it, but the bar is missing from the scroll bar and I can't figure out why. Here is my code for the GUI portion:
root = Tk()
# create top part
top=Frame(root)
# create a canvas to scroll
holder = Canvas(top)
# create scroll bar
scroll = Scrollbar(top, orient=VERTICAL, command=holder.yview)
# configure scrollbar for canvas
holder.configure(yscrollcommand=scroll.set)
holder.bind('<Configure>', lambda e: holder.configure(scrollregion=holder.bbox("all")))
# create frame for content inside canvas and add it to the canvas
content = Frame(holder, relief=RAISED)
holder.create_window(0, 0, window=content, anchor='nw')
# create bottom part
bottom = Frame(root, relief=SUNKEN)
root.rowconfigure(0, weight=18)
root.rowconfigure(1, weight=1, minsize=50)
root.columnconfigure(0, weight=1)
holder.pack(side=LEFT, fill=BOTH, expand=1)
scroll.pack(side=RIGHT, fill=Y)
content.pack(fill=X)
top.grid(row=0, column=0, sticky='NSEW')
bottom.grid(row=1, column=0, sticky='NSEW')
num=0
for site in sites:
temp=Text(content, height = 5)
temp.configure(state= DISABLED)
temp.pack(fill=X, side=TOP, padx= 5, pady= 5)
siteBoxes.append(temp)
num += 1
root.mainloop()
here is a screenshot of what the result looks like
Program GUI screenshot
there are that many text boxes there just to test the scrollbar, the data display within the Text widgets haven't been written yet.
I found the culprit, it was the line content.pack(fill=X), since I already have it in the window of the canvas this line of code was causing the issue. How ever now the Text widget no longer spans all of the horizontal space, how would I fix this issue while still using .create_window()?
I have a tkinter window with several images that use grid. I tried to grid a scrollbar to the right side of the window but don't know what options to use because "side = right", "fill = Y" cannot be used inside grid. Any suggestions?
Grid is row / column oriented. So each widget needs its row and column in the geometry manager set. Here is a demo that answers the question posed.
# create a widget and scrollbar
import tkinter as tk
root = tk.Tk()
text = tk.Text(root)
vs = tk.Scrollbar(root, command=text.yview)
text.configure(yscrollcommand=vs.set)
# set the row, column and expansion for each widget
text.grid(row=0, column=0, sticky='news')
vs.grid(row=0, column=1, sticky='news')
# now make the grid manager expand to fill the available space in root.
# making 0, 0 expand to use all the spare space and 0,1 be fixed
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
If you are managing a set of images on label widgets then put them in a frame to separate out the geometry management of those. You might want to consider if you should
put them into a canvas instead which has quite good scrolling support.
I have read a number of threads and other resources to try to find the correct way to handle this but I have not found anything that works with my application.
Here is what I am trying to accomplish.
When a query is completed and the insert of the data to a Listbox is done I cannot seem to get it to margin the data insert by 1 character space.
I am using pack() and I have read the tkinter manual for this and have tried each example available along with others found on various threads here.
The widget:
output = tkinter.Listbox(window_2, height = 20, font='Times 10',
width=42, bd=1, bg = '#FFD599', fg = '#9A0615', selectmode=SINGLE)
output.pack()
output.place(x=210, y=195)
I have tried padx and pady with pack() without success, although this works successfully with the Text widget. I have also attempted to use a few alternatives that I have found here on the site but all without success in margining the Listbox when the data is inserted.
Any advice?
pack's padx/pady and ipadx/ipady options don't affect the data that is inside the listbox. The listbox itself doesn't have any options to add an internal margin.
To get a margin around the inside of the listbox, what I normally do is give it a zero borderwidth and highlightthickness, and then place it in a frame with the same background color and let the frame be the border. You can then add any padding you want between the border and the listbox.
This is also convenient because you can put a scrollbar inside the frame, giving it the appearance that it is inside the listbox without actually being inside the listbox.
Example:
import tkinter as tk
root = tk.Tk()
root.configure(background="gray")
listbox_border = tk.Frame(root, bd=1, relief="sunken", background="white")
listbox_border.pack(padx=10, pady=10, fill=None, expand=False)
listbox = tk.Listbox(listbox_border, width=20, height=10,
borderwidth=0, highlightthickness=0,
background=listbox_border.cget("background"),
)
vsb = tk.Scrollbar(listbox_border, orient="vertical", command=listbox.yview)
listbox.configure(yscrollcommand=vsb)
vsb.pack(side="right", fill="y")
listbox.pack(padx=10, pady=10, fill="both", expand=True)
for i in range(100):
listbox.insert("end", "Item #{}".format(i))
root.mainloop()
here is a variation on the much appreciated answer by Bryan Oakley.
it uses ttk widgets instead of tk widgets
the scrollbar tracks your position in the list box when you scroll with the mouse
uses the oStyle.theme_use("clam") because it may look more modern...this can be commented out
'
import tkinter as tk
from tkinter import ttk
try: # allows the text to be more crisp on a high dpi display
from ctypes import windll
windll.shcore.SetProcessDpiAwareness(1)
except:
pass
root = tk.Tk()
oStyle = ttk.Style()
oStyle.theme_use("clam")
oStyle.configure('LB.TFrame', bd=1, relief="sunken", background="white")
listbox_border = ttk.Frame(root, style='LB.TFrame')
listbox_border.pack(padx=4, pady=4, fill=None, expand=False)
vsb = ttk.Scrollbar(listbox_border)
vsb.pack(side="right", fill="y")
listbox = tk.Listbox(listbox_border, width=20, height=10, borderwidth=0,
highlightthickness=0, selectmode=tk.SINGLE,
activestyle=tk.NONE)
listbox.pack(padx=6, pady=6, fill="y", expand=True)
listbox.config(yscrollcommand=vsb.set)
vsb.config(command=listbox.yview)
for i in range(100):
listbox.insert("end", "Item #{}".format(i))
root.mainloop()
'
first of all to format chars in a tkinter listbox you need to use a fixed font and .format python funcion....;
So you can do something this
Press Load to load data in the listbox and pay attention to this line code
s = '{0:>8}{1:5}'.format(i[0],i[1])
self.list.insert(tk.END, s)
import tkinter as tk
RS = (('Apple',10),
('Banana',20),
('Peack',8),
('Lemon',6),)
class App(tk.Frame):
def __init__(self,):
super().__init__()
self.master.title("Hello World")
self.init_ui()
def init_ui(self):
self.pack(fill=tk.BOTH, expand=1,)
f = tk.Frame()
sb = tk.Scrollbar(f,orient=tk.VERTICAL)
self.list = tk.Listbox(f,
relief=tk.GROOVE,
selectmode=tk.BROWSE,
exportselection=0,
background = 'white',
font='TkFixedFont',
yscrollcommand=sb.set,)
sb.config(command=self.list.yview)
self.list.pack(side=tk.LEFT,fill=tk.BOTH, expand =1)
sb.pack(fill=tk.Y, expand=1)
w = tk.Frame()
tk.Button(w, text="Load", command=self.on_callback).pack()
tk.Button(w, text="Close", command=self.on_close).pack()
f.pack(side=tk.LEFT, fill=tk.BOTH, expand=0)
w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=0)
def on_callback(self,):
for i in RS:
s = '{0:>8}{1:5}'.format(i[0],i[1])
self.list.insert(tk.END, s)
def on_close(self):
self.master.destroy()
if __name__ == '__main__':
app = App()
app.mainloop()
I started with the GUI in Python and have a problem.
I've added widgets to my frame, but they're always on the left side.
I have tried some examples from the internet, but I did not manage it .
I tried .place, but it does not work for me. Can one show me how to place the widgets in the middle?
Code:
import tkinter as tk
def site_open(frame):
frame.tkraise()
window = tk.Tk()
window.title('Test')
window.geometry('500x300')
StartPage = tk.Frame(window)
FirstPage = tk.Frame(window)
for frame in (StartPage, FirstPage):
frame.grid(row=0, column=0, sticky='news')
lab = tk.Label(StartPage, text='Welcome to the Assistant').pack()
lab1 = tk.Label(StartPage, text='\n We show you helpful information about you').pack()
lab2 = tk.Label(StartPage, text='\n \n Name:').pack()
ent = tk.Entry(StartPage).pack()
but = tk.Button(StartPage, text='Press', command=lambda:site_open(FirstPage)).pack()
lab1 = tk.Label(FirstPage, text='1Page').pack()
but1 = tk.Button(FirstPage, text='Press', command=lambda:site_open(StartPage)).pack()
site_open(StartPage)
window.mainloop()
After you have created window, add:
window.columnconfigure(0, weight=1)
More at The Grid Geometry Manager
You are mixing two different Layout Managers. I suggest you either use The Grid Geometry Manager or The Pack Geometry Manager.
Once you have decided which one you would like to use, it is easier to help you :)
For example you could use the Grid Geometry Manager with two rows and two columns and place the widgets like so:
label1 = Label(start_page, text='Welcome to the Assistant')
# we place the label in the page as the fist element on the very left
# and allow it to span over two columns
label1.grid(row=0, column=0, sticky='w', columnspan=2)
button1 = Button(start_page, text='Button1', command=self.button_clicked)
button1.grid(row=1, column=0)
button2 = Button(start_page, text='Button2', command=self.button_clicked)
button2.grid(row=1, column=1)
This will lead to having the label in the first row and below the two buttons next to each other.
I am developing a simple (so far) GUI on tkinter.
What I have right now is a GUI window with a canvas object and a treeview table in the same window.
My aim is to load csv data generate a heat map and use the positions to show further data about the clicked locations.
I can already generate the heat map(picture below) from the csv.
What I need now is for the canvas to detect my mouse click and based on the click transfer data from the same (or a different it doesn't matter as of yet) csv to the table. I tried a few things but I quite don't seem to understand how to assign the data on the canvas or the table for it to recognize it.
def tableDisplayFromGraph(self):
tableframe = tk.Frame(self.master)
tableframe.grid(row=2, column=10, ipadx=4, pady=2, sticky ="e") ## Packing against tableframe Frame
COLUMNS = ['Type', 'Value'] ## Column Headers for Data
## See Documentation for more info on Treeview
table = ttk.Treeview(tableframe, columns=COLUMNS, show='headings', padding=4)
table.grid(row=0, column=0)
for column in COLUMNS: ## Setting Column Header
table.heading(column, text=column)
scroll = tk.Scrollbar(tableframe, command=table.yview) ## Adding Vertical Scrollbar
scroll.grid(row=0, column=1) # problem how to set scrollbar inside the table :/
table.configure(yscrollcommand=scroll.set) ## Attach Scrollbar :/
def canvas(self):
f = plt.figure(figsize=(8, 8), dpi=110)
a = f.add_subplot(111)
if not self.Data.empty:
pivot_table = self.Data.pivot('Rows', 'Columns', 'B635 Mean')
plt.xlabel('Columns', size=12)
plt.ylabel('Rows', size=12)
plt.title('Heat Map', size=15)
sns.heatmap(pivot_table, annot=True, annot_kws={'size': 8},fmt="0.0f", linewidths=0, square=True, cmap='Reds')
#a.clear()
canvasFig = FigureCanvasTkAgg(f, master=self.master)
canvasFig.get_tk_widget().grid(row=0, column=0, rowspan=5, columnspan=5, padx=30, pady=10, sticky="ew")
navigatorFrame = tk.Frame(self.master)
navigatorFrame.grid(row=21, column=0, columnspan=5, padx=30, sticky="nw")
toolbar = NavigationToolbar2TkAgg(canvasFig, navigatorFrame)
toolbar.update()
canvasFig._tkcanvas.grid()
f.canvas.mpl_connect('pick_event', self.pick)
def pick(self, event):
if canvas.find_withtag(CURRENT):
canvas.itemconfig(CURRENT, fill="blue")
canvas.update_idletasks()
canvas.after(200)
canvas.itemconfig(CURRENT, fill="red")
canvas.bind("<Button-1>", self.pick)enter code here
When I hover around the heat map the canvas doesn't show x,y coordinates.
pick is my function for the click event.
Any help would be appreciated.
This is the image of my GUI. On the left is my heat map and on the right is my table treeview widget for displaying further data: