PySide【第1回 | デザイン編】Qt StyleSheets入門(CSS風デザイン)

\ 迷ったらまずTechAcademyの無料カウンセリング! /

PySideで作るGUIは、標準のままだとシンプルですが、業務アプリ風で「見た目が地味」と思われがちです。
そんなときに活躍するのが Qt StyleSheets (QSS) です。
QSSを使えば、WebのCSSと同じ感覚でウィジェットの見た目を整えられます。

この記事では ボタン(QPushButton)のデザインに絞りサンプルコードで解説しています。

目次

サンプルコードと概要

サンプルコードの概要

目的:Bootstrapのボタン群を意識しつつ、PySide/QSSで実装したサンプルの説明。
キー仕様

  • Primary / Success / Danger:色違いの標準ボタン(固定サイズ)
  • Outline:枠線タイプ(透明→hoverで塗りつぶし)
  • Large / Small:サイズ違い(font-size と padding で調整、固定サイズ)
  • Block Button (Full Width):ウィンドウ幅に追従するボタン(QSizePolicy.Expanding
  • Disabled:無効化ボタン(setEnabled(False)、グレーアウト見た目)

レイアウト方針

  • 各ボタンは QSizePolicy.Fixed(幅はコンテンツ+paddingに基づく固定)に設定。
  • Full Width のみ QSizePolicy.Expanding を与え、親レイアウトの幅に追従させる。
  • 見た目はすべて setStyleSheet() により QSS(CSS風)で定義。

サンプルコード

import sys
from PySide6.QtWidgets import QApplication, QPushButton, QWidget, QVBoxLayout, QSizePolicy

class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QSS入門:ボタンデザイン集")

        layout = QVBoxLayout()

        # --- 色違いボタン ---
        primary_btn = QPushButton("標準ボタン")
        primary_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        primary_btn.setStyleSheet("""
            QPushButton {
                background-color: #007bff;
                color: white;
                border-radius: 6px;
                padding: 8px 16px;
            }
            QPushButton:hover {
                background-color: #0056b3;
            }
        """)

        success_btn = QPushButton("成功")
        success_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        success_btn.setStyleSheet("""
            QPushButton {
                background-color: #28a745;
                color: white;
                border-radius: 6px;
                padding: 8px 16px;
            }
            QPushButton:hover {
                background-color: #1e7e34;
            }
        """)

        danger_btn = QPushButton("危険")
        danger_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        danger_btn.setStyleSheet("""
            QPushButton {
                background-color: #dc3545;
                color: white;
                border-radius: 6px;
                padding: 8px 16px;
            }
            QPushButton:hover {
                background-color: #a71d2a;
            }
        """)

        # --- アウトラインボタン ---
        outline_btn = QPushButton("アウトラインボタン")
        outline_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        outline_btn.setStyleSheet("""
            QPushButton {
                background-color: transparent;
                color: #007bff;
                border: 2px solid #007bff;
                border-radius: 6px;
                padding: 8px 16px;
            }
            QPushButton:hover {
                background-color: #007bff;
                color: white;
            }
        """)

        # --- サイズ変更ボタン ---
        large_btn = QPushButton("大きいボタン")
        large_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        large_btn.setStyleSheet("""
            QPushButton {
                background-color: #6c757d;
                color: white;
                font-size: 18px;
                border-radius: 6px;
                padding: 12px 24px;
            }
        """)

        small_btn = QPushButton("小さいボタン")
        small_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        small_btn.setStyleSheet("""
            QPushButton {
                background-color: #6c757d;
                color: white;
                font-size: 12px;
                border-radius: 6px;
                padding: 4px 8px;
            }
        """)

        # --- 幅いっぱいのボタン(Full Width) ---
        full_btn = QPushButton("幅いっぱいのボタン")
        full_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        full_btn.setStyleSheet("""
            QPushButton {
                background-color: #17a2b8;
                color: white;
                font-size: 16px;
                border-radius: 6px;
                padding: 10px;
            }
        """)

        # --- 非アクティブ(無効化)ボタン ---
        disabled_btn = QPushButton("非アクティブ")
        disabled_btn.setEnabled(False)
        disabled_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        disabled_btn.setStyleSheet("""
            QPushButton {
                background-color: #6c757d;
                color: #d6d6d6;
                border-radius: 6px;
                padding: 8px 16px;
            }
        """)

        # レイアウトに追加
        layout.addWidget(primary_btn)
        layout.addWidget(success_btn)
        layout.addWidget(danger_btn)
        layout.addWidget(outline_btn)
        layout.addWidget(large_btn)
        layout.addWidget(small_btn)
        layout.addWidget(full_btn)
        layout.addWidget(disabled_btn)

        self.setLayout(layout)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MyWindow()
    window.show()
    sys.exit(app.exec())

プロパティ・メソッドの全まとめ(表)

分類プロパティ / メソッド説明使用例
メソッドsetStyleSheet(str)ウィジェットにQSS文字列を適用btn.setStyleSheet("background-color:#007bff;")
メソッドsetSizePolicy(h, v)幅・高さの伸縮方針を指定(QSizePolicy)btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
メソッドsetEnabled(bool)有効/無効を切替(disabled表現)btn.setEnabled(False)
プロパティbackground-color背景色background-color: #28a745;
プロパティcolorテキスト色color: white;
プロパティborder枠線(太さ・スタイル・色)border: 2px solid #007bff;
プロパティborder-radius角丸border-radius: 6px;
プロパティpadding内側の余白(横・縦)padding: 8px 16px;
プロパティfont-sizeフォントサイズ(px単位)font-size: 18px;
疑似状態:hoverマウスホバー時のスタイルQPushButton:hover { ... }
疑似状態:pressedクリック押下時のスタイルQPushButton:pressed { ... }
疑似状態:disabled無効化時のスタイルQPushButton:disabled { ... }
QtクラスQSizePolicy.Fixed固定サイズ(伸びない)setSizePolicy(QSizePolicy.Fixed, ...)
QtクラスQSizePolicy.Expanding利用可能スペースへ伸びるsetSizePolicy(QSizePolicy.Expanding, ...)
代替setFixedWidth(int) / setFixedSize(w,h)明示的にピクセルで固定btn.setFixedWidth(120)

詳細解説

1) 「固定サイズ」と「Full Width(可変)」の違い

  • 固定(Fixed)
    • setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) を使うと、ボタンは内部コンテンツ(テキスト、padding、font-size)に基づく サイズヒント(sizeHint) を使い、親が広くても横に伸びません。
    • これにより複数ボタンが同じ列に並んだとき、意図しない横伸びを防げます。
  • 可変(Expanding)
    • setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) を与えた Full Width ボタンだけが親の横幅に拡張されます。
    • レイアウト内で余白がある場合に自動的に幅を埋めるので「ブロックボタン」挙動を実現できます。
# 固定
fixed_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
# 可変
full_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

2) サイズの決定要素(実務的ポイント)

ボタンの見た目サイズは主に以下で決まります:

  1. font-size(文字の高さ)
  2. padding(内側の余白)
  3. テキストの文字列長(ラベル)
  4. setFixedWidthsetSizePolicy の有無

固定にしたいなら setSizePolicy(Fixed, Fixed) にして、必要なら setFixedWidth() で厳密に指定。
柔軟にしたいなら QSizePolicy.Expanding を使う。

primary_btn = QPushButton("標準ボタン")
primary_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
primary_btn.setStyleSheet("""
    QPushButton {
        font-family: 'Yu Gothic UI';
        background-color: #007bff;
        color: white;
        border-radius: 6px;
        padding: 8px 16px;
    }
    QPushButton:hover {
        background-color: #0056b3;
    }
""")

3) 色違い(Primary / Success / Danger)

色は背景色を background-color、文字色を color で設定します。
マウスでhover した際にやや暗い色にすることで押せる感を出すことができます(QPushButton:hover)。

Primary:背景色#007bff,hover時#0056b3

primary_btn.setStyleSheet("""
    QPushButton {
        font-family: 'Yu Gothic UI';
        background-color: #007bff;
        color: white;
        border-radius: 6px;
        padding: 8px 16px;
    }
    QPushButton:hover {
        background-color: #0056b3;
    }
""")

Success:背景色#28a745,hover時#1e7e34

success_btn.setStyleSheet("""
    QPushButton {
        font-family: 'Arial';
        background-color: #28a745;
        color: white;
        border-radius: 6px;
        padding: 8px 16px;
    }
    QPushButton:hover {
        background-color: #1e7e34;
    }
""")

Danger:背景色#dc3545,hover時#a71d2a

danger_btn.setStyleSheet("""
    QPushButton {
        font-family: 'Meiryo';
        background-color: #dc3545;
        color: white;
        border-radius: 6px;
        padding: 8px 16px;
    }
    QPushButton:hover {
        background-color: #a71d2a;
    }
""")

4) アウトラインボタンの実装トリック

通常は 背景色を透明background-color: transparent;、枠を色と太さborder: 2px solid <color>で指定します。

hover で背景を同色にして文字色を白にするとWebのアウトラインボタンと同じUXに。

outline_btn = QPushButton("アウトラインボタン")
outline_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
outline_btn.setStyleSheet("""
    QPushButton {
        font-family: 'Meiryo';
        background-color: transparent;
        color: #007bff;
        border: 2px solid #007bff;
        border-radius: 6px;
        padding: 8px 16px;
    }
    QPushButton:hover {
        background-color: #007bff;
        color: white;
    }
""")
通常hover

注意:透明背景にすると背後のウィジェット(親ウィジェット)の色が透けるため、親背景色を統一しておくと見栄えが安定します。

5) Large / Small(サイズバリエーション)

  • font-sizepadding を組み合わせる。
    • Large: font-size:18px; padding:12px 24px;
    • Small: font-size:12px; padding:4px 8px;
  • さらに厳密にしたければ setFixedHeight()setMinimumWidth() で縦横を固定できます。
# --- サイズ変更ボタン ---
large_btn = QPushButton("大きいボタン")
large_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
large_btn.setStyleSheet("""
    QPushButton {
        font-family: 'Meiryo';
        background-color: #6c757d;
        color: white;
        font-size: 18px;
        border-radius: 6px;
        padding: 12px 24px;
    }
""")

small_btn = QPushButton("小さいボタン")
small_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
small_btn.setStyleSheet("""
    QPushButton {
        font-family: 'Meiryo';
        background-color: #6c757d;
        color: white;
        font-size: 12px;
        border-radius: 6px;
        padding: 4px 8px;
    }
""")

6) Disabled(無効化)表現

  • btn.setEnabled(False) で内部的に無効化。QSSでは QPushButton:disabled { ... } で色を変える。
  • 実務的に推奨する見せ方:背景を薄め、文字色は淡いグレーに。マウス反応(hover)をなくすことで明確に非アクティブ感を出す。
disabled_btn = QPushButton("非アクティブ")
disabled_btn.setEnabled(False)
disabled_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
disabled_btn.setStyleSheet("""
    QPushButton {
        font-family: 'Meiryo';
        background-color: #6c757d;
        color: #d6d6d6;
        border-radius: 6px;
        padding: 8px 16px;
    }
""")

7) ボタン単体だけにスタイルを当てる方法(選択的スタイリング)

全ボタンに同じスタイルを当てたくない場合、オブジェクト名 を付けて指定できます:

primary_btn = QPushButton("標準のボタン")
primary_btn.setObjectName("primaryBtn")

QPushButton#primaryBtn {
    font-family: 'Yu Gothic UI';
    background-color: #007bff;
    color: white;
    border-radius: 6px;
    padding: 8px 16px;
}
QPushButton#primaryBtn:hover {
    background-color: #0056b3;
}

setProperty("variant","primary") とし、QSSで QPushButton[variant="primary"] { ... } のように属性セレクタで切り分けることも可能。

8) 外部QSSファイルでの運用

大きいアプリでは QSS を一つの .qss(もしくは .qss として保存)にまとめて、起動時に読み込むと保守性が上がります

下記にQSSファイル,メインPythonファイル,Pythonの呼び出しコードを記載しています

QSSファイルのコード

/* 共通の基本スタイル(フォントやボタンの共通見た目) */
QWidget {
    font-family: "Meiryo";
    font-size: 12px;
}

/* デフォルトボタン(Primary) */
QPushButton#primaryBtn {
    font-family: 'Yu Gothic UI';
    background-color: #007bff;
    color: white;
    border-radius: 6px;
    padding: 8px 16px;
}
QPushButton#primaryBtn:hover {
    background-color: #0056b3;
}

/* Success */
QPushButton#successBtn {
    font-family: 'Arial';
    background-color: #28a745;
    color: white;
    border-radius: 6px;
    padding: 8px 16px;
}
QPushButton#successBtn:hover {
    background-color: #1e7e34;
}

/* Danger */
QPushButton#dangerBtn {
    font-family: 'Meiryo';
    background-color: #dc3545;
    color: white;
    border-radius: 6px;
    padding: 8px 16px;
}
QPushButton#dangerBtn:hover {
    background-color: #a71d2a;
}

/* アウトラインボタン(ID: outlineBtn を利用) */
QPushButton#outlineBtn {
    font-family: 'Meiryo';
    background-color: transparent;
    color: #007bff;
    border: 2px solid #007bff;
    border-radius: 6px;
    padding: 8px 16px;
}
QPushButton#outlineBtn:hover {
    background-color: #007bff;
    color: white;
}

/* 大きいボタン */
QPushButton#largeBtn {
    font-family: 'Meiryo';
    background-color: #6c757d;
    color: white;
    font-size: 18px;
    border-radius: 6px;
    padding: 12px 24px;
}

/* 小さいボタン */
QPushButton#smallBtn {
    font-family: 'Meiryo';
    background-color: #6c757d;
    color: white;
    font-size: 12px;
    border-radius: 6px;
    padding: 4px 8px;
}

/* 固定幅ボタン(見た目) */
QPushButton#fixedBtn {
    font-family: 'Meiryo';
    font-weight: bold;
    background-color: #17a2b8;
    color: white;
    font-size: 16px;
    border-radius: 6px;
    padding: 10px;
}

/* 可変(フル幅)ボタン */
QPushButton#fullBtn {
    font-family: 'Meiryo';
    font-weight: bold;
    background-color: #17a2b8;
    color: white;
    font-size: 16px;
    border-radius: 6px;
    padding: 10px;
}

/* 無効化されたボタン */
QPushButton:disabled, QPushButton#disabledBtn:disabled {
    font-family: 'Meiryo';
    background-color: #6c757d;
    color: #d6d6d6;
    border-radius: 6px;
    padding: 8px 16px;
}

/* 共通ホバーの微調(必要なら上書き可) */
QPushButton:hover {
    /* デフォルトホバーは個別で定義しているため基本は空にしておく */
}

メインのPythonファイルのメインコード

import sys
from PySide6.QtWidgets import QApplication, QPushButton, QWidget, QVBoxLayout, QSizePolicy
from PySide6.QtGui import QFont
from PySide6.QtCore import QFile, QTextStream

class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QSS入門:ボタンデザイン集")
        self.setFont(QFont("Meiryo", 12))

        layout = QVBoxLayout()

        # --- 色違いボタン ---
        primary_btn = QPushButton("標準のボタン")
        primary_btn.setObjectName("primaryBtn")
        primary_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        success_btn = QPushButton("Success")
        success_btn.setObjectName("successBtn")
        success_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        danger_btn = QPushButton("危険")
        danger_btn.setObjectName("dangerBtn")
        danger_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        # --- アウトラインボタン ---
        outline_btn = QPushButton("アウトラインボタン")
        outline_btn.setObjectName("outlineBtn")
        outline_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        # --- サイズ変更ボタン ---
        large_btn = QPushButton("大きいボタン")
        large_btn.setObjectName("largeBtn")
        large_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        small_btn = QPushButton("小さいボタン")
        small_btn.setObjectName("smallBtn")
        small_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        # --- 幅いっぱいのボタン(Full Width) ---
        fixed_btn = QPushButton("固定のボタン")
        fixed_btn.setObjectName("fixedBtn")
        fixed_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        full_btn = QPushButton("可変のボタン")
        full_btn.setObjectName("fullBtn")
        full_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

        # --- 非アクティブ(無効化)ボタン ---
        disabled_btn = QPushButton("非アクティブ")
        disabled_btn.setObjectName("disabledBtn")
        disabled_btn.setEnabled(False)
        disabled_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        # レイアウトに追加
        layout.addWidget(primary_btn)
        layout.addWidget(success_btn)
        layout.addWidget(danger_btn)
        layout.addWidget(outline_btn)
        layout.addWidget(large_btn)
        layout.addWidget(small_btn)
        layout.addWidget(fixed_btn)
        layout.addWidget(full_btn)
        layout.addWidget(disabled_btn)

        self.setLayout(layout)

メインのPythonファイルでの呼び出しコード

if __name__ == "__main__":
    app = QApplication(sys.argv)
    with open("sytle.qss", "r", encoding="utf-8") as f:
        app.setStyleSheet(f.read())
    window = MyWindow()
    window.show()
    sys.exit(app.exec())

9) アクセシビリティ&高DPI対応メモ

  • フォントを px で指定すると DPI によるスケールで見切れることがあるため、必要なら QFont を使ってポイント指定やフォントファミリを明確にすると良い。
  • Qt の AA_EnableHighDpiScaling 等を有効にすることで高解像度ディスプレイでの見栄えが安定します。
from PySide6.QtCore import Qt, QCoreApplication

# --- 高DPI対応を有効化 ---
# Qt 5.14 以降では基本的に自動対応するが、明示する方が安心
QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)

よくある質問 Q&A

「全部固定にしたい」ならどうすれば?

btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) のまま、必要なら btn.setFixedWidth(120)btn.setFixedHeight(36) を使えば完全にピクセル固定できます。

Full Width を左右にマージン入れて伸ばしたい(画面端ぴったりにしない)

Full Width ボタンを内側の QWidget(コンテナ)に入れて、そのコンテナに左右の余白(layout.setContentsMargins(left,top,right,bottom))を設定すると簡単に実現できます。

Bootstrap のような「btn-sm」「btn-lg」を複数で使いたい(コードを簡潔にしたい)

setProperty() と QSS の属性セレクタを活用すると良いです。例:

btn.setProperty("size","lg")
# QSS:
QPushButton[size="lg"] { font-size:18px; padding:12px 24px; }
QSSでドロップシャドウやグラデーションはできる?

QSSでのビルトインは限定的。グラデーションは background-image: qlineargradient(...) の形式で可能ですが、影(box-shadow)はサポートされていません。影を付けたい場合は QGraphicsDropShadowEffect を使います(スタイルではなくエフェクトとして適用)。

複数のウィンドウで同じスタイルを使いたい(共通化)

アプリ起動時に app.setStyleSheet() で全体に読み込めばOK。個別の微調整はオブジェクト名/属性で上書き。

アニメーション(hoverでスムーズに背景色が変わる)をつけたい

QSS にトランジションは無いので、QPropertyAnimation(例えばボタンの palettegeometry、カスタムプロパティ)で色やサイズをアニメーションする実装が必要です。

まとめ

今回のサンプルは「基本は固定サイズ、Full Widthだけ可変」という実務的な要件に沿って作られています。

  • 固定にする手段QSizePolicy.Fixed(+必要なら setFixedWidth
  • Full WidthQSizePolicy.Expanding を与えるだけで親幅に追従する簡潔な実装が可能。
  • QSS(QSS = CSS風) で色・枠・角丸・padding・疑似状態(hover/pressed/disabled)を実現。

大規模化するなら 外部QSSの共通化 / objectName や property によるセレクター分離 / QPropertyAnimationでの動き付け を検討すると良いです。

シェアしてくださると嬉しいです!
  • URLをコピーしました!

コメント

コメントする

目次