1. はじめに
CustomTkinterは簡単におしゃれなGUIを実現可能なライブラリで素晴らしいのですが、いまいちどう設定していいのかわかりにくいところもあります。
そこで以下のリンク先でウィジェットプレビューツールを作りました。
しかしながら、このウィジェットプレビューツールを拡張してカスタムテーマ作成ツールを作るのは設定項目が多すぎて、ちょっと使いにくそうだったので、もう少し簡易的にカスタムテーマを作れるツールを検討してみました。
できた画面は以下の通りです。
動かしてみると以下のような感じです。
1.1. 開発環境
Windows 10 Pro 64bit
Python 3.9.13
CustomTkinter 5.1.2
2. CustomTkinterのカスタムテーマ設定
CustomTkinterにはテーマ設定をjsonでまとめておいて、一括読み込みする手段が用意されています。
customtkinter.set_default_color_theme("./custom_theme.json")
参考となる3種類のデフォルトテーマのjsonが公開されており、中身は以下のような形で各ウィジェットをキーとしてその下にオプション引数の設定が記述されています。
{
"CTk": {
"fg_color": ["gray92", "gray14"]
},
"CTkToplevel": {
"fg_color": ["gray92", "gray14"]
},
"CTkFrame": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["gray86", "gray17"],
"top_fg_color": ["gray81", "gray20"],
"border_color": ["gray65", "gray28"]
},
...(後略)...
しかし用意されているとはいえ、このjsonを狙いのテーマにまとめる作業は大変そうで気が遠くなってしまいます。
3. 簡易カスタムテーマ作成ツール
上記のカスタムテーマについては公式Wikiに記載がありますが、そもそもオプション引数だけではどれがどの色かわからん!ということで、1.はじめに で紹介したプレビューツールを作ってみたりしていました。
しかしプレビューツールを作っている際に、変更がすぐ反映されるのは楽だし、面白いなーと思いましたが、これでカスタムテーマを作るのはやはり面倒だなと気付きました笑
そこでもう少し簡易的にカスタムテーマ作成を行えるツールを考えてみました。
3.1. 概要
CustomTkinterは背景などは基本的にグレーの階調を変えているだけで、メインとなる彩度の高い色は一部のみであるため、デフォルトテーマで設定されている グレー以外の色を抽出して、それを置換する ことで新たなカスタムテーマを作成するツールとしました。
3.2. 使い方
- 上段フレームの3つのスライダーを左右に振る
(3つのスライダーはそれぞれ色相(Hue)、彩度(Saturation)、明度(Brightness/Value)を表しています) - 設定した配色が中段フレーム右側のウィジェットの色として確認できる。
- 希望の配色になったら、下段フレームでファイル名を指定して、カスタムテーマのjsonが保存可能
3.3. ソースコードの説明
3.3.1. 色の設定について
スライダーで変化する色のベースとなっているのはデフォルトのblue、dark-blue、greenで設定されている色をHSVモデルで表記した値です。
HSVモデルは色相(Hue)、彩度(Saturation)、明度(Brightness/Value)の頭文字を取ったもので、一般的に知られるRGBとは異なる色の表し方をしたものですが、RGBより人にとって直感的に認識が可能です。
そのためスライダーでHSVの値を指定して、HSVからRGB、RGBから16進数表記に変換させて色の設定に使っています。
必要なライブラリはcolorsys
とmatplotlib.colors
です。colorsys
は標準ライブラリなのでインストール不要で、matplotlib
はpip install
しておいてください。
import colorsys
import matplotlib.colors as mcolors
HSV値からRGB値への変換、RGB値から16進数表記への変換は以下のとおりです。
#hue, saturation, brightnessは0~1
colorsys.hsv_to_rgb(hue, saturation, brightness)
#R, G, Bは0~1
mcolors.to_hex((R, G, B))
したがって、以下のような配列を用意することで色相をグラデーションした配列を用意可能です。
color_bar_list = [f'{mcolors.to_hex(colorsys.hsv_to_rgb(hue/72, 0.7, 0.65))}' for hue in range(72)]
3.3.2. ベースとなる色について
CustomTkinter において、blue.jsonでボタンなどの配色に使われる青い色を抜き出して16進数表記からRGBとHSVへ変換すると下表のようになります。RGBでは各数値が複雑に変化してしまいますが、HSVでは色相(Hue)は一定で、彩度・明度が変化していることがわかります。
16進数表記 | R | G | B | H | S | V |
---|---|---|---|---|---|---|
#27577D |
39 | 87 | 125 | 206 | 68 | 49 |
#36719F |
54 | 113 | 159 | 206 | 66 | 62 |
#3B8ED0 |
59 | 142 | 208 | 206 | 71 | 81 |
#1F6AA5 |
31 | 106 | 165 | 206 | 81 | 64 |
#144870 |
20 | 72 | 112 | 206 | 82 | 43 |
#203A4F |
32 | 58 | 79 | 206 | 59 | 30 |
そのため、色相は全範囲(0~1)で変化させつつ、彩度と明度を範囲を絞って変化させることで、CustomTkinter のウィジェットの配色として破綻しない領域で自由に決められるようにしました。
実装としては以下のようにしています。
def color_set(self, event):
hue, sat, val = self.slider_hsv[0].get(), self.slider_hsv[1].get(), self.slider_hsv[2].get()
bases = [[0.53,0.4], [0.5,0.5], [0.55,0.7], [0.45, 0.25], [0.65,0.33], [0.66,0.49]]
self.colors = [f'{mcolors.to_hex(colorsys.hsv_to_rgb(hue, base[0] + sat*0.3, base[1] + val*0.2))}' for i, base in enumerate(bases)]
for i in range(len(bases), len(bases)*2):
self.color_label[i].configure(fg_color=self.colors[i-len(bases)])
self.label_color2.configure(fg_color=self.colors[5])
self.color_label[i].delete(0, tk.END)
self.color_label[i].insert(0, self.colors[i-len(bases)])
HSVの基となる値をスライダー(0~1で設定)から取得、ベースとなる彩度・明度は事前に配列で用意しておき、colorsys.hsv_to_rgb(hue, base[0] + sat*0.3, base[1] + val*0.2)
という形で、ベースへの足し算で変化させるようにしています。
変化量としては彩度がベースから+0.3
まで、明度がベースから+0.2
までとすることで配色範囲を絞っています。
3.3.3. 本ツールで保存されるカスタムテーマのjsonファイルについて
ベースとなるjsonはpyファイル内に埋め込んでいます。
というのも、blue.jsonの色を抜き出していただけるとわかると思いますが、#DCE4EE
などわずかに青みがかったグレーが存在しますが、これはgreen.jsonでも使われており、単なるグレーとしての位置づけとして設定されています。
デフォルトのテーマには、こうしたほぼグレーだけどgray**
(**は0~100の数値)で書かれていない色が10数個存在します。
作者も気にしていないのだと思いますが、個人的には気になりますし、わかりにくいので、今回微妙な色がついたほぼグレー(#DCE4EE
など)はすべて近しいgray**
へ変換したjsonをpyファイル内に用意しています。
3.4. ソースコード
ソースコード
import json
import colorsys
import tkinter as tk
from tkinter import filedialog
import customtkinter as ctk
from functools import partial
import matplotlib.colors as mcolors
class App(ctk.CTk):
def __init__(self):
super().__init__()
self.title("Custom Theme Maker for CustomTkinter")
self.geometry("600x420")
# default color settings
ctk.set_appearance_mode("dark") # "system":default value, "dark", "light"
ctk.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue"
# set grid layout 1x2
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(0, weight=1)
# font settings
self.save_font = ctk.CTkFont(family='Yu Gothic', size=13, weight='bold')
# color list
self.blue = ['#27577D', '#36719F', '#3B8ED0', '#203A4F', '#144870', '#1F6AA5']
self.dark_blue = ['#234567', '#325882', '#3a7ebf', '#1e2c40', '#14375e', '#1f538d']
self.green = ['#0b6e3d', '#0C955A', '#2CC985', '#17472e', '#106A43', '#2FA572']
self.color_bar_list = [f'{mcolors.to_hex(colorsys.hsv_to_rgb(hue/72, 0.7, 0.65))}' for hue in range(72)]
# create frame
self.frame = [ctk.CTkFrame(self, corner_radius=10) for _ in range(3)]
self.frame[0].grid(row=0, column=0, padx=20, pady=(20,10), sticky='nsew')
self.frame[1].grid(row=1, column=0, padx=20, pady=(0,10), ipadx=10, ipady=10, sticky='nsew')
self.frame[2].grid(row=2, column=0, padx=20, pady=(0,20), sticky='nsew')
self.frame[0].grid_columnconfigure(1, weight=1)
self.frame[1].grid_rowconfigure((1,2,3), weight=1)
self.frame[1].grid_columnconfigure((0,1,2,3), weight=1)
self.frame[2].grid_columnconfigure(0, weight=1)
# frame[0] - Color bar
self.color_bar_frame = ctk.CTkFrame(self.frame[0], corner_radius=0, height=30, fg_color='transparent')
self.color_bar_frame.grid(row=0, column=1, padx=(6, 16), pady=10, sticky='nsew')
self.color_bar_frame.grid_rowconfigure(0, weight=1)
self.color_bar_frame.grid_columnconfigure(tuple(range(len(self.color_bar_list))), weight=1)
self.color_bar = [ctk.CTkLabel(self.color_bar_frame, corner_radius=0, fg_color=f'{color}', text='', padx=0, pady=0) for color in self.color_bar_list]
for i in range(72):
self.color_bar[i].grid(row=0, column=i, padx=0, pady=0, sticky='nsew')
# frame[0] - Slider for selecting color
self.label_hsv = [ctk.CTkLabel(self.frame[0], text=f'{item}') for item in ['Hue', 'Saturation', 'Brightness']]
self.slider_hsv = [ctk.CTkSlider(self.frame[0], from_=0, to=1, number_of_steps=i, orientation="horizontal", command=self.color_set) for i in [72, 11, 11]]
for i in range(3):
self.label_hsv[i].grid(row=i+1, column=0, padx=(10,0), pady=(0 if i<2 else (0,10)), sticky='nsew')
self.slider_hsv[i].grid(row=i+1, column=1, padx=(0,10), pady=(0 if i<2 else (0,10)), sticky='ew')
# frame[1] - color sample
self.label_color1 = ctk.CTkOptionMenu(self.frame[1], anchor="center", corner_radius=6,
values=['blue.json', 'dark-blue.json', 'green.json'],
command=self.reference_color)
self.label_color1.grid(row=0, column=0, columnspan=2, padx=(10,3), pady=(10,3), sticky='ew')
self.label_color2 = ctk.CTkLabel(self.frame[1], corner_radius=6, fg_color='#27577D', text='custom theme')
self.label_color2.grid(row=0, column=2, columnspan=2, padx=(3,10), pady=(10,3), sticky='ew')
self.color_label = [ctk.CTkEntry(self.frame[1], corner_radius=6, border_width=0, fg_color=f'{color}', justify="center") for color in self.blue*2]
for i, color in enumerate(self.blue*2):
self.color_label[i].grid(row=i%3+1, column=i//3, padx=((10,3) if i//3==0 else (3,10) if i//3==3 else 3), pady=((3,10) if i%3==3 else 3), sticky='nsew')
self.color_label[i].insert(0, f'{color}')
# frame[2] - save json file
self.file_name_entry = ctk.CTkEntry(self.frame[2], border_width=1, placeholder_text="file name of json file to save")
self.file_name_entry.grid(row=0, column=0, padx=(10,3), pady=(10,3), sticky='nsew')
self.file_name_button = ctk.CTkButton(self.frame[2], text='Browse', font=self.save_font,
fg_color='transparent', border_width=1, command=self.file_select)
self.file_name_button.grid(row=0, column=1, padx=(3,10), pady=(10,3), sticky='e')
self.save_button = ctk.CTkButton(self.frame[2], text='Save as json', font=self.save_font, command=self.save_json)
self.save_button.grid(row=1, column=1, padx=(3,10), pady=(3,10), sticky='e')
# 参考用カラーの表示設定
def reference_color(self, choice):
# OptionMenuから選択した情報を元にcolorに配色リストを代入
color = self.blue if choice == 'blue.json' else self.green if choice == 'green.json' else self.dark_blue
# 参考用カラーの適用
self.label_color1.configure(fg_color=color[5], button_color=color[4], button_hover_color=color[3])
self.save_button.configure(fg_color=color[5])
for i in range(len(color)):
self.color_label[i].configure(fg_color=color[i])
self.color_label[i].delete(0, tk.END)
self.color_label[i].insert(0, color[i])
# カスタムテーマとなる配色の表示設定
def color_set(self, event):
# スライダーからHSVの数値を取得(0~1)
hue, sat, val = self.slider_hsv[0].get(), self.slider_hsv[1].get(), self.slider_hsv[2].get()
# 初期値となるHSV値のうちSaturationとValue(Brightness)のリスト
bases = [[0.53,0.4], [0.5,0.5], [0.55,0.7], [0.45, 0.25], [0.65,0.33], [0.66,0.49]]
# スライダーから取得したHSV値と初期値から16進数表記のカラーコードを生成
self.colors = [f'{mcolors.to_hex(colorsys.hsv_to_rgb(hue, base[0] + sat*0.3, base[1] + val*0.2))}' for i, base in enumerate(bases)]
# ウィジェットへ適用
for i in range(len(bases), len(bases)*2):
self.color_label[i].configure(fg_color=self.colors[i-len(bases)])
self.label_color2.configure(fg_color=self.colors[5])
self.color_label[i].delete(0, tk.END)
self.color_label[i].insert(0, self.colors[i-len(bases)])
# 名前をつけて保存のダイアログボックス表示
def file_select(self):
file_name = filedialog.asksaveasfilename(title="名前をつけて保存", filetypes=[("json file", ".json")], initialdir = "./")
if file_name[-5:] != '.json' and file_name != '':
file_name += '.json'
if file_name != '':
self.file_name_entry.delete(0, tk.END)
self.file_name_entry.insert(0, file_name)
# jsonファイルの保存
def save_json(self):
default_json = '''{
"CTk": {
"fg_color": ["gray95", "gray10"]
},
"CTkToplevel": {
"fg_color": ["gray95", "gray10"]
},
"CTkFrame": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["gray90", "gray13"],
"top_fg_color": ["gray85", "gray16"],
"border_color": ["gray65", "gray28"]
},
"CTkButton": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["#3a7ebf", "#1f538d"],
"hover_color": ["#325882", "#14375e"],
"border_color": ["grey27", "grey60"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkLabel": {
"corner_radius": 0,
"fg_color": "transparent",
"text_color": ["gray14", "gray84"]
},
"CTkEntry": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray98", "gray21"],
"border_color": ["gray61", "grey35"],
"text_color": ["gray14", "gray84"],
"placeholder_text_color": ["gray52", "gray62"]
},
"CTkCheckbox": {
"corner_radius": 6,
"border_width": 3,
"fg_color": ["#3a7ebf", "#1f538d"],
"border_color": ["grey27", "grey60"],
"hover_color": ["#325882", "#14375e"],
"checkmark_color": ["grey89", "gray90"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkSwitch": {
"corner_radius": 1000,
"border_width": 3,
"button_length": 0,
"fg_Color": ["gray60", "grey30"],
"progress_color": ["#3a7ebf", "#1f538d"],
"button_color": ["gray36", "gray85"],
"button_hover_color": ["gray20", "gray100"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkRadiobutton": {
"corner_radius": 1000,
"border_width_checked": 6,
"border_width_unchecked": 3,
"fg_color": ["#3a7ebf", "#1f538d"],
"border_color": ["grey27", "grey60"],
"hover_color": ["#325882", "#14375e"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkProgressBar": {
"corner_radius": 1000,
"border_width": 0,
"fg_color": ["gray60", "grey30"],
"progress_color": ["#3a7ebf", "#1f538d"],
"border_color": ["gray", "gray"]
},
"CTkSlider": {
"corner_radius": 1000,
"button_corner_radius": 1000,
"border_width": 6,
"button_length": 0,
"fg_color": ["gray60", "grey30"],
"progress_color": ["gray40", "gray69"],
"button_color": ["#3a7ebf", "#1f538d"],
"button_hover_color": ["#325882", "#14375e"]
},
"CTkOptionMenu": {
"corner_radius": 6,
"fg_color": ["#3a7ebf", "#1f538d"],
"button_color": ["#325882", "#14375e"],
"button_hover_color": ["#234567", "#1e2c40"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkComboBox": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray98", "gray21"],
"border_color": ["gray61", "grey35"],
"button_color": ["gray61", "grey35"],
"button_hover_color": ["grey44", "grey52"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray50", "gray45"]
},
"CTkScrollbar": {
"corner_radius": 1000,
"border_spacing": 4,
"fg_color": "transparent",
"button_color": ["gray55", "gray41"],
"button_hover_color": ["gray40", "gray53"]
},
"CTkSegmentedButton": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray61", "gray29"],
"selected_color": ["#3a7ebf", "#1f538d"],
"selected_hover_color": ["#325882", "#14375e"],
"unselected_color": ["gray61", "gray29"],
"unselected_hover_color": ["gray70", "gray41"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkTextbox": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["gray100", "gray20"],
"border_color": ["gray61", "grey35"],
"text_color": ["gray14", "gray84"],
"scrollbar_button_color": ["gray55", "gray41"],
"scrollbar_button_hover_color": ["gray40", "gray53"]
},
"CTkScrollableFrame": {
"label_fg_color": ["gray80", "gray21"]
},
"DropdownMenu": {
"fg_color": ["gray90", "gray20"],
"hover_color": ["gray75", "gray28"],
"text_color": ["gray14", "gray84"]
},
"CTkFont": {
"macOS": {
"family": "SF Display",
"size": 13,
"weight": "normal"
},
"Windows": {
"family": "Roboto",
"size": 13,
"weight": "normal"
},
"Linux": {
"family": "Roboto",
"size": 13,
"weight": "normal"
}
}
}
'''
# エントリーボックスからファイル名を取得
file_name = self.file_name_entry.get()
# 置換元の色のリスト
replace_words = ['#234567', '#325882', '#3a7ebf', '#1e2c40', '#14375e', '#1f538d']
# エントリーボックスから置換先のリストを取得
colors = [self.color_label[i+len(replace_words)].get() for i in range(len(replace_words))]
# 色を置換
for i, replace_word in enumerate(replace_words):
default_json = default_json.replace(replace_word, colors[i])
# 文字列からjsonに変換
default_json = json.loads(default_json)
# jsonファイルを保存
if file_name != '':
with open(file_name, 'w') as f:
json.dump(default_json, f, indent=4)
def main():
app = App()
app.mainloop()
if __name__ == "__main__":
main()
3.5. 作例
実際に作ってみた作例を以下に載せてみます。
公式サイトのcomplex_example.pyへ適用したものになります。
3.5.1. red
red.json
{
"CTk": {
"fg_color": ["gray95", "gray10"]
},
"CTkToplevel": {
"fg_color": ["gray95", "gray10"]
},
"CTkFrame": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["gray90", "gray13"],
"top_fg_color": ["gray85", "gray16"],
"border_color": ["gray65", "gray28"]
},
"CTkButton": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["#ca2f2f", "#941212"],
"hover_color": ["#972a2a", "#6b0e0e"],
"border_color": ["grey27", "grey60"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkLabel": {
"corner_radius": 0,
"fg_color": "transparent",
"text_color": ["gray14", "gray84"]
},
"CTkEntry": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray98", "gray21"],
"border_color": ["gray61", "grey35"],
"text_color": ["gray14", "gray84"],
"placeholder_text_color": ["gray52", "gray62"]
},
"CTkCheckbox": {
"corner_radius": 6,
"border_width": 3,
"fg_color": ["#ca2f2f", "#941212"],
"border_color": ["grey27", "grey60"],
"hover_color": ["#972a2a", "#6b0e0e"],
"checkmark_color": ["grey89", "gray90"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkSwitch": {
"corner_radius": 1000,
"border_width": 3,
"button_length": 0,
"fg_Color": ["gray60", "grey30"],
"progress_color": ["#ca2f2f", "#941212"],
"button_color": ["gray36", "gray85"],
"button_hover_color": ["gray20", "gray100"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkRadiobutton": {
"corner_radius": 1000,
"border_width_checked": 6,
"border_width_unchecked": 3,
"fg_color": ["#ca2f2f", "#941212"],
"border_color": ["grey27", "grey60"],
"hover_color": ["#972a2a", "#6b0e0e"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkProgressBar": {
"corner_radius": 1000,
"border_width": 0,
"fg_color": ["gray60", "grey30"],
"progress_color": ["#ca2f2f", "#941212"],
"border_color": ["gray", "gray"]
},
"CTkSlider": {
"corner_radius": 1000,
"button_corner_radius": 1000,
"border_width": 6,
"button_length": 0,
"fg_color": ["gray60", "grey30"],
"progress_color": ["gray40", "gray69"],
"button_color": ["#ca2f2f", "#941212"],
"button_hover_color": ["#972a2a", "#6b0e0e"]
},
"CTkOptionMenu": {
"corner_radius": 6,
"fg_color": ["#ca2f2f", "#941212"],
"button_color": ["#972a2a", "#6b0e0e"],
"button_hover_color": ["#7d2020", "#571d1d"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkComboBox": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray98", "gray21"],
"border_color": ["gray61", "grey35"],
"button_color": ["gray61", "grey35"],
"button_hover_color": ["grey44", "grey52"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray50", "gray45"]
},
"CTkScrollbar": {
"corner_radius": 1000,
"border_spacing": 4,
"fg_color": "transparent",
"button_color": ["gray55", "gray41"],
"button_hover_color": ["gray40", "gray53"]
},
"CTkSegmentedButton": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray61", "gray29"],
"selected_color": ["#ca2f2f", "#941212"],
"selected_hover_color": ["#972a2a", "#6b0e0e"],
"unselected_color": ["gray61", "gray29"],
"unselected_hover_color": ["gray70", "gray41"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkTextbox": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["gray100", "gray20"],
"border_color": ["gray61", "grey35"],
"text_color": ["gray14", "gray84"],
"scrollbar_button_color": ["gray55", "gray41"],
"scrollbar_button_hover_color": ["gray40", "gray53"]
},
"CTkScrollableFrame": {
"label_fg_color": ["gray80", "gray21"]
},
"DropdownMenu": {
"fg_color": ["gray90", "gray20"],
"hover_color": ["gray75", "gray28"],
"text_color": ["gray14", "gray84"]
},
"CTkFont": {
"macOS": {
"family": "SF Display", "size": 13, "weight": "normal"
},
"Windows": {
"family": "Roboto", "size": 13, "weight": "normal"
},
"Linux": {
"family": "Roboto", "size": 13, "weight": "normal"
}
}
}
3.5.2. magenta
magenta.json
{
"CTk": {
"fg_color": ["gray95", "gray10"]
},
"CTkToplevel": {
"fg_color": ["gray95", "gray10"]
},
"CTkFrame": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["gray90", "gray13"],
"top_fg_color": ["gray85", "gray16"],
"border_color": ["gray65", "gray28"]
},
"CTkButton": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["#c01d6f", "#8b0648"],
"hover_color": ["#8d1c55", "#620533"],
"border_color": ["grey27", "grey60"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkLabel": {
"corner_radius": 0,
"fg_color": "transparent",
"text_color": ["gray14", "gray84"]
},
"CTkEntry": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray98", "gray21"],
"border_color": ["gray61", "grey35"],
"text_color": ["gray14", "gray84"],
"placeholder_text_color": ["gray52", "gray62"]
},
"CTkCheckbox": {
"corner_radius": 6,
"border_width": 3,
"fg_color": ["#c01d6f", "#8b0648"],
"border_color": ["grey27", "grey60"],
"hover_color": ["#8d1c55", "#620533"],
"checkmark_color": ["grey89", "gray90"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkSwitch": {
"corner_radius": 1000,
"border_width": 3,
"button_length": 0,
"fg_Color": ["gray60", "grey30"],
"progress_color": ["#c01d6f", "#8b0648"],
"button_color": ["gray36", "gray85"],
"button_hover_color": ["gray20", "gray100"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkRadiobutton": {
"corner_radius": 1000,
"border_width_checked": 6,
"border_width_unchecked": 3,
"fg_color": ["#c01d6f", "#8b0648"],
"border_color": ["grey27", "grey60"],
"hover_color": ["#8d1c55", "#620533"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkProgressBar": {
"corner_radius": 1000,
"border_width": 0,
"fg_color": ["gray60", "grey30"],
"progress_color": ["#c01d6f", "#8b0648"],
"border_color": ["gray", "gray"]
},
"CTkSlider": {
"corner_radius": 1000,
"button_corner_radius": 1000,
"border_width": 6,
"button_length": 0,
"fg_color": ["gray60", "grey30"],
"progress_color": ["gray40", "gray69"],
"button_color": ["#c01d6f", "#8b0648"],
"button_hover_color": ["#8d1c55", "#620533"]
},
"CTkOptionMenu": {
"corner_radius": 6,
"fg_color": ["#c01d6f", "#8b0648"],
"button_color": ["#8d1c55", "#620533"],
"button_hover_color": ["#741444", "#4e1331"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkComboBox": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray98", "gray21"],
"border_color": ["gray61", "grey35"],
"button_color": ["gray61", "grey35"],
"button_hover_color": ["grey44", "grey52"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray50", "gray45"]
},
"CTkScrollbar": {
"corner_radius": 1000,
"border_spacing": 4,
"fg_color": "transparent",
"button_color": ["gray55", "gray41"],
"button_hover_color": ["gray40", "gray53"]
},
"CTkSegmentedButton": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray61", "gray29"],
"selected_color": ["#c01d6f", "#8b0648"],
"selected_hover_color": ["#8d1c55", "#620533"],
"unselected_color": ["gray61", "gray29"],
"unselected_hover_color": ["gray70", "gray41"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkTextbox": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["gray100", "gray20"],
"border_color": ["gray61", "grey35"],
"text_color": ["gray14", "gray84"],
"scrollbar_button_color": ["gray55", "gray41"],
"scrollbar_button_hover_color": ["gray40", "gray53"]
},
"CTkScrollableFrame": {
"label_fg_color": ["gray80", "gray21"]
},
"DropdownMenu": {
"fg_color": ["gray90", "gray20"],
"hover_color": ["gray75", "gray28"],
"text_color": ["gray14", "gray84"]
},
"CTkFont": {
"macOS": {
"family": "SF Display", "size": 13, "weight": "normal"
},
"Windows": {
"family": "Roboto", "size": 13, "weight": "normal"
},
"Linux": {
"family": "Roboto", "size": 13, "weight": "normal"
}
}
}
3.5.3. purple
purple.json
{
"CTk": {
"fg_color": ["gray95", "gray10"]
},
"CTkToplevel": {
"fg_color": ["gray95", "gray10"]
},
"CTkFrame": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["gray90", "gray13"],
"top_fg_color": ["gray85", "gray16"],
"border_color": ["gray65", "gray28"]
},
"CTkButton": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["#cb45e5", "#9821b0"],
"hover_color": ["#9f3eb2", "#631773"],
"border_color": ["grey27", "grey60"],
"text_color": ["#eadded", "#eadded"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkLabel": {
"corner_radius": 0,
"fg_color": "transparent",
"text_color": ["gray14", "gray84"]
},
"CTkEntry": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray98", "gray21"],
"border_color": ["gray61", "grey35"],
"text_color": ["gray14", "gray84"],
"placeholder_text_color": ["gray52", "gray62"]
},
"CTkCheckbox": {
"corner_radius": 6,
"border_width": 3,
"fg_color": ["#cb45e5", "#9821b0"],
"border_color": ["grey27", "grey60"],
"hover_color": ["#9f3eb2", "#631773"],
"checkmark_color": ["#eadded", "gray90"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkSwitch": {
"corner_radius": 1000,
"border_width": 3,
"button_length": 0,
"fg_Color": ["gray60", "grey30"],
"progress_color": ["#cb45e5", "#9821b0"],
"button_color": ["gray36", "gray85"],
"button_hover_color": ["gray20", "gray100"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkRadiobutton": {
"corner_radius": 1000,
"border_width_checked": 6,
"border_width_unchecked": 3,
"fg_color": ["#cb45e5", "#9821b0"],
"border_color": ["grey27", "grey60"],
"hover_color": ["#9f3eb2", "#631773"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkProgressBar": {
"corner_radius": 1000,
"border_width": 0,
"fg_color": ["gray60", "grey30"],
"progress_color": ["#cb45e5", "#9821b0"],
"border_color": ["gray", "gray"]
},
"CTkSlider": {
"corner_radius": 1000,
"button_corner_radius": 1000,
"border_width": 6,
"button_length": 0,
"fg_color": ["gray60", "grey30"],
"progress_color": ["gray40", "gray69"],
"button_color": ["#cb45e5", "#9821b0"],
"button_hover_color": ["#9f3eb2", "#631773"]
},
"CTkOptionMenu": {
"corner_radius": 6,
"fg_color": ["#cb45e5", "#9821b0"],
"button_color": ["#9f3eb2", "#631773"],
"button_hover_color": ["#883199", "#683473"],
"text_color": ["#eadded", "#eadded"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkComboBox": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray98", "gray21"],
"border_color": ["gray61", "grey35"],
"button_color": ["gray61", "grey35"],
"button_hover_color": ["grey44", "grey52"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray50", "gray45"]
},
"CTkScrollbar": {
"corner_radius": 1000,
"border_spacing": 4,
"fg_color": "transparent",
"button_color": ["gray55", "gray41"],
"button_hover_color": ["gray40", "gray53"]
},
"CTkSegmentedButton": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray61", "gray29"],
"selected_color": ["#cb45e5", "#9821b0"],
"selected_hover_color": ["#9f3eb2", "#631773"],
"unselected_color": ["gray61", "gray29"],
"unselected_hover_color": ["gray70", "gray41"],
"text_color": ["#eadded", "#eadded"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkTextbox": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["gray100", "gray20"],
"border_color": ["gray61", "grey35"],
"text_color": ["gray14", "gray84"],
"scrollbar_button_color": ["gray55", "gray41"],
"scrollbar_button_hover_color": ["gray40", "gray53"]
},
"CTkScrollableFrame": {
"label_fg_color": ["gray80", "gray21"]
},
"DropdownMenu": {
"fg_color": ["gray90", "gray20"],
"hover_color": ["gray75", "gray28"],
"text_color": ["gray14", "gray84"]
},
"CTkFont": {
"macOS": {
"family": "SF Display", "size": 13, "weight": "normal"
},
"Windows": {
"family": "Roboto", "size": 13, "weight": "normal"
},
"Linux": {
"family": "Roboto", "size": 13, "weight": "normal"
}
}
}
3.5.4. torquoise
torquoise.json
{
"CTk": {
"fg_color": ["gray95", "gray10"]
},
"CTkToplevel": {
"fg_color": ["gray95", "gray10"]
},
"CTkFrame": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["gray90", "gray13"],
"top_fg_color": ["gray85", "gray16"],
"border_color": ["gray65", "gray28"]
},
"CTkButton": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["#2fcaca", "#129494"],
"hover_color": ["#2a9797", "#0e6b6b"],
"border_color": ["grey27", "grey60"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkLabel": {
"corner_radius": 0,
"fg_color": "transparent",
"text_color": ["gray14", "gray84"]
},
"CTkEntry": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray98", "gray21"],
"border_color": ["gray61", "grey35"],
"text_color": ["gray14", "gray84"],
"placeholder_text_color": ["gray52", "gray62"]
},
"CTkCheckbox": {
"corner_radius": 6,
"border_width": 3,
"fg_color": ["#2fcaca", "#129494"],
"border_color": ["grey27", "grey60"],
"hover_color": ["#2a9797", "#0e6b6b"],
"checkmark_color": ["grey89", "gray90"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkSwitch": {
"corner_radius": 1000,
"border_width": 3,
"button_length": 0,
"fg_Color": ["gray60", "grey30"],
"progress_color": ["#2fcaca", "#129494"],
"button_color": ["gray36", "gray85"],
"button_hover_color": ["gray20", "gray100"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkRadiobutton": {
"corner_radius": 1000,
"border_width_checked": 6,
"border_width_unchecked": 3,
"fg_color": ["#2fcaca", "#129494"],
"border_color": ["grey27", "grey60"],
"hover_color": ["#2a9797", "#0e6b6b"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray60", "gray45"]
},
"CTkProgressBar": {
"corner_radius": 1000,
"border_width": 0,
"fg_color": ["gray60", "grey30"],
"progress_color": ["#2fcaca", "#129494"],
"border_color": ["gray", "gray"]
},
"CTkSlider": {
"corner_radius": 1000,
"button_corner_radius": 1000,
"border_width": 6,
"button_length": 0,
"fg_color": ["gray60", "grey30"],
"progress_color": ["gray40", "gray69"],
"button_color": ["#2fcaca", "#129494"],
"button_hover_color": ["#2a9797", "#0e6b6b"]
},
"CTkOptionMenu": {
"corner_radius": 6,
"fg_color": ["#2fcaca", "#129494"],
"button_color": ["#2a9797", "#0e6b6b"],
"button_hover_color": ["#207d7d", "#1d5757"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkComboBox": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray98", "gray21"],
"border_color": ["gray61", "grey35"],
"button_color": ["gray61", "grey35"],
"button_hover_color": ["grey44", "grey52"],
"text_color": ["gray14", "gray84"],
"text_color_disabled": ["gray50", "gray45"]
},
"CTkScrollbar": {
"corner_radius": 1000,
"border_spacing": 4,
"fg_color": "transparent",
"button_color": ["gray55", "gray41"],
"button_hover_color": ["gray40", "gray53"]
},
"CTkSegmentedButton": {
"corner_radius": 6,
"border_width": 2,
"fg_color": ["gray61", "gray29"],
"selected_color": ["#2fcaca", "#129494"],
"selected_hover_color": ["#2a9797", "#0e6b6b"],
"unselected_color": ["gray61", "gray29"],
"unselected_hover_color": ["gray70", "gray41"],
"text_color": ["grey89", "grey89"],
"text_color_disabled": ["gray74", "gray60"]
},
"CTkTextbox": {
"corner_radius": 6,
"border_width": 0,
"fg_color": ["gray100", "gray20"],
"border_color": ["gray61", "grey35"],
"text_color": ["gray14", "gray84"],
"scrollbar_button_color": ["gray55", "gray41"],
"scrollbar_button_hover_color": ["gray40", "gray53"]
},
"CTkScrollableFrame": {
"label_fg_color": ["gray80", "gray21"]
},
"DropdownMenu": {
"fg_color": ["gray90", "gray20"],
"hover_color": ["gray75", "gray28"],
"text_color": ["gray14", "gray84"]
},
"CTkFont": {
"macOS": {
"family": "SF Display", "size": 13, "weight": "normal"
},
"Windows": {
"family": "Roboto", "size": 13, "weight": "normal"
},
"Linux": {
"family": "Roboto", "size": 13, "weight": "normal"
}
}
}
4. さいごに
CustomTkinterをどうやったら簡単に使えるか考えていたら、結果的にプレビューツールやカスタムテーマ作成ツールに行き着いていました。
意図せず色設定の勉強まで必要でしたし、やってみたいことベースで考えているとどんどん広がって大変ですが、その分面白くもあるので、今後もいろいろ作ってみようと思います。
参考
色の設定については以下を参考としてました。