tkinter ttk treeview colored rows - python

I am trying to set colors to rows in a tkinter treeview object, using tags and tag_configure.
There has been an earlier discussion on coloring rows which is rather old and seems to work no longer for Python3:
ttk treeview: alternate row colors
I have added a brief example. For me, all rows stay white, independent of whether I execute tag_configure prior or after the insert command.
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
w = tk.Label(root, text="Hello, world!")
w.pack()
lb= ttk.Treeview(root, columns=['number', 'text'], show="headings", height =20)
lb.tag_configure('gr', background='green')
lb.column("number", anchor="center", width=10)
lb.insert('',tk.END, values = ["1","testtext1"], tags=('gr',))
lb.insert('',tk.END, values = ["2","testtext2"])
lb.pack()
root.mainloop()
What has changed or what am I missing?
EDIT:
Seems that this is a new known bug with a workaround, but I don't get this working:
https://core.tcl-lang.org/tk/tktview?name=509cafafae
EDIT2:
I am now using tk Version 8.6.10 (Build hfa6e2cd_0, Channel conda-forge) and python 3.7.3. Can anyone reproduce this error with this version of python and tk?

You no longer need to use fixed_map the bug was fixed in tkinter version 8.6.
The following code works fine for me using tkinter 8.6 and python 3.8.2 running in Linux.
import tkinter as tk
import tkinter.ttk as ttk
def fixed_map(option):
return [elm for elm in style.map("Treeview", query_opt=option) if elm[:2] != ("!disabled", "!selected")]
root = tk.Tk()
style = ttk.Style()
style.map("Treeview", foreground=fixed_map("foreground"), background=fixed_map("background"))
w = tk.Label(root, text="Hello, world!")
w.pack()
lb= ttk.Treeview(root, columns=['number', 'text'], show="headings", height =20)
lb.tag_configure('odd', background='green')
lb.tag_configure('even', background='lightgreen')
lb.column("number", anchor="center", width=10)
lb.insert('', tk.END, values = ["1","testtext1"], tags=('odd',))
lb.insert('', tk.END, values = ["2","testtext2"], tags=('even',))
lb.insert('', tk.END, values = ["3","testtext3"], tags=('odd',))
lb.insert('', tk.END, values = ["4","testtext4"], tags=('even',))
lb.pack()
root.mainloop()

That answer of Chuck666 did the trick:
https://stackoverflow.com/a/60949800/4352930
This code works
import tkinter as tk
import tkinter.ttk as ttk
def fixed_map(option):
# Returns the style map for 'option' with any styles starting with
# ("!disabled", "!selected", ...) filtered out
# style.map() returns an empty list for missing options, so this should
# be future-safe
return [elm for elm in style.map("Treeview", query_opt=option)
if elm[:2] != ("!disabled", "!selected")]
root = tk.Tk()
style = ttk.Style()
style.map("Treeview",
foreground=fixed_map("foreground"),
background=fixed_map("background"))
w = tk.Label(root, text="Hello, world!")
w.pack()
lb= ttk.Treeview(root, columns=['number', 'text'], show="headings", height =20)
lb.tag_configure('gr', background='green')
lb.column("number", anchor="center", width=10)
lb.insert('',tk.END, values = ["1","testtext1"], tags=('gr',))
lb.insert('',tk.END, values = ["2","testtext2"])
lb.pack()
root.mainloop()
I hope that Chuck666 copies his answer here since I think he has earned the bonus if he shows up.

Related

Treeview moves after click on Combobox with Tkinter

I have developped a app in Python (tested with 3.8 and 3.9 on Windows 10) with Tkinter. I am using a Combobox and a Treeview. I want to change dynamically the width of dropdown listbox and I could do it by changing the style of TCombobox with the parameter postoffset.
However, everytime I click on the Combobox, the table next to it moves and extends its width by itself. I really don't know where this problem comes from.
I have created a simple code so that you can reproduce the problem.
import tkinter as tk
from tkinter import ttk
import tkinter.font as tkfont
def combo_configure(event, style):
combo = event.widget
long = max(combo.cget('values'), key=len)
font = tkfont.Font(family="Helvetica", size=10)
width = max(0,font.measure(long.strip() + '0') - combo.winfo_width())
style.configure('TCombobox', postoffset=(0,0,width,0))
win = tk.Tk()
win.geometry("850x250")
style = ttk.Style()
f = tk.Frame(win)
f.configure(bg="black")
f.pack()
combo = ttk.Combobox(f, style="TCombobox", values=["It's a test on Combobox style."], width=10)
combo.bind('<ButtonPress>', lambda e : combo_configure(e, style))
combo.pack(side="left")
tree = ttk.Treeview(f, column=["Column 1"], show='headings', height=10)
tree.heading(0, text="Column 1")
tree.column(0, anchor=tk.CENTER, width=125)
tree.pack()
win.mainloop()
Thanks.

tkinter scale slider value not showing

below is my code for a basic tkinter scale:
root = tk.Tk()
root.geometry('150x75')
root.resizable(width=False, height=False)
root.eval('tk::PlaceWindow . center')
v1 = tk.IntVar()
ttk.Scale(root, from_=0, to=100, orient='horizontal', variable=v1).pack(pady=20)
root.mainloop()
below is the attached output :
why is the slider value not showing above the slider ?
I would very much appreciate if someone could point out the error with the code.
The tkinter.ttk version of Scale does not support showing the value.
But the tkinter version of Scale DOES support showing the Scale value, by default. The showvalue option defaults to 1. You can set it to 0 to hide the value if so desired.
There is no error in your code. I think the answer is "because it's not designed to". There is no mention in the documentation of the ttk scale widget that it shows the value.
Try something like this:-
import tkinter as tk
from tkinter import ttk
# root window
root = tk.Tk()
root.geometry('300x200')
root.resizable(False, False)
root.title('Slider Demo')
root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=3)
# slider current value
current_value = tk.DoubleVar()
def get_current_value():
return '{: .2f}'.format(current_value.get())
def slider_changed(event):
value_label.configure(text=get_current_value())
# label for the slider
slider_label = ttk.Label(root, text='Slider:')
slider_label.grid(column=0, row=0, sticky='w')
# slider
slider = ttk.Scale(root, from_=0, to=100, orient='horizontal', command=slider_changed, variable=current_value)
slider.grid(column=1, row=0, sticky='we')
# current value label
current_value_label = ttk.Label(root, text='Current Value:')
current_value_label.grid(row=1, columnspan=2, sticky='n', ipadx=10, ipady=10)
# value label
value_label = ttk.Label(root,text=get_current_value())
value_label.grid(row=2, columnspan=2, sticky='n')
root.mainloop()
Link to site from which I got the answer:- https://www.pythontutorial.net/tkinter/tkinter-slider/
You may try removing this from tkinter ttk import * if you have imported something like this at the top of your code. Simply importing this from tkinter import * helps in showing the values of the scale in slider.
Happy Coding!
A simple like this:
import tkinter as tk
from tkinter import ttk
from tkinter import *
root = tk.Tk()
root.geometry('150x75')
root.resizable(width=False, height=False)
root.eval('tk::PlaceWindow . center')
def sel():
selection = f"Value = str{var.get()}"
label.config(text = selection)
var = tk.DoubleVar()
scale = tk.Scale(root, variable=var )
scale.pack(anchor=CENTER)
label = Label(root)
label.pack()
root.mainloop()

Positioning text inside OptionMenu in tkinter python

hy I am working on tkinter python project.
I am trying to position text to the Left inside OptionMenu using anchor option but it does not seem to work. I am using ttk theme widgets.
Here is the code that I am trying currently.
s = ttk.Style()
s.configure('my.TMenubutton', font=("Cambria", fontSize, "bold"), background="white", anchor = W )
shapeMenu = ttk.OptionMenu(shapeFrame, shape, myShapes[1], *myShapes, style='my.TMenubutton', command=getShapes)
What I am doing wrong ?
It seems like there is no anchor option under TMenubutton. I tried TLabel, and it worked. Don't know if there is any side effect though.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry('300x100')
CHART_TYPES = ('Reticle', 'Circle Grid', 'Checkerboard', 'Grille', 'Slanted Edge MTF')
s = ttk.Style()
s.configure('my.TLabel', font=("Cambria", 10, "bold"), background="white", anchor = 'w' )
chart_type = tk.StringVar()
chart_type.set(CHART_TYPES[0])
# chart_selector = tk.OptionMenu(root, chart_type, *CHART_TYPES)
chart_selector = ttk.OptionMenu(root, chart_type, *CHART_TYPES, style='my.TLabel')
# chart_selector.configure(anchor='w')
chart_selector.pack(expand=True, fill='x')
root.mainloop()

ttk Combobox set background colour programatically and dynamically

I have a row of widgets which contains a ttk.Combobox and I want to change the background colour of the widgets in the row when I tick a Checkbutton at the end of the row. With tkinter it is simple just to use configure but with ttk you have to use a theme which seems to be neither dynamic nor specific to a single widget. Is there a way to achieve this functionality ?
Thankyou.
in response to fhdrsdg's comment. I can't get it working but this code demonstrates it
import Tkinter as tk
import ttk
def skillUsed():
if chkUsedVar.get() == 1:
style.map('TCombobox', background=[('readonly','green')])
style.map('TCombobox', foreground=[('readonly','red')])
else:
style.map('TCombobox', background=[('readonly','white')])
style.map('TCombobox', foreground=[('readonly','black')])
root = tk.Tk()
style = ttk.Style()
cboxVar1 = tk.StringVar()
cboxVar1.set("spam")
cboxVar2 = tk.StringVar()
cboxVar2.set("silly")
chkUsedVar = tk.IntVar()
chk = tk.Checkbutton(root, text='Used', variable=chkUsedVar, command=skillUsed)
chk.grid(row=0, column=2)
combo01 = ttk.Combobox(root, values=['spam', 'eric', 'moose'], textvariable=cboxVar1)
combo01['state'] = 'readonly'
combo01.grid(row=0, column=0)
combo02 = ttk.Combobox(root, values=['parrot', 'silly', 'walk'], textvariable=cboxVar2)
combo02['state'] = 'readonly'
combo02.grid(row=0, column=1)
root.mainloop()
When the tick box is clicked the foreground goes red and when unticked it goes black. The issue is the background never changes (but doesn't error) and the style is applied globally to both comboboxes and I want to apply it to a single box.
I have a workaround which I will use just using tkinter's OptionMenu and everything I can find on the tinterweb implies it can't be done with ttk widgets but that seems a bit of a limit to ttk widgets but I have little to no experience with tkinter or ttk.
the workaround is :-
from Tkinter import *
def skillUsed():
if chkUsedVar.get() == 1:
opt01.configure(bg="#000fff000")
opt01.configure(highlightbackground="#000fff000")
opt01.configure(activebackground="#000fff000")
opt01.configure(highlightcolor="#000fff000")
opt01["menu"].configure(bg="#000fff000")
else:
opt01.configure(bg=orgOptbg)
opt01.configure(highlightbackground=orgOpthighlightbackground)
opt01.configure(activebackground=orgOptactivebackground)
opt01.configure(highlightcolor=orgOpthighlightcolor)
opt01["menu"].configure(bg=orgOptmenu)
root = Tk()
optionList = ('parrot','silly','walk')
varopt01 = StringVar()
varopt01.set(optionList[0])
chkUsedVar = IntVar()
opt01 = OptionMenu(root, varopt01, *optionList)
opt01.grid(row=0, column=0)
orgOptbg = opt01.cget("bg")
orgOpthighlightbackground = opt01.cget("highlightbackground")
orgOptactivebackground = opt01.cget("activebackground")
orgOpthighlightcolor = opt01.cget("highlightcolor")
orgOptmenu = opt01["menu"].cget("bg")
chk = Checkbutton(root, text='Used', variable=chkUsedVar, command=skillUsed)
chk.grid(row=0, column=1)
root.mainloop()
Thankyou
First, if you want to apply the style to a single combobox, give it a name like 'custom.TCombobox' so that it inherits from 'TCombobox' but doesn't change the default combobox style. Then all you have to do is set the style of your combobox to 'custom.TCombobox'.
Secondly, the background was not changing because it's the fieldbackground you want to change.
EDIT: What can be customized in a style depends on the ttk theme being used. For instance, the default Mac and Windows themes don't allow much customization and the fieldbackground color of the combobox cannot be changed. However, the 'alt' and 'clam' themes allow more customization.
Here is an example based on your code:
import tkinter as tk
from tkinter import ttk
def skillUsed():
if chkUsedVar.get() == 1:
style.map('custom.TCombobox', fieldbackground=[('readonly','green')])
style.map('custom.TCombobox', foreground=[('readonly','red')])
else:
style.map('custom.TCombobox', fieldbackground=[('readonly','white')])
style.map('custom.TCombobox', foreground=[('readonly','black')])
root = tk.Tk()
style = ttk.Style()
style.theme_use('alt')
cboxVar1 = tk.StringVar()
cboxVar1.set("spam")
cboxVar2 = tk.StringVar()
cboxVar2.set("silly")
chkUsedVar = tk.IntVar()
chk = tk.Checkbutton(root, text='Used', variable=chkUsedVar, command=skillUsed)
chk.grid(row=0, column=2)
combo01 = ttk.Combobox(root, values=['spam', 'eric', 'moose'], textvariable=cboxVar1)
combo01['state'] = 'readonly'
combo01.grid(row=0, column=0)
combo02 = ttk.Combobox(root, values=['parrot', 'silly', 'walk'], textvariable=cboxVar2, style='custom.TCombobox')
combo02['state'] = 'readonly'
combo02.grid(row=0, column=1)
root.mainloop()

Anti-aliased fonts in tkinter?

Is there a way to get anti-aliased fonts in tkinter? If I increase the size of the default font like so:
default_font = tkFont.nametofont("TkDefaultFont")
default_font.configure(size=32)
the text comes out jagged.
Here is some version information:
Python 2.7.9 (default, May 6 2015, 09:33:48)
>>> Tkinter.__version__
'$Revision: 81008 $
I am using Gentoo Linux and have Tk 8.5 installed (which i believe should support anti-aliased fonts):
$ equery l tk
[IP-] [ ] dev-lang/tk-8.5.17:0/8.5
EDIT: adding this full MWE to describe what I'm doing:
from Tkinter import *
import tkFont
from ttk import *
root = Tk()
note = Notebook(root)
default_font = tkFont.nametofont("TkDefaultFont")
default_font.configure(size=48)
tab1 = Frame(note)
tab2 = Frame(note)
Button(tab1, text='Exit', command=root.destroy).pack(padx=100, pady=100)
note.add(tab1, text = "Curvy Words")
note.add(tab2, text = "Aliased")
note.pack()
root.mainloop()
exit()
It turns out to have been an issue with how tk was installed with gentoo. After adding truetype support by setting the use flag
For example, I added the line to /etc/portage/package.use
>=dev-lang/tk-8.5.17 truetype
And then remerged tk:
emerge -Na tk
I don't know much about ttk, but do know that you use "style" to set the font-->ttk tutorial http://www.tkdocs.com/tutorial/styles.html This looks fine on my Slackware box, but it uses anti-aliased by default.
from Tkinter import *
import ttk
import tkFont
root = Tk()
##default_font = tkFont.nametofont("TkDefaultFont")
##default_font.configure(size=48)
f = tkFont.Font(family='helvetica', size=24)
s = ttk.Style()
s.configure('.', font=f)
note = ttk.Notebook(root)
tab1 = ttk.Frame(note)
tab2 = ttk.Frame(note)
note.add(tab1, text = "Curvy Words")
note.add(tab2, text = "Aliased")
note.pack()
ttk.Style().configure("TButton", padding=6, relief="flat",
background="white")
ttk.Button(tab1, text='Exit', command=root.destroy).pack(padx=100, pady=100)
root.mainloop()

Categories