\ 迷ったらまずTechAcademyの無料カウンセリング! /
Pyside 【第2回 | デザイン編】ダークテーマを実現!QSSでライト/ダーク切替機能付きアプリ

現代のデスクトップアプリではダークテーマの需要が高く、目の疲れ軽減やモダンな印象づけに有効です。
PySide(Qt)の QSS は CSS に似た書き方で、アプリ全体の配色・ボタン・入力欄・フォント等を一括で整えられます。
この記事では GitHub風のダークテーマ をベースに、ライトテーマとの切替機能まで含めた実践的な実装と、QSSでよく使う主要プロパティを丁寧に解説します。
完成コードと概要
ダーク / ライト切替付きのサンプルアプリです。ぜひそのまま実行してみてください。
完成コード
dark_qss
/light_qss
を用意してapp.setStyleSheet()
で一括適用。- 切替は
QPushButton
(チェックトグル)とtoggled
シグナルでコントロール。 - サンプルとして
QLabel
,QPushButton
,QLineEdit
,QTextEdit
を置き、テーマ差を確認できる。
# theme_toggle_demo.py
import sys
from PySide6.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QPushButton, QLineEdit, QLabel, QTextEdit
)
from PySide6.QtCore import Qt
class ThemeDemoApp(QWidget):
def __init__(self, app):
super().__init__()
self.app = app
self.setWindowTitle("ダーク/ライト テーマ切替デモ")
self.resize(640, 360)
# UI
main = QVBoxLayout()
control_row = QHBoxLayout()
self.toggle_btn = QPushButton("ライトに切替")
self.toggle_btn.setCheckable(True) # 押すと ON (ライト)
self.toggle_btn.toggled.connect(self.on_toggle)
# Add some sample widgets
self.title = QLabel("ダークテーマサンプル")
self.title.setObjectName("title")
info = QLabel("以下はテーマによる見た目の違いを示すサンプルウィジェットです。")
button = QPushButton("サンプルボタン")
input_line = QLineEdit()
input_line.setPlaceholderText("テキスト入力欄")
text = QTextEdit()
text.setPlainText("QTextEdit のサンプルテキスト。テーマ切替で色や枠が変わります。")
control_row.addWidget(self.toggle_btn)
control_row.addStretch()
main.addLayout(control_row)
main.addWidget(self.title)
main.addWidget(info)
main.addWidget(button)
main.addWidget(input_line)
main.addWidget(text)
self.setLayout(main)
# 初期はダーク
self.apply_dark()
def on_toggle(self, checked: bool):
# checked == True -> ライトに切替
if checked:
self.apply_light()
else:
self.apply_dark()
def apply_dark(self):
theme = 'dark'
with open(fr"python-tool\PySide\{theme}.qss", "r", encoding="utf-8") as f:
self.app.setStyleSheet(f.read())
print(f.read())
self.toggle_btn.setText("ライトに切替")
self.toggle_btn.setChecked(False)
self.title.setText("ダークテーマサンプル")
def apply_light(self):
theme = 'light'
with open(fr"python-tool\PySide\{theme}.qss", "r", encoding="utf-8") as f:
self.app.setStyleSheet(f.read())
self.toggle_btn.setText("ダークに切替")
self.toggle_btn.setChecked(True)
self.title.setText("ライトテーマサンプル")
if __name__ == "__main__":
app = QApplication(sys.argv)
demo = ThemeDemoApp(app)
demo.show()
sys.exit(app.exec())
ダークテーマQSS
/* --- ダークテーマ QSS --- */
QWidget {
background-color: #0d1117;
color: #c9d1d9;
font-family: "Yu Gothic UI", "Segoe UI", sans-serif;
font-size: 14px;
}
/* Buttons */
QPushButton {
background-color: #21262d;
color: #c9d1d9;
border: 1px solid #30363d;
border-radius: 6px;
padding: 6px 12px;
}
QPushButton:hover { background-color: #30363d; }
QPushButton:pressed { background-color: #161b22; }
/* Inputs */
QLineEdit, QTextEdit {
background-color: #161b22;
color: #c9d1d9;
border: 1px solid #30363d;
border-radius: 6px;
padding: 6px;
}
/* Labels (headings) */
QLabel#title {
font-size: 18px;
font-weight: bold;
color: #adbac7;
}

ライトテーマQSS
/* --- ライトテーマ QSS --- */
QWidget {
background-color: #ffffff;
color: #222222;
font-family: "Yu Gothic UI", "Segoe UI", sans-serif;
font-size: 14px;
}
/* Buttons */
QPushButton {
background-color: #f3f4f6;
color: #222222;
border: 1px solid #d1d5db;
border-radius: 6px;
padding: 6px 12px;
}
QPushButton:hover { background-color: #e5e7eb; }
QPushButton:pressed { background-color: #d1d5db; }
/* Inputs */
QLineEdit, QTextEdit {
background-color: #ffffff;
color: #222222;
border: 1px solid #d1d5db;
border-radius: 6px;
padding: 6px;
}
/* Labels (headings) */
QLabel#title {
font-size: 18px;
font-weight: bold;
color: #111827;
}

プロパティ・メソッドの全まとめ
No | プロパティ / メソッド | 用途 | 実例 |
---|---|---|---|
1 | QWidget { background-color } | アプリ全体の背景色 | background-color: #0d1117; |
2 | color | テキストの文字色 | color: #c9d1d9; |
3 | font-family | フォントの種類 | font-family: "Yu Gothic UI", "Segoe UI"; |
4 | font-size | 基本文字サイズ | font-size: 14px; |
5 | border | 枠線の色や太さ(ボタン/入力欄) | border: 1px solid #30363d; |
6 | border-radius | 角丸の指定 | border-radius: 6px; |
7 | padding | 内側余白(ボタン/入力) | padding: 6px 12px; |
8 | QPushButton:hover | ボタンにカーソルを乗せた時の色 | QPushButton:hover { background-color: #30363d; } |
9 | QPushButton:pressed | ボタンが押されている時の色 | QPushButton:pressed { background-color: #161b22; } |
10 | QLineEdit, QTextEdit | 入力欄の背景・文字色・枠 | QLineEdit { background-color: #161b22; } |
詳細解説
以下の見出しは先ほどの表の No + 用途 と一致しています。各項目は 概要 / メソッド / コード例 の順で説明します。例は 2〜3 個ずつ載せ、実務ですぐ使える形にしています。
1 . アプリ全体の背景色(QWidget { background-color }
)
概要
アプリ全体の背景色を決める最も基本的な設定です。QWidget
セレクタで指定すれば、全ウィジェットのデフォルト背景に影響します(ただし個別ウィジェットで上書き可能)。
メソッド
app.setStyleSheet(qss)
で全体に適用。window.setStyleSheet(...)
で特定ウィンドウ配下に限定適用可能。
コード例
- アプリ全体(推奨)
# ダークテーマ
app.setStyleSheet("QWidget { background-color: #0d1117; }")
# ライトテーマ
app.setStyleSheet("QWidget { background-color: #ffffff; }")
- 特定ウィンドウだけ
window.setStyleSheet("QWidget { background-color: #f8fafc; }") # そのウィンドウ配下のみライト
- 個別ウィジェット上書き
some_widget.setStyleSheet("background-color: #1f2937;") # QWidget セレクタより優先
2 . テキストの文字色(color
)
概要
背景とのコントラストを取るために重要。真っ白は疲れやすいので、ダークテーマではやや灰色寄りの色(例: #c9d1d9
)がよく使われます。
メソッド
- QSS 内の
color: <hex>
。 - 個別に
label.setStyleSheet("color: #adbac7;")
でも可。
コード例
- 全体で設定
# ダークテーマ
QWidget { color: #c9d1d9; }
# ライトテーマ
QWidget { color: #222222; }
- ラベルだけ
# ダークテーマ
QLabel#title { color: #adbac7; }
# ライトテーマ
QLabel#title { color: #111827; }
- 直接 Python で
label.setStyleSheet("color: #333333;")<br>
3. フォントの種類(font-family
)
概要
フォントを揃えることで UI の印象が安定します。日本語対応を考えて "Yu Gothic UI"
や Meiryo
を優先指定し、英語系は "Segoe UI"
などをフォールバックします。
メソッド
- QSS:
font-family
を使う。 - 代替:
app.setFont(QFont(...))
でアプリ全体のフォントを設定する方法もある。
コード例
- QSSで一括
QWidget { font-family: "Yu Gothic UI", "Segoe UI", sans-serif; }
- アプリ全体で QFont を使う
from PySide6.QtGui import QFont
app.setFont(QFont("Meiryo", 12))
- 特定ウィジェットだけ
label.setStyleSheet("font-family: 'Courier New';")
4. 基本文字サイズ(font-size
)
概要
可読性と情報密度のバランスを取るために基本サイズを決めます。14px前後がデスクトップでは標準的です。高DPI対応にはポイント指定や app.setFont()
と併用を検討。
メソッド
- QSS:
font-size: 14px;
。 - QFont:
QFont("Meiryo", 12)
(ポイント指定)。
コード例
- QSS で設定
QWidget { font-size: 14px; }
- QFont でアプリ全体
app.setFont(QFont("Meiryo", 12)) # point-size を指定<br>
- 部分的に大きく
QLabel#title { font-size: 18px; }
5. 枠線(border
:ボタン/入力欄)
概要
入力フィールドやボタンの「境界線」を決める設定。ダーク背景では暗めのグレーを使うと落ち着きます。
メソッド
- QSS:
border: 1px solid #30363d;
など。 - 複数ウィジェットをカンマ区切りで指定可能:
QLineEdit, QTextEdit { ... }
コード例
- ボタンの枠線
QPushButton { border: 1px solid #30363d; }
- 入力欄の枠線
# ダークテーマ
QLineEdit { border: 1px solid #30363d; border-radius:6px; }
# ライトテーマ
QLineEdit { border: 1px solid #d1d5db; border-radius:6px; }
- 個別 Python 上書き
btn.setStyleSheet("border: 2px dashed #4b5563;")
6. 角丸(border-radius
)
概要border-radius
で丸めるとモダンな印象になります。数値はアプリのトーンに合わせて 4〜10px を目安に。
メソッド
- QSS:
border-radius: 6px;
。 - 注意:角丸を使うとボタンの高さやpaddingとのバランスに注意。
コード例
- ボタン角丸
QPushButton { border-radius: 6px; }
- 入力欄角丸
QLineEdit { border-radius: 8px; padding:6px; }
- より丸く
QPushButton { border-radius: 999px; } /* pill style */
7. 内側余白(padding
)
概要
padding はボタンや入力欄の「押しやすさ」「読みやすさ」に影響します。上下左右のバランスを整えて UX を向上させます。
メソッド
- QSS:
padding: 6px 12px;
(縦 横)。 - 固定サイズを厳密にするときは
setFixedHeight()
などと併用。
コード例
- 標準ボタン
QPushButton { padding: 6px 12px; }
- 大きめのボタン
QPushButton.big { font-size:16px; padding:10px 18px; }
- 入力欄の内側余白
QLineEdit { padding: 8px; }
8. ホバー時(QPushButton:hover
)
概要
マウスが乗ったときのフィードバックを与えるためのスタイル。色を少し明るくするのが定石です。
メソッド
- QSSの疑似状態:
QPushButton:hover { ... }
。 - hover を使うと「ボタンが押せる」ことが視覚的に伝わる。
コード例
- 基本 hover
# ダークテーマ
QPushButton:hover { background-color: #30363d; }
# ライトテーマ
QPushButton:hover { background-color: #e5e7eb; }
- アウトラインボタンで塗りつぶす
QPushButton#outline:hover { background-color: #0b1220; color: white; }
- 影を演出(QSSでは box-shadow 非対応 → QGraphicsEffect を使う)
# QSS では不可。QGraphicsDropShadowEffect を使う実装例が必要
9. 押下時(QPushButton:pressed
)
概要
クリック時のスタイル。押下感(色を暗くする等)を出して操作の確信を与えます。
メソッド
- QSS:
QPushButton:pressed { background-color: #161b22; }
コード例
- 基本
# ダークテーマ
QPushButton:pressed { background-color: #161b22; }
# ライトテーマ
QPushButton:pressed { background-color: #d1d5db; }
- 押下で少し縮小感(アニメーション必要)
# QSS にトランジションは無い。QPropertyAnimation で geometry を一時的に縮める処理を行う
- 色の変化 + テキスト色保持
QPushButton:pressed { background-color: #111417; color: #c9d1d9; }
10. 入力欄(QLineEdit, QTextEdit
)
概要
入力欄は視認性とフォーカス時の指標が重要。背景色・枠線・フォーカス時の色を設計します。
メソッド
- QSS:
QLineEdit { background-color: #161b22; border:1px solid #30363d; }
- フォーカス時スタイル:
QLineEdit:focus { border-color: #58a6ff; }
(フォーカス色を用意すると良い)
コード例
- 基本
# ダークテーマ
QLineEdit, QTextEdit {
background-color: #161b22;
color: #c9d1d9;
border: 1px solid #30363d;
border-radius: 6px;
padding: 6px;
}
# ライトテーマ
QLineEdit, QTextEdit {
background-color: #ffffff;
color: #222222;
border: 1px solid #d1d5db;
border-radius: 6px;
padding: 6px;
}
- フォーカス時にアクセントを出す
QLineEdit:focus { border: 1px solid #58a6ff; }
- プレースホルダ色を変えたい(Qt のバージョンに依存)
# Qt 側で placeholderText の色を QPalette で指定する方が確実:
palette = line.palette()
palette.setColor(QPalette.PlaceholderText, QColor("#9aa5b1"))
line.setPalette(palette)
テーマ切替(実装の注意点と拡張例)
概要
- 切替は単に
app.setStyleSheet(dark_qss)
/app.setStyleSheet(light_qss)
を呼べばOK。 - 切替タイミングで「一時的にUIがチラつく」ケースがあるため、必要なら
QApplication::processEvents()
を呼ぶか、切替を非同期で滑らかに行う工夫を検討。
実装上のポイント
- 状態保存:ユーザーが選択したテーマを次回起動時に復元するなら、
QSettings
等に “theme=dark” を保存・読み込みする。 - 部分的上書き:特定ウィジェットの見た目を常に固定したいなら、個別ウィジェットで
setStyleSheet()
を当てる(全体の切替でも上書きされないように注意)。 - フォント / DPI:テーマ切替時もフォントサイズが整合するよう
app.setFont()
を併用すると安定。
コード例(状態保存の簡易例)
from PySide6.QtCore import QSettings
# 保存
settings = QSettings("YourOrg", "YourApp")
settings.setValue("theme", "dark") # or "light"
# 読み込み
theme = settings.value("theme", "dark")
if theme == "light":
app.setStyleSheet(light_qss)
else:
app.setStyleSheet(dark_qss)
よくある質問 Q&A
app.setStyleSheet()
とwidget.setStyleSheet()
の違いは?-
app.setStyleSheet()
はアプリ全体に適用(推奨)。widget.setStyleSheet()
はそのウィジェット配下にだけ適用(部分的な上書き)が可能。 - テーマ切替時に一部ウィジェットの色が変わらない(上書きされない)
-
そのウィジェットに個別
setStyleSheet()
がされていると、アプリ全体のQSS に上書きされる場合があります。優先順位を整理して、必要なら個別セレクタ(#objectName
)を使う。 - システム(OS)ダークモードを検知して自動切替できる?
-
Qt側で直接の簡単なAPIは限られます。プラットフォーム固有APIや Qt 6 の OS情報機能を使って検知し、
app.setStyleSheet()
を切り替える実装を行います。 - QSS だけで全ての UI を同じ見た目にできる?
-
多くは可能ですが、Qt内部でネイティブ描画される部分(特定のネイティブウィジェットやプラットフォーム固有の要素)は QSS で完全にコントロールできない場合があります。
- ダークテーマで色選びのコツは?
-
完全な白(#ffffff)ではなく、やや灰色寄りの文字色を使う(例:
#c9d1d9
)。アクセントカラーは 1〜2 色に限定して統一感を持たせるとモダンに見えます。
まとめ
QSS は PySide で アプリ全体を一括してテーマ化する強力な手段です。
基本は「背景 (QWidget
), 文字色 (color
), 枠線 (border
), 角丸 (border-radius
), padding」 を整えるだけでモダンなダークテーマが作れます。
ライト/ダーク切替 は app.setStyleSheet()
を切り替えるだけで実装可能で,実務では状態保存(QSettings
)やフォント/DPIの整合も考慮しましょう。
本記事の完成コードをベースに、アクセントカラーの差し替え、フォントの最適化、フォーカス時アニメーション などを追加していくとさらに完成度が上がります。
コメント