I am making a school project, and right now I'm having a problem with the label's backgrounds.
the objective is to make the label's background the same as the frame in both dark and light themes, and if possible, remove the little different color on the edges of the buttons.
import tkinter
import customtkinter
root_tk = customtkinter.CTk() # create CTk window like you do with the Tk window
root_tk.geometry("1280x720")
root_tk.minsize(1280, 720)
class GUI:
def __init__(self, root_tk):
Frame1 = customtkinter.CTkFrame(root_tk)
Frame1.pack
frame2 = customtkinter.CTkFrame(Frame1, width=100, height=720)
frame2.pack(pady=20,padx=20)
frame3 = customtkinter.CTkFrame(root_tk, width=250, height=725)
frame3.pack()
frame3.place(anchor="w", relx=0.0, rely=0.5, relwidth=0.2, relheight=1)
self.test()
def test(self):
self.switch = customtkinter.CTkSwitch(master=root_tk, text="Dark Mode", command=self.theme_change)
self.switch.toggle(1)
self.switch.place(relx=0.05, rely=0.05)
self.label_width = customtkinter.CTkLabel(root_tk, text="glasses width:")
self.label_width.place(relx=0.1, rely=0.67, anchor=tkinter.CENTER)
self.label_height = customtkinter.CTkLabel(root_tk, text="glasses height:")
self.label_height.place(relx=0.1, rely=0.77, anchor=tkinter.CENTER)
self.button_add_Face = customtkinter.CTkButton(root_tk, width=200, height=50, border_width=0, corner_radius=8, hover=True, text="Adicionar Rostos", command=print("added"))
self.button_add_Face.place(relx=0.1, rely=0.6, anchor=tkinter.CENTER)
def theme_change(self):
if self.switch.get() == 1:
customtkinter.set_appearance_mode("dark")
else:
customtkinter.set_appearance_mode("light")
start = GUI(root_tk)
root_tk.mainloop()
According to the source code of the CTkBaseClass for the widgets. The background color should be the same as the fg_color of your master as long as you haven't defined explicitly a bg_color for your widget.
Look at the configure method of the BaseClass and follow it to the detect_color_of_master.
the objective is to make the label's background the same as the frame
in both dark and light themes
So this should do the trick:
Frame1 = customtkinter.CTkFrame(root_tk,fg_color=root_tk.fg_color)
Frame1.pack()
self.button_add_Face = customtkinter.CTkButton(Frame1, width=200, height=50, border_width=0, corner_radius=8, hover=True, text="Adicionar Rostos", command=print("added"), border_color=root_tk.fg_color)
But you may are more interested in the ThemeManager. There are some Themes and you could just do another .json file in the form of the examples and add it in this directory to apply your own style.
Related
I'm using Tkinter to create an application, and with this Dashboard class, I'm trying to get a pop out window to show another canvas, so I can use create_image and tag_bind on the pop out. The result I'm currently getting is that the second canvas appears over the first canvas instead of in the pop out window.
import tkinter as tk
from tkinter import *
class Dashboard(tk.Tk):
"""
Configures, and displays the Dashboard
"""
def __init__(self):
tk.Tk.__init__(self)
self.config(width=1440, height=1024)
canvas = tk.Canvas(self, bg="#343333", height=1024, width=1440, bd=0, highlightthickness=0, relief="ridge")
canvas.place(x=0, y=0)
# Captures the background image for the canvas
image_path = "dashboard_background.png"
self.background_img = tk.PhotoImage(file=image_path)
canvas.create_image(0, 0, anchor='nw', image=self.background_img)
def logoutbuttonClicker():
pop = Toplevel(self)
pop.geometry('537x273')
pop.config(height=273, width=537)
logout_canvas = tk.Canvas(canvas, bg="#ffffff", height=273, width=537, bd=0, highlightthickness=0, relief="ridge")
logout_canvas.place(x=0, y=0)
self.logout_background_img = PhotoImage(file=f"logout_background.png")
logout_canvas.create_image(268.5, 136.5, anchor='nw', image=self.logout_background_img)
self.logout_yes_img = PhotoImage(file=f"logout_yes.png")
self.logout_no_img = PhotoImage(file=f"logout_no.png")
logout_image_path = "dashboard_logout.png"
self.logout_image = tk.PhotoImage(file=logout_image_path)
logoutButton = canvas.create_image(45, 950, anchor='nw', image=self.logout_image)
canvas.tag_bind(logoutButton, "<ButtonRelease-1>", lambda event: logoutbuttonClicker())
def main():
app = Dashboard()
app.mainloop()
if __name__ == '__main__':
main()
This is how it currently appears in the UI
I would like to click a button and view its content on the rest of the screen (where the gray color is), but through the frame, not across the canvas.
I would need 2 examples, but apply to my code please:
example 1: click on button 1 and color the page (as in the classic use in these frames) with the code written in the same single file
example 2: click on the button and import an external py file as a module, then the contents of the external file will open completely inside the gray screen
I would need these two simple examples, because for each frame (therefore for each button) I will have a long enough code and I would like to manage it in an orderly and clean way. So I would like to test both examples, but applied to my code.
I've seen examples on the web and on StackOverflow before, but I couldn't apply myself to my code. Can you please help me use my code?
(my code below)
from tkinter import messagebox
import tkinter as tk
from tkinter import ttk
from PIL import ImageTk, Image
root = tk.Tk()
root.title("xxxx")
root.geometry("1920x1080+0+0")
root.config(bg="#f0f0f0")
root.state("normal")
topbar = tk.Frame(root, background="#e10a0a", height=43)
topbar.pack(fill='x') # use pack() instead of place()
leftbar = tk.Frame(root, width=250, background="white")
leftbar.pack(side='left', fill='y') # use pack() instead of place()
leftbar.pack_propagate(0) # disable size auto-adjustment
def clicked(btn):
for w in leftbar.winfo_children():
w['bg'] = 'white' if w is not btn else 'yellow'
button1 = tk.PhotoImage(file="/image.png")
btn1 = tk.Button(leftbar, image=button1, borderwidth=0, highlightthickness=0,
bg="white", text="aaaaa", foreground='green', compound='left', anchor='w')
btn1.pack(fill='x') # use pack() instead of place()
btn1['command'] = lambda: clicked(btn1)
button2 = tk.PhotoImage(file="/image.png")
btn2 = tk.Button(leftbar, image=button2, borderwidth=0, highlightthickness=0,
bg="white", text="bbbbb", foreground='green', compound='left', anchor='w')
btn2.pack(fill='x') # use pack() instead of place()
btn2['command'] = lambda: clicked(btn2)
root.mainloop()
I would suggest you create a separate class by subclassing tk.Frame and implement the logic of tab change there.
import tkinter as tk
from PIL import ImageTk, Image
class TabBar(tk.Frame):
def __init__(self, *args, **kwargs):
super(TabBar, self).__init__(*args, **kwargs)
self.side_bar = tk.Frame(self, background="white")
# self.side_bar.place(relx=0, rely=0, relheight=1, relwidth=0.2)
self.side_bar.pack(side="left", fill="both")
self.tabs = {}
self.active_tab = None
self.active_color = "yellow"
self.default_color = "grey"
def addTab(self, name, widget, image: ImageTk.PhotoImage=None):
btn = tk.Button(self.side_bar, text=name, image=image,
compound="left", command=lambda: self.setActive(name),
bg=self.default_color, width=20, relief="flat")
btn.pack(fill="x", anchor="n")
self.tabs[name] = [btn, widget]
if self.active_tab is None:
self.setActive(name)
def setActive(self, name):
if self.active_tab:
# self.tabs[self.active_tab][1].place_forget()
self.tabs[self.active_tab][1].pack_forget()
self.tabs[self.active_tab][0].config(bg=self.default_color)
self.tabs[name][0].config(bg=self.active_color)
# self.tabs[name][1].place(relx=0.2, rely=0, relheight=1, relwidth=1)
self.tabs[name][1].pack(side="left", expand=True, fill="both")
self.active_tab = name
def removeTab(self, name):
self.tabs.pop(name)
In the above code, you can add tabs by using the addTab method, the name parameter should be unique for each tab as the name is being used as the key in the dictionary. Optionally you can pass PhotoImage instance to image parameter to display the image.
You can put the above class in the same file or a different file and import it.
usage example:
root = tk.Tk()
root.config(bg="#f0f0f0")
imag = Image.open("image.png")
imagtk = ImageTk.PhotoImage(imag)
tab_bar = TabBar(root)
tab_bar.pack(expand=True, fill="both")
frame = tk.Frame(tab_bar)
button = tk.Button(frame, text="Click Me")
button.pack()
tab_bar.addTab("aaaa", tk.Label(tab_bar, text="contents"), imagtk)
tab_bar.addTab("bbbb", frame)
root.mainloop()
(note: You need to pass tab_bar as parent to your widgets the widgets that you want to place inside the tab)
Output:
You can use a ttk.Notebook to achieve what you want:
import tkinter as tk
from tkinter import ttk
from PIL import ImageTk
# define classes for each page
class Page1(tk.Frame):
def __init__(self, master, **kw):
super().__init__(master, **kw)
tk.Label(self, text='Hello', font='Arial 64 bold').pack(fill='both', expand=1)
class Page2(tk.Frame):
def __init__(self, master, **kw):
super().__init__(master, **kw)
tk.Label(self, text='Python is awesome', font='Times 24 bold', bg=self['bg']).pack()
self.logo = ImageTk.PhotoImage(file='images/python-logo.png')
tk.Label(self, image=self.logo, bg=self['bg']).pack(fill='both', expand=1)
root = tk.Tk()
root.geometry('640x480')
topbar = tk.Frame(root, bg='#e10a0a', height=43)
topbar.pack(fill='x')
style = ttk.Style()
style.theme_use('default') # select a theme that allows configuration of ttk.Notebook
# put the tabs at the left with white background
style.configure('TNotebook', tabposition='wn', background='white', tabmargins=0)
# configure tab with white background initially, yellow background when selected
style.configure('TNotebook.Tab', background='white', width=10, focuscolor='yellow', borderwidth=0)
style.map('TNotebook.Tab', background=[('selected', 'yellow')])
nb = ttk.Notebook(root)
nb.pack(fill='both', expand=1)
img = ImageTk.PhotoImage(file='images/div2.png')
page1 = Page1(nb)
page2 = Page2(nb, bg='pink', bd=0)
nb.add(page1, text='aaaaa', image=img, compound='left')
nb.add(page2, text='bbbbb', image=img, compound='left')
root.mainloop()
Output:
You can also put the class definitions of each page to external files, for example Page1 in page1.py and Page2 in page2.py. Then import them into main script:
import tkinter as tk
from tkinter import ttk
from PIL import ImageTk
from page1 import Page1
from page2 import Page2
root = tk.Tk()
root.geometry('640x480')
topbar = tk.Frame(root, bg='#e10a0a', height=43)
topbar.pack(fill='x')
style = ttk.Style()
style.theme_use('default') # select a theme that allows configuration of ttk.Notebook
# put the tabs at the left with white background
style.configure('TNotebook', tabposition='wn', background='white', tabmargins=0)
# configure tab with white background initially, yellow background when selected
style.configure('TNotebook.Tab', background='white', width=10, focuscolor='yellow', borderwidth=0)
style.map('TNotebook.Tab', background=[('selected', 'yellow')])
nb = ttk.Notebook(root)
nb.pack(fill='both', expand=1)
img = ImageTk.PhotoImage(file='images/div2.png')
page1 = Page1(nb)
page2 = Page2(nb, bg='pink', bd=0)
nb.add(page1, text='aaaaa', image=img, compound='left')
nb.add(page2, text='bbbbb', image=img, compound='left')
root.mainloop()
page1.py
import tkinter as tk
class Page1(tk.Frame):
def __init__(self, master, **kw):
super().__init__(master, **kw)
tk.Label(self, text='Hello', font='Arial 64 bold').pack(fill='both', expand=1)
page2.py
import tkinter as tk
from PIL import ImageTk
class Page2(tk.Frame):
def __init__(self, master, **kw):
super().__init__(master, **kw)
tk.Label(self, text='Python is awesome', font='Times 24 bold', bg=self['bg']).pack()
self.logo = ImageTk.PhotoImage(file='images/python-logo.png')
tk.Label(self, image=self.logo, bg=self['bg']).pack(fill='both', expand=1)
I want to fit this frame with scrollbar(refer the provided image) in the black space present in the provided image. How do I do that. The frame should totally cover the black space.
The code for program.The image
from tkinter import *
from tkinter import ttk
C = Tk()
C.maxsize(1200, 750)
C.geometry("1200x750")
C.title("Mainscreen")
style = ttk.Style()
style.theme_use('clam')
BG = PhotoImage(file="Mainscreen bg.png")
ML = PhotoImage(file="Music_label.png")
BG_label = Label(C, image=BG, border=0)
BG_label.place(x=0, y=0)
style.configure("Vertical.TScrollbar", gripcount=0,
background="Cyan", darkcolor="gray6", lightcolor="LightGreen",
troughcolor="Turquoise4", bordercolor="gray6", arrowcolor="gray6",arrowsize=15)
wrapper1= LabelFrame(C, width="1600", height="100", background="gray6",bd=0)
mycanvas = Canvas(wrapper1,background="gray6",borderwidth=0, highlightthickness=0, width=700, height=600)
mycanvas.pack(side=LEFT, expand="false", padx=0)
yscrollbar = ttk.Scrollbar(wrapper1, orient="vertical",command=mycanvas.yview)
yscrollbar.pack(side=RIGHT, fill="y")
mycanvas.configure(yscrollcommand=yscrollbar.set)
mycanvas.bind('<Configure>',lambda e: mycanvas.configure(scrollregion=mycanvas.bbox("all")))
myframe = Frame(mycanvas)
mycanvas.create_window((0,0), window=myframe, anchor="n")
wrapper1.pack(side=RIGHT,expand="false", padx=0, pady=200)
for i in range(50):
Button(myframe, image=ML,bg="gray6",bd=0).pack()
mainloop()
EDIT:
Music_Label
Mainscreen bg
So after trying to understand the underlying problem for a while I have reached the conclusion, that the problem is with the fact that the button are being drawn in the myframe and the myframe is outside the mycanvas which contains the scrollbar. So by changing the master widget for the button from myframe to mycanvas, the problem gets fixed now the scrollbar is adjacent to the buttons. BUT, Also now the button r shifted the side since while packing the wrapper1, you did side = RIGHT, so I would also suggest that you use place here instead of pack, since pack depends on the space available and is not reliable if you are using a Background for your GUI and want the buttons within a portion of it.
I have changed the following lines -:
Button(mycanvas, image=ML,bg="gray6",bd=0).pack() # Changed to mycanvas from myframe
and
wrapper1.place(x = {YOUR X, WHERE THE BOX STARTS}, y = {YOUR Y, WHERE THE BOX STARTS}) # Use place instead..
You can use pack also, and change the padx and pady arguments but it will be tricky to get it to work always as expected.
The fixed code is this -:
from tkinter import *
from tkinter import ttk
C = Tk()
C.maxsize(1200, 750)
C.geometry("1200x750")
C.title("Mainscreen")
style = ttk.Style()
style.theme_use('clam')
BG = PhotoImage(file="Mainscreen bg.png")
ML = PhotoImage(file="Music_label.png")
BG_label = Label(C, image=BG, border=0)
BG_label.place(x=0, y=0)
style.configure("Vertical.TScrollbar", gripcount=0,
background="Cyan", darkcolor="gray6", lightcolor="LightGreen",
troughcolor="Turquoise4", bordercolor="gray6", arrowcolor="gray6",arrowsize=15)
wrapper1= LabelFrame(C, width="1600", height="100", background="gray6",bd=0)
mycanvas = Canvas(wrapper1,background="gray6",borderwidth=0, highlightthickness=0, width=700, height=600)
mycanvas.pack(side=LEFT, expand=False, padx=0)
yscrollbar = ttk.Scrollbar(wrapper1, orient="vertical",command=mycanvas.yview)
yscrollbar.pack(side=RIGHT, fill="y", expand = False)
mycanvas.configure(yscrollcommand=yscrollbar.set)
mycanvas.bind('<Configure>',lambda e: mycanvas.configure(scrollregion=mycanvas.bbox("all")))
myframe = Frame(mycanvas)
mycanvas.create_window((0,0), window=myframe, anchor="n")
wrapper1.pack(expand=True, padx=0, pady=200) # Use place instead
for i in range(50):
Button(mycanvas, image=ML,bg="gray6",bd=0).pack() # Change this to mycanvas from myframe
mainloop()
I've been researching this question, but none of the solutions I've found seem to work. I'm trying to get a Label (self.status_bar in the code below) to appear in my frame, but any edits (i.e. using update() method or resizing the frame/text widget/window) I've made have gotten me nowhere.
from tkinter import *
from tkinter import filedialog
from tkinter import font
#Build frame with features to put into parent window
class TextEditor:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
#Create Scrollbar
self.text_scroll = tk.Scrollbar(self.frame)
self.text_scroll.pack(side=RIGHT, fill=Y)
#Create text box
self.text = tk.Text(self.frame, width=155, height=55, font=('Helvetica', 12), selectbackground="yellow",
selectforeground = "black", undo=True, yscrollcommand=self.text_scroll.set)
self.text.pack()
#Configure scrollbar
self.text_scroll.config(command=self.text.yview)
#Create menu
self.menu = tk.Menu(self.master)
self.master.config(menu=self.menu)
#Add file menu
self.file_menu = tk.Menu(self.menu, tearoff=False)
self.menu.add_cascade(label="File", menu=self.file_menu)
self.file_menu.add_command(label="Open")
self.file_menu.add_command(label="Save")
self.file_menu.add_command(label="New")
self.file_menu.add_separator()
self.file_menu.add_command(label="Exit", command=self.master.destroy)
#Add edit menu
self.edit_menu = tk.Menu(self.menu, tearoff=False)
self.menu.add_cascade(label="Edit", menu=self.edit_menu)
self.edit_menu.add_command(label="Cut")
self.edit_menu.add_command(label="Copy")
self.edit_menu.add_command(label="Undo")
self.edit_menu.add_command(label="Redo")
#Add status bar to bottom of app
self.status_bar = tk.Label(self.frame, text="Ready", anchor=E)
self.status_bar.pack(fill=X, side=BOTTOM, ipady=5)
#Pack frame into window
self.frame.pack()
#Instantiates the text editor app
def main():
root = tk.Tk()
app = TextEditor(root)
root.geometry("1220x660")
root.title("Text Editor")
root.mainloop()
if __name__ == '__main__':
main()
You are forcing the window to a size that is too small to fit all of the widgets. When you do that while using pack, pack will start to shrink widgets in order to make them fit, starting with the last widget that was packed. In this case that's the status bar. So, pack starts removing pixels from self.status_bar until there's enough room for the other widgets. Eventually, it has to completely remove the status bar, and then start shrinking the text widget.
The first step is to create the status bar first, so that the text widget is higher in the stacking order (ie: pack will try to shrink it before shrinking other widgets).
The second thing you should do is use the appropriate options to get the TextEditor window to fill the frame, and get the frame to fill the window. For example:
self.text.pack(fill="both", expand=True)
self.frame.pack(fill="both", expand=True)
I suggest, with the more complicated layout you have, that you use the grid method instead of pack. Here is the code with the widgets gridded instead of packed:
import tkinter as tk
from tkinter import filedialog
from tkinter import font
from tkinter.constants import *
#Build frame with features to put into parent window
class TextEditor:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
#Create Scrollbar
self.text_scroll = tk.Scrollbar(self.frame)
self.text_scroll.grid(row=0, column=1, sticky=E+NS) ### EDITED THIS LINE
#Create text box
self.text = tk.Text(self.frame, font=('Helvetica', 12), selectbackground="yellow", ### EDITED THIS LINE
selectforeground = "black", undo=True, yscrollcommand=self.text_scroll.set)
self.text.grid(row=0, column=0, sticky=NSEW) ### EDITED THIS LINE
#Configure scrollbar
self.text_scroll.config(command=self.text.yview)
#Create menu
self.menu = tk.Menu(self.master)
self.master.config(menu=self.menu)
#Add file menu
self.file_menu = tk.Menu(self.menu, tearoff=False)
self.menu.add_cascade(label="File", menu=self.file_menu)
self.file_menu.add_command(label="Open")
self.file_menu.add_command(label="Save")
self.file_menu.add_command(label="New")
self.file_menu.add_separator()
self.file_menu.add_command(label="Exit", command=self.master.destroy)
#Add edit menu
self.edit_menu = tk.Menu(self.menu, tearoff=False)
self.menu.add_cascade(label="Edit", menu=self.edit_menu)
self.edit_menu.add_command(label="Cut")
self.edit_menu.add_command(label="Copy")
self.edit_menu.add_command(label="Undo")
self.edit_menu.add_command(label="Redo")
#Add status bar to bottom of app
self.status_bar = tk.Label(self.frame, text="Ready", anchor=E)
self.status_bar.grid(row=1, column=0, sticky=S+EW) ### EDITED THIS LINE
# Configure the rows and columns so that they expand properly ### ADDED THESE LINES
self.frame.rowconfigure(0, weight=1) ### ADDED THESE LINES
self.frame.columnconfigure(0, weight=1) ### ADDED THESE LINES
#Pack frame into window
self.frame.pack(expand=YES, fill=BOTH) ### EDITED THIS LINE
#Instantiates the text editor app
def main():
root = tk.Tk()
app = TextEditor(root)
root.geometry("1220x660")
root.title("Text Editor")
root.mainloop()
if __name__ == '__main__':
main()
Notice how I also changed the line where the frame is packed into the window. The only thing keeping the frame filling the window before was the size of the text widget.
With these changes, the widgets expand properly, so I also removed the width and height parameters from the creation of self.text.
TkVersion = 8.6, Python version 3.7.3
Im trying to create a button in python with tkinter using a PNG image. The transparent corners of the image are transparent depending on which widget I use. It seems canvas.create_image is the only widget retaining the transparency.
First I added the image on a canvas using create_image(0,0, image=button) and it works fine - the rounded corners are transparent.
But then when I try to implement it as an actual button using Button() and create_window() widgets, the corners are filled with white.
button = ImageTk.PhotoImage(file="button.png")
canvas = tk.Canvas(width=200, heigh=200, borderwidth=0, highlightthickness=0)
canvas.grid()
canvas.create_rectangle(0,0,199,199, fill="blue")
canvas.create_image(0,0, image=button, anchor="nw")
[]
button = ImageTk.PhotoImage(file="button.png")
canvas = tk.Canvas(width=200, heigh=200, borderwidth=0, highlightthickness=0)
canvas.grid()
canvas.create_rectangle(0,0,199,199, fill="blue")
buttonWidget = tk.Button(root, image=button)
canvas.create_window(0,0, window=buttonWidget, anchor="nw")
How can I make the PNG button corners transparent?
Here is also the button image:
You can make your own custom button class inherited from canvas and use it just like you use Button(). I made one for you hopefully you find it helpful.
Custom Button Class:
Save this class in a separate file as imgbutton.py and then import it to your main file. Also make sure it is in the same directory as the main file is in. Or you can just keep it on the top of the main file after your imports.
import tkinter as tk
class Imgbutton(tk.Canvas):
def __init__(self, master=None, image=None, command=None, **kw):
# Declared style to keep a reference to the original relief
style = kw.get("relief", "groove")
if not kw.get('width') and image:
kw['width'] = image.width()
else: kw['width'] = 50
if not kw.get('height') and image:
kw['height'] = image.height()
else: kw['height'] = 24
kw['relief'] = style
kw['borderwidth'] = kw.get('borderwidth', 2)
kw['highlightthickness'] = kw.get('highlightthickness',0)
super(Imgbutton, self).__init__(master=master, **kw)
self.set_img = self.create_image(kw['borderwidth'], kw['borderwidth'],
anchor='nw', image=image)
self.bind_class( self, '<Button-1>',
lambda _: self.config(relief='sunken'), add="+")
# Used the relief reference (style) to change back to original relief.
self.bind_class( self, '<ButtonRelease-1>',
lambda _: self.config(relief=style), add='+')
self.bind_class( self, '<Button-1>',
lambda _: command() if command else None, add="+")
Here is an Example how to use it
import tkinter as tk
from imgbutton import Imgbutton # Import the custom button class
root = tk.Tk()
root['bg'] = 'blue'
but_img = tk.PhotoImage(file='button.png')
but = Imgbutton(root, image=but_img, bg='blue',
command=lambda: print("Button Image"))
but.pack(pady=10)
root.mainloop()