I am creating a GUI with Tkinter and ttk, and I'm trying to create a custom map to make ttk widgets blue on hover. I could apply that to all widgets with passing "." as the first argument to ttk.Style().map(...).
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
style = ttk.Style()
style.map(".", background=[("active", "blue")])
button = ttk.Button(root, text="An example button")
button.pack()
scrollbar = ttk.Scrollbar(root)
scrollbar.pack()
root.mainloop()
But now I want to exclude TButton from this query. That is, I need to make all widgets but TButton blue on hover. How can I do that?
Passing ".!TButton" as well as "!TButton" instead of "." has no effect.
There is a root style whose name is '.'. To change some feature's default appearance for every widget, you can configure this style. For example, let's suppose that you want all text to be 12-point Helvetica (unless overriden by another style or font option).
So we can override it by simply adding another style:
style.map('TButton',background=[('active','#f0f0f0')])
Keep a note that you might want to do this for every style that you wish to set to default too.
Take a read here for more info.
Related
By using wrong keyword I've stupidly struggled to change what we could call the first level of color of ttk widgets. It's not underground or underlayer but fieldbackground as most of you already know.
See below...
A little reminder :
background color is the color under the text in the widget
foreground color is the color of the text
fieldground color is the color of the place where the text will appear
This can be manage with Style:
self.MainTk = tkinter.Tk()
self.style = ttk.Style( self.MainTk )
self.style.configure("Treeview", fieldbackground = 'grey65')
self.style.configure("TEntry", fieldbackground = 'grey65')
Note that some widgets need a T before the name in the configure phase.
see https://www.pythontutorial.net/tkinter/ttk-style/ for more infos.
In Treeview, it manage the Tree mode appearence when you have a single parent collapsed.
From digging old posts it seems that this may not work with some themes under some configuration. You'll find out.
WARNING : Since the error is often made even if it's logic, the widgets must be ttk not tkinter so you must use
self.MyEntry = ttk.Entry(MainTk)
instead of
self.MyEntry = tkinter.Entry(MainTk)
or
self.MyEntry = tk.Entry(MainTk)
if you have import tkinter as tk. Here lie the most common mistake I think.
How can I remove the dotted black border after a button is clicked in Tkinter (with Ttkthemes)?
I'm on Windows 10, Python 3.7.9.
There seems to be no uniform way to remove it and I searched across Google and SO with no luck. Thanks.
Here's a minimal example:
import tkinter
import tkinter.ttk
from ttkthemes import ThemedTk
tk = ThemedTk(theme="arc")
tk.configure(background="#f5f6f7")
tk.resizable(0,0)
selectFileInput = tkinter.ttk.Button(
tk,
text="Select Input File"
)
selectFileInput.place(x=20,y=60)
tk.mainloop()
I found the solution. It was to create a dummy button and focus it to remove focus from the button to the dummy button by using dummy.focus()
ttk.Button has the keyword argument takefocus this can be set to false and the button does not take focus after it is clicked.
ttk.Button(.., .., takefocus=False)
Therefore you do not need a hack with a dummy button that takes focus as in the answer.
Summary
How do I create a derived style with underlined text using ttk styling?
Details
I'm attempting to create a ttk style derived from the built-in TLabel style. The only difference between the built-in and the derived style should be that the text is underlined; it should inherit all other characteristics from the built-in TLabel style (i.e, if the TLabel font changes later, so should the Underline.TLabel).
I know that the basic way (not using ttk styling) is to create a new underlined font. However, as you can see from the sample code (below), the Underline.TLabel style displays in the correct (default) font, but the font-size is larger. I'm certain I'm missing something obvious, but haven't been able to find it through any Google searches, etc.
import tkinter as tk
from tkinter import font
from tkinter import ttk
def main():
root = tk.Tk()
style = ttk.Style(root)
f = font.Font(underline=1)
style.configure('Underline.TLabel', font=f)
lbl0 = ttk.Label(root, text='Label 0', style='TLabel')
lbl0.pack()
lbl1 = ttk.Label(root, text='Label 1', style='Underline.TLabel')
lbl1.pack()
root.mainloop()
if __name__ == '__main__':
main()
The problem is that you are assuming that font.Font(underline=1) returns the exact same font that is used by TLabel but with the underline bit turned on. This may or may not be true depending on the platform and how it's configured.
If you need the custom font to be based off of the font used by TLabel, you should first make a copy of the font instead of relying on defaults.
For example:
original_font = font.nametofont(style.lookup("TLabel", "font"))
f = font.Font(**original_font.configure())
f.configure(underline=1)
I am trying to disable all of the (ttk) widgets in a frame, but it appears that the scale widget is giving me some trouble, as it throws the following exception:
_tkinter.TclError: unknown option "-state"
Some relevant code:
import tkinter as tk
from tkinter import ttk
def disable_widgets(parent):
for child in parent.winfo_children():
child.config(state = 'disabled')
root = tk.Tk()
# Frame full of widgets to toggle
frame_of_widgets = ttk.Frame(root)
frame_of_widgets.pack()
# Button to be disabled
button_to_disable = ttk.Button(frame_of_widgets)
button_to_disable.pack()
# Entry to be disabled
entry_to_disable = ttk.Entry(frame_of_widgets)
entry_to_disable.pack()
# Scale to be disabled
scale_to_disable = ttk.Scale(frame_of_widgets)
scale_to_disable.pack()
# Button that disables widgets in frame
disable_button = ttk.Button(root,text="Disable",command= lambda: disable_widgets(frame_of_widgets))
disable_button.pack()
root.mainloop()
It works for the button and entry, but not for the scale. I thought one of the benefits of ttk was making widgets more uniform with common methods and attributes, so I am guessing perhaps I am accessing all three of these widgets incorrectly?
For ttk widgets you use the state method. The state method for buttons and entry widgets are just a convenience function to mimic the standard button and entry widgets.
You can rewrite your function like this:
def disable_widgets(parent):
for child in parent.winfo_children():
child.state(["disabled"])
ttk states are mentioned in the ttk documentation here (though the description borders on useless): https://docs.python.org/3.1/library/tkinter.ttk.html#widget-states
another way:
scale_to_disable.configure(state='disabled') # 'normal'
You can consider that set the breakpoint at the configure of the class Scale (from tkinter.ttk import Scale) may get some helpful.
The following is part of the code to intercept the class Scale
class Scale(Widget, tkinter.Scale):
...
def configure(self, cnf=None, **kw):
if cnf:
kw.update(cnf)
Widget.configure(self, **kw)
Basically, I want the body of a Text widget to change when a StringVar does.
Short version is, you can't. At least, not without doing extra work. The text widget doesn't directly support a variable option.
If you want to do all the work yourself it's possible to set up a trace on a variable so that it keeps the text widget up to date, and you can add bindings to the text widget to keep the variable up to date, but there's nothing built directly into Tkinter to do that automatically.
The main reason this isn't directly supported is that the text widget can have more than just ascii text -- it can have different fonts and colors, embedded widgets and images, and tags.
I thought of this while working on a project. It's actually really simple:
import tkinter as tk
from tkinter import *
from tkinter.scrolledtext import ScrolledText
def get_stringvar(event):
SV.set(ST1.get("1.0", END))
ST2.replace("1.0", END, SV.get())
root = tk.Tk()
SV = StringVar()
ST1 = ScrolledText(root)
ST1.pack()
ST1.bind('<KeyRelease>', get_stringvar)
ST2 = ScrolledText(root)
ST2.pack()
root.mainloop()