Related
So what I am trying to do is create a theme picker for my application
For example, the user could click on a the Green/Black button and it would change every widgets background to Black and it would change every widgets foreground to Green. Then they could click the Red/White button and it would do the same thing but change every widgets background to White and every widgets foreground to Red.
# Imports the tkinter library.
from tkinter import *
from tkmacosx import Button
# Pillow is a improved verison of PIL, stands for Python Image Library. Allows you to import image types like .jpg and .png
from PIL import ImageTk,Image
# Imports messagebox module from tkinter library.
from tkinter import messagebox
# Declare global variables
global selectedBackground
global selectedForeground
selectedBackground="white"
selectedForeground="red"
# Tk() helps to display the root window and manages all the other components of the tkinter application and assigns it to root.
root = Tk()
root.eval("tk::PlaceWindow . center")
root.configure(bg=selectedBackground)
cipherButton = Button(root, text=" Cipher ", padx=40, pady=20, command=openCipher, borderwidth=0, fg="#22fd35", bg="black", highlightbackground="#22fd35").grid(row=1, column=0)
decipherButton = Button(root, text="Decipher", padx=40, pady=20, command=openDecipher, borderwidth=0, fg="#22fd35", bg="black", highlightbackground="#22fd35").grid(row=1, column=1)
spacer1 = Label(root, text=" ", padx=10, pady=1, background="black").grid(row=4, column=1)
quitButton = Button(root, text="Exit d3cryptt", padx=10, pady=5, command=root.quit, borderwidth=0, fg="#22fd35", bg="black", highlightbackground="#22fd35").grid(row=5, column=0, columnspan=2)
spacer2 = Label(root, text=" ", padx=10, pady=1, background=selectedBackground).grid(row=6, column=1)
changecolour = Button(root, text="change colour", padx=1, pady=5, background="black", command=changeColour).grid(row=7, column=0)
#Enter the event main loop
root.mainloop()
I have tried using a function. Something like this.
def changeColour():
selectedBackground="black"
selectedForeground="#22fd35"
changecolour = Button(root, text="change colour", padx=1, pady=5, background="black", command=changeColour).grid(row=7, column=0)
But that doesn't work. I think a function is the right way to go, but I may be wrong.
I will also need this 'theme' to carry on to any other windows that are created from this window. I think I can just do that by using lambda in the command section of the widget.
Widget.config(bg=color) is what your looking for.
Here is a small example of a theme-changing app:
from tkinter import *
from tkmacosx import Button
root = Tk()
def changethemetoblack():
root.config(bg="#000000")
def changethemetowhite():
root.config(bg="#ffffff")
def changethemetored():
root.config(bg="#ff0000")
themeblackbutton = Button(root, text="Change Theme To Black", command=changethemetoblack, bg="#000000", fg="#ffffff")
themewhitebutton = Button(root, text="Change Theme To White", command=changethemetowhite)
themeredbutton = Button(root, text="Change Theme To Red", command=changethemetored, bg="#ff0000", fg="#ffffff")
themeblackbutton.pack()
themewhitebutton.pack()
themeredbutton.pack()
root.mainloop()
I'll try to change it so that it applies for your code.
However, your provided script does not seem to be a working one. I assume this is because it is only a snippet of the real one. I'm not pushing for your entire code, but edit it so we can run it. Ex. openCipher method is causing errors as we have not defined it.
I'd like to allow the user to configure the appearance of the app (background color, font, font size and color, button color, etc). I've got all of the default settings saved into a config file, which the program interprets and saves into variables within a class for easy access between functions. Now, I can save the changes the user made into the config file and those changes will be reflected when the user closes and reopens the app, but I'd like the changes to be instantaneous, so I tried something like this:
import tkinter as tk
class SetColor:
def __init__(self, color):
self.color = 'green'
current = SetColor('green')
root = tk.Tk()
lbl_color = tk.Label(root, text='Choose button color')
lbl_color.grid(row=0, column=0, pady=5, padx=2)
btn_red = tk.Button(root, text='Red', bg=current.color, command=lambda:update_color('red'))
btn_red.grid(row=0, column=1, pady=5, padx=2)
btn_green = tk.Button(root, text='Green', bg=current.color, command=lambda:update_color('green'))
btn_green.grid(row=0, column=2, pady=5, padx=2)
btn_blue = tk.Button(root, text='Blue', bg=current.color, command=lambda:update_color('blue'))
btn_blue.grid(row=0, column=3, pady=5, padx=2)
def update_color(color):
current.color = color
#THIS is where I'm wondering if there's a way to refresh without individually updating each widget as I've done below
btn_red.config(bg=current.color)
btn_green.config(bg=current.color)
btn_blue.config(bg=current.color)
root.mainloop()
This does work, but in my actual app there are a loooooot more widgets that would need updating than in this^ example. So I have a feeling I'm missing something or going about this in the wrong way. Any help greatly appreciated :)
Your best bet is to store the buttons in a list and loop over that list. This way you can seperate different buttons. But if you are sure you want to change the color of every singlle button you can do: for widget in root.winfo_children():
if isinstance(widget, tk.Button):
widget.config(bg=current.color)
#Maarten's answer is perfect for the tkinter button.
There is another option using ttk.Button can be used in such scenario
create the button object with a custom style
btn_green = ttk.Button(root, text='Green', style="color.TButton", command=lambda: update_color('green'))
create style object
style = ttk.Style()
style.theme_use("default")
set the style
style.configure('color.TButton', background=current.color)
# Activate is when you mouse over the button.
style.map('color.TButton', background=[('active', current.color)])
Full example:
import tkinter as tk
from tkinter import ttk
class SetColor:
def __init__(self, color):
self.color = 'green'
def update_color(color):
current.color = color
# Let's set the style
# naming that style variable as color.TButton
# NOTE: .TButton is important, you can add any other pretix though
style.configure('color.TButton', background=current.color)
# Activate is when you mouse over the button.
style.map('color.TButton', background=[('active', current.color)])
current = SetColor('green')
root = tk.Tk()
# Create style Object
style = ttk.Style()
# Setting theme to default (built in themes can be found https://wiki.tcl-lang.org/page/List+of+ttk+Themes)
style.theme_use("default")
lbl_color = ttk.Label(root, text='Choose button color')
lbl_color.grid(row=0, column=0, pady=5, padx=2)
btn_red = ttk.Button(root, text='Red', style="color.TButton", command=lambda: update_color('red'))
btn_red.grid(row=0, column=1, pady=5, padx=2)
btn_green = ttk.Button(root, text='Green', style="color.TButton", command=lambda: update_color('green'))
btn_green.grid(row=0, column=2, pady=5, padx=2)
btn_blue = ttk.Button(root, text='Blue', style="color.TButton", command=lambda: update_color('blue'))
btn_blue.grid(row=0, column=3, pady=5, padx=2)
update_color(current.color)
root.mainloop()
There are a lot more options with ttk style to play around.
Have a look at
Python ttk Style
ttk Themes
I did this and works perfectly. I hope it works for you.
def groups1(): # This function is to place the widgets for Groups.
# Clean widgets immediately after you call the button inside
# the button function.
for widget in frameleft.winfo_children():
widget.destroy()
groups = tkinter.ttk.Label(frameleft, text='Grupos', font=
('URW Gothic', 20))
groups.place(x=20, y=30)
I'm trying to make a simple calculator but when I try to configure my entry with 'relief' method it is showing the error _tkinter.TclError: unknown option "-relief".
I don't know why this is showing this error
import tkinter as tk
from tkinter import ttk
win = tk.Tk()
win.geometry('400x400')
win.title('Simple Calculator')
win.configure(bg='Peach puff')
value = tk.StringVar()
entry = ttk.Entry(win, font=('Helvetica', 35, 'bold'), justify='right', textvariable=value, relief=tk.SUNKEN)
entry.pack(padx=30, pady=15, side='top', fill='both')
def spin():
pass
button_images = {'one': tk.PhotoImage(file=r'C:\Users\hruthik\Desktop\Pics\numbers\one.png')}
b_one = ttk.Button(win, image=button_images['one'], command=spin, borderwidth=0)
b_one.pack(pady=20)
win.resizable(False, False)
win.mainloop()
The ttk package widgets have different options than the standard tkinter widgets. For example, the ttk.Entry widget has no option for relief, and the ttk.Button widget has no option for borderwidth. Try using the tk.Entry and tk.Button widgets instead, if you want to specify these options
import tkinter as tk
from tkinter import ttk
win = tk.Tk()
win.geometry('400x400')
win.title('Simple Calculator')
win.configure(bg='Peach puff')
value = tk.StringVar()
entry = tk.Entry(win, font=('Helvetica', 35, 'bold'), justify='right', textvariable=value, relief=tk.SUNKEN)
entry.pack(padx=30, pady=15, side='top', fill='both')
def spin():
pass
button_images = {'one': tk.PhotoImage(file=r'C:\Users\hruthik\Desktop\Pics\numbers\one.png')}
b_one = tk.Button(win, image=button_images['one'], command=spin, borderwidth=0)
b_one.pack(pady=20)
win.resizable(False, False)
win.mainloop()
I need a python messagebox with custom buttons.
I need something like this. I need it to return the button clicked. Like If I clicked 'A' it would return 'A'
I know about tkinter but I want to use this with pygame and can't get it to work.
Here is what I made with tkinter, not the perfect messagebox, but why not?
For the theme used you have to install it first, like:
pip install ttkthemes
Then the code
# imports
from tkinter import *
from tkinter import ttk
from ttkthemes import themed_tk as tktheme
from PIL import ImageTk, Image
from tkinter import messagebox
# making new themed window
root = tktheme.ThemedTk()
root.title('Take selection')
root.get_themes()
root.set_theme('vista')
# message to be shown by the box
message = 'Here is a custom messagebox.'
# defining functions
def click1():
root.destroy()
return 'A'
def click2():
root.destroy()
return 'B'
def click3():
root.destroy()
return 'C'
# creating white frame
frame1 = Frame(height=139, width=440, bg='white')
frame1.grid(row=0, column=0)
# creating gray frame
frame2 = ttk.Frame(height=50, width=440)
frame2.grid(row=1, column=0)
# importing the image, any image can be used(for the question mark)
dir = Image.open('Blue_question.png')
dir = dir.resize((50, 50), Image.ANTIALIAS)
img_prof = ImageTk.PhotoImage(dir)
img_label = Label(root, image=img_prof, bg='white')
img_label.grid(row=0, column=0, sticky=W, padx=25)
# defining main label
cust_messagebox = Label(root, text=message, font=('Arial', 10), bg='white')
cust_messagebox.grid(row=0, column=0, sticky=W, padx=(95, 0))
# defining buttons
button1 = ttk.Button(root, text='A', command=click1)
button1.grid(row=1, column=0, sticky=W, padx=30, ipadx=10)
button2 = ttk.Button(root, text='B', command=click2)
button2.grid(row=1, column=0, ipadx=10)
button3 = ttk.Button(root, text='C', command=click3)
button3.grid(row=1, column=0, sticky=E, padx=(0, 30), ipadx=10)
# keeping the app alive
root.mainloop()
With bigger messages you might want to increase the width of the frames and the play with the padding of the widgets too.
If any doubts or errors, do let me know.
Cheers
I just picked up python recently and I've been working on a project called "ToDoList.py".It's finished but I want to add a button to change the theme of the GUI using tkinter / ttk but its not working.
This is the error:
Traceback (most recent call last):
File "todolist.py", line 64, in <module>
lbl_title = Label(root, text="ToDoList", bg="white")
File "C:\Users\Sam\AppData\Local\Programs\Python\Python37-32\lib\tkinter\ttk.py", line 761, in __init__
Widget.__init__(self, master, "ttk::label", kw)
File "C:\Users\Sam\AppData\Local\Programs\Python\Python37-32\lib\tkinter\ttk.py", line 559, in __init__
tkinter.Widget.__init__(self, master, widgetname, kw=kw)
File "C:\Users\Sam\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 2296, in __init__
(widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: unknown option "-bg"
I don't understand why this error is possible since i haven't adjusted the widgets yet
from tkinter import *
from tkinter import ttk
from tkinter.ttk import *
from ttkthemes import themed_tk as tk
import random
import tkinter.messagebox
#--------root style
root = Tk()
#--------root backgroud
root.configure(bg="white")
#--------root title
root.title("Reminder")
#--------root size
root.geometry("225x300")
#--------create empty list
tasks = []
#--------fuction
def darkmd():
root.get_themes()
root.set_theme("equilux")
#--------command
lbl_title = Label(root, text="ToDoList", bg="white")
lbl_title.grid(row=0, column=0)
lbl_display = Label(root, text="", fg="black", bg="white")
lbl_display.grid(row=0, column=1)
txt_input = Entry(root, width=20, fg="black", bg="white")
txt_input.grid(row=1, column=1)
bt_add_task = Button(root, text="Add Task", fg="black", bg="white", command = add_task)
bt_add_task.grid(row=1, column=0)
bt_del_all = Button(root, text="Del all", fg="black", bg="white", command = del_all)
bt_del_all.grid(row=2, column=0)
bt_del_one= Button(root, text="Del", fg="black", bg="white", command = del_one)
bt_del_one.grid(row=3, column=0)
bt_sort_asc = Button(root, text="Sort (ASC)", fg="black", bg="white", command = sort_asc)
bt_sort_asc.grid(row=4, column=0)
bt_sort_desc = Button(root, text="Sort (DESC)", fg="black", bg="white", command = sort_desc)
bt_sort_desc.grid(row=5, column=0)
bt_total_task = Button(root, text="Num Of Task", fg="black", bg="white", command = total_task)
bt_total_task.grid(row=6, column=0)
bt_darkmd = Button(root, text="Darkmode", fg="black", bg="white", command = darkmd)
bt_darkmd.grid(row=7, column=0)
lb_tasks = Listbox(root,fg="black", bg="white")
lb_tasks.grid(row=2, column=1, rowspan=9)
#--------main
root.mainloop()
As an alternative to ThemedTk, you can use ThemedStyle. This way your code will be exactly like if you were using one of the standard ttk themes except that you define your style with style = ThemedStyle(root) instead of style = Style(root). Then you simply use style.theme_use(<theme name>) to change theme and you can list the available themes with style.theme_names().
from tkinter import ttk
import tkinter as tk
from ttkthemes import ThemedStyle
#--------root style
root = tk.Tk()
#--------root backgroud
root.configure(bg="white")
#--------root title
root.title("Reminder")
#--------root size
root.geometry("225x300")
# white theme
style = ThemedStyle(root)
style.theme_use('arc') # white style
#--------create empty list
tasks = []
#--------function
def darkmd():
style.theme_use("equilux") # only changes the theme of the ttk widgets
# change style of tk widgets manually:
bg = style.lookup('TLabel', 'background')
fg = style.lookup('TLabel', 'foreground')
root.configure(bg=style.lookup('TLabel', 'background'))
lb_tasks.configure(bg=bg, fg=fg)
#--------command
lbl_title = ttk.Label(root, text="ToDoList")
lbl_title.grid(row=0, column=0)
lbl_display = ttk.Label(root, text="")
lbl_display.grid(row=0, column=1)
txt_input = ttk.Entry(root, width=20)
txt_input.grid(row=1, column=1)
bt_add_task = ttk.Button(root, text="Add Task")
bt_add_task.grid(row=1, column=0)
bt_del_all = ttk.Button(root, text="Del all")
bt_del_all.grid(row=2, column=0)
bt_del_one = ttk.Button(root, text="Del")
bt_del_one.grid(row=3, column=0)
bt_sort_asc = ttk.Button(root, text="Sort (ASC)")
bt_sort_asc.grid(row=4, column=0)
bt_sort_desc = ttk.Button(root, text="Sort (DESC)")
bt_sort_desc.grid(row=5, column=0)
bt_total_task = ttk.Button(root, text="Num Of Task")
bt_total_task.grid(row=6, column=0)
bt_darkmd = ttk.Button(root, text="Darkmode", command=darkmd)
bt_darkmd.grid(row=7, column=0)
lb_tasks = tk.Listbox(root, fg="black")
lb_tasks.grid(row=2, column=1, rowspan=9)
#--------main
root.mainloop()
Clear theme:
Dark theme:
Note that only the ttk widgets become dark after setting the theme to "equilux". So you need to manually change the colors of your tk widgets in darkmd() (like I did for root and lb_tasks).
Comment: HowTo using: ttkthemes
To use ttkthemes change to the following:
No style.theme_use(... statement, as this is alredy done in __init__(....
from ttkthemes import ThemedTk
class App(ThemedTk):
def __init__(self):
super().__init__("equilux")
# ATTENTION!!
# The following could fail as i couldn't test with `ThemedTk`
# ATTENTION!!
style = ttk.Style(self)
style.configure("TLabel", background="white")
Question: How to add themes?
First you have to understand, not to mix tkinter and tkinter.ttk widgets in a uncontrolled way. Only tkinter.ttk widgets can be styled using theme and style.
TkDocs - Tk Tutorial - Styles and Themes
tkinterbook - Widget Styling
Use only the following common import statements
import tkinter as tk
import tkinter.ttk as ttk
To instantiate a ttk widget use:
Note: You can't use bg= on a ttk widget!
lbl_title = ttk.Label(root, text="ToDoList")
Application wide usage:
Note: It's important to do all style definition once and before any widget instantiation.
class App(tk.Tk):
def __init__(self):
super().__init__()
style = ttk.Style(self)
style.theme_use('clam')
style.configure("TLabel", background="white")
self.title("Tkinter Style")
self.geometry("225x300")
lbl_title = ttk.Label(self, text="ToDoList")
lbl_title.grid(row=0, column=0)
if __name__ == "__main__":
App().mainloop()
Tested with Python: 3.5
After reading your comment, I thought my input may help.
First, identify your OS. Windows/Mac
Second, open IDLE and then open IDLE preferences
You will see the settings and in "Highlights", below the radio buttons for the themes, you will see a drop box that allows you to switch your themes from IDLE Dark to Classic and New!