PC Cleaner
In this example, I demonstrate how to use various styles to build a UI for a PC Cleaner application. This is adapted
from an image you can find here. The overall theme is pulse. This application includes several widget styles
including a custom header style which is configured in the init
method that changes the background and foreground
colors from theme colors available in the Style.colors
property.
- Action buttons
info.TButton
- Progressbar
success.Striped.Horizontal.TProgressbar
There is a secondary.TButton
style applied to the result card frames. This gives the cards the same format as a
button for any attributes they share. This effectively gives it a highlight color and hover effect. Additionally, by
putting another label or card inside with padding around, you can create a border effect, with the card background
serving as the border. By increasing the internal padding, you can effectively increase the border size.
Run this code live on repl.it
"""
Author: Israel Dryer
Modified: 2021-04-09
Adapted from: https://images.idgesg.net/images/article/2018/08/cw_win10_utilities_ss_02-100769136-orig.jpg
"""
import tkinter
from tkinter import ttk
from pathlib import Path
from ttkbootstrap import Style
class Application(tkinter.Tk):
def __init__(self):
super().__init__()
self.title('PC Cleaner')
self.style = Style('pulse')
self.cleaner = Cleaner(self)
self.cleaner.pack(fill='both', expand='yes')
# custom styles
self.style.configure('header.TLabel', background=self.style.colors.secondary, foreground=self.style.colors.info)
# do not allow window resizing
self.resizable(False, False)
class Cleaner(ttk.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# application images
p = Path(__file__).parent
self.logo_img = tkinter.PhotoImage(name='logo', file=p/'assets/icons8_broom_64px_1.png')
self.brush_img = tkinter.PhotoImage(name='cleaner', file=p/'assets/icons8_broom_64px.png')
self.registry_img = tkinter.PhotoImage(name='registry', file=p/'assets/icons8_registry_editor_64px.png')
self.tools_img = tkinter.PhotoImage(name='tools', file=p/'assets/icons8_wrench_64px.png')
self.options_img = tkinter.PhotoImage(name='options', file=p/'assets/icons8_settings_64px.png')
self.privacy_img = tkinter.PhotoImage(name='privacy', file=p/'assets/icons8_spy_80px.png')
self.junk_img = tkinter.PhotoImage(name='junk', file=p/'assets/icons8_trash_can_80px.png')
self.protect_img = tkinter.PhotoImage(name='protect', file=p/'assets/icons8_protect_40px.png')
# header
header_frame = ttk.Frame(self, padding=20, style='secondary.TFrame')
header_frame.grid(row=0, column=0, columnspan=3, sticky='ew')
ttk.Label(header_frame, image='logo', style='header.TLabel').pack(side='left')
logo_text = ttk.Label(header_frame, text='pc cleaner', font=('TkDefaultFixed', 30), style='header.TLabel')
logo_text.pack(side='left', padx=10)
# action buttons
action_frame = ttk.Frame(self)
action_frame.grid(row=1, column=0, sticky='nsew')
cleaner_btn = ttk.Button(action_frame, image='cleaner', text='cleaner', compound='top', style='info.TButton')
cleaner_btn.pack(side='top', fill='both', ipadx=10, ipady=10)
registry_btn = ttk.Button(action_frame, image='registry', text='registry', compound='top', style='info.TButton')
registry_btn.pack(side='top', fill='both', ipadx=10, ipady=10)
tools_btn = ttk.Button(action_frame, image='tools', text='tools', compound='top', style='info.TButton')
tools_btn.pack(side='top', fill='both', ipadx=10, ipady=10)
options_btn = ttk.Button(action_frame, image='options', text='options', compound='top', style='info.TButton')
options_btn.pack(side='top', fill='both', ipadx=10, ipady=10)
# option notebook
notebook = ttk.Notebook(self)
notebook.grid(row=1, column=1, sticky='nsew', pady=(25, 0))
## windows tab
windows_tab = ttk.Frame(notebook, padding=10)
wt_scrollbar = tkinter.Scrollbar(windows_tab)
wt_scrollbar.pack(side='right', fill='y')
wt_canvas = tkinter.Canvas(windows_tab, border=0, highlightthickness=0, yscrollcommand=wt_scrollbar.set)
wt_canvas.pack(side='left', fill='both')
### adjust the scrollregion when the size of the canvas changes
wt_canvas.bind('<Configure>', lambda e: wt_canvas.configure(scrollregion=wt_canvas.bbox('all')))
wt_scrollbar.configure(command=wt_canvas.yview)
scroll_frame = ttk.Frame(wt_canvas)
wt_canvas.create_window((0, 0), window=scroll_frame, anchor='nw')
radio_options = [
'Internet Cache', 'Internet History', 'Cookies', 'Download History', 'Last Download Location',
'Session', 'Set Aside Tabs', 'Recently Typed URLs', 'Saved Form Information', 'Saved Password']
edge = ttk.Labelframe(scroll_frame, text='Microsoft Edge', padding=(20, 5))
edge.pack(fill='both')
explorer = ttk.Labelframe(scroll_frame, text='Internet Explorer', padding=(20, 5))
explorer.pack(fill='both', pady=10)
### add radio buttons to each label frame section
for section in [edge, explorer]:
for opt in radio_options:
cb = ttk.Checkbutton(section, text=opt, state='normal')
cb.invoke()
cb.pack(side='top', pady=2, fill='x')
notebook.add(windows_tab, text='windows')
## empty tab for looks
notebook.add(ttk.Frame(notebook), text='applications')
# results frame
results_frame = ttk.Frame(self)
results_frame.grid(row=1, column=2, sticky='nsew')
## progressbar with text indicator
pb_frame = ttk.Frame(results_frame, padding=(0, 10, 10, 10))
pb_frame.pack(side='top', fill='x', expand='yes')
pb = ttk.Progressbar(pb_frame, style='success.Striped.Horizontal.TProgressbar', variable='progress')
pb.pack(side='left', fill='x', expand='yes', padx=(15, 10))
ttk.Label(pb_frame, text='%').pack(side='right')
ttk.Label(pb_frame, textvariable='progress').pack(side='right')
self.setvar('progress', 78)
## result cards
cards_frame = ttk.Frame(results_frame, name='cards-frame', style='secondary.TFrame')
cards_frame.pack(fill='both', expand='yes')
### privacy card
priv_card = ttk.Frame(cards_frame, padding=1, style='secondary.TButton')
priv_card.pack(side='left', fill='both', padx=(10, 5), pady=10)
priv_container = ttk.Frame(priv_card, padding=40)
priv_container.pack(fill='both', expand='yes')
priv_lbl = ttk.Label(priv_container, image='privacy', text='PRIVACY', compound='top', anchor='center')
priv_lbl.pack(fill='both', padx=20, pady=(40, 0))
ttk.Label(priv_container, textvariable='priv_lbl', style='primary.TLabel').pack(pady=(0, 20))
self.setvar('priv_lbl', '6025 tracking file(s) removed')
### junk card
junk_card = ttk.Frame(cards_frame, padding=1, style='secondary.TButton')
junk_card.pack(side='left', fill='both', padx=(5, 10), pady=10)
junk_container = ttk.Frame(junk_card, padding=40)
junk_container.pack(fill='both', expand='yes')
junk_lbl = ttk.Label(junk_container, image='junk', text='PRIVACY', compound='top', anchor='center')
junk_lbl.pack(fill='both', padx=20, pady=(40, 0))
ttk.Label(junk_container, textvariable='junk_lbl', style='primary.TLabel', justify='center').pack(pady=(0, 20))
self.setvar('junk_lbl', '1,150 MB of unneccesary file(s)\nremoved')
## user notification
note_frame = ttk.Frame(results_frame, style='secondary.TFrame', padding=40)
note_frame.pack(fill='both')
note_msg = ttk.Label(note_frame, text='We recommend that you better protect your data', anchor='center',
style='header.TLabel', font=('Helvetica', 12, 'italic'))
note_msg.pack(fill='both')
if __name__ == '__main__':
Application().mainloop()