PySide超入門【第19回 | 応用編】カスタムウィジェットの作り方!QWidgetの継承と描画

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

GUIアプリケーションを開発していると、標準のウィジェットでは表現しきれない独自の見た目や動作が必要になることがあります。そのような場合に役立つのがカスタムウィジェットの作成です。

本記事では、QWidget を継承してカスタム描画を行う方法を中心に、基本構造から便利なプロパティ・メソッド、描画イベントの実践例まで解説します。

目次

QWidgetとは?

QWidgetは、PySide6におけるすべてのGUI部品(ボタン、ラベル、テキストボックスなど)の「土台」となる基本クラスです。

PySide6(Qt)では、すべてのUI要素がこのQWidgetをベースにして作られています。
つまり、自分で「オリジナルのウィジェット(部品)」を作りたいときも、QWidgetを継承することで、独自の機能や見た目を持った部品を作成できます。

特に描画処理(カスタム描画)を行いたい場合には、QWidgetを継承し、paintEvent()という関数を使って、自分だけのUIを描き出すことができます。

たとえば、普通のボタンではなく、グラフや図形などを自分で描きたい場合などに大活躍します!

基本コード

以下は、QWidgetを継承してカスタムウィジェットを作成する最小構成のコードです

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QColor
import sys

class CustomWidget(QWidget):
    # QWidgetをクラス継承
    def __init__(self):
        super().__init__()
        self.setWindowTitle("カスタムウィジェットの例")
        self.resize(300, 200)

    def paintEvent(self, event):
        # paintEvent() をオーバーライド
        painter = QPainter(self)
        painter.setBrush(QColor("skyblue"))
        painter.drawRect(50, 50, 200, 100)

app = QApplication(sys.argv)
window = CustomWidget()
window.show()
sys.exit(app.exec())
説明
CustomWidget(QWidget)QWidgetを継承して自作ウィジェットを定義します。
self.setWindowTitle()ウィンドウのタイトルを設定します。
self.resize()ウィンドウのサイズを幅300px × 高さ200pxに設定します。
widget.show()ウィジェットを画面に表示します。
app.exec()アプリケーションのイベントループを開始します。ウィンドウが閉じられるまで実行され続けます。

主なプロパティとメソッド一覧(全解説)

Noメソッド / プロパティ説明
1setGeometry(x, y, w, h)ウィジェットの位置とサイズを設定widget.setGeometry(10, 10, 200, 100)
2resize(w, h)ウィジェットのサイズを変更widget.resize(300, 200)
3move(x, y)ウィジェットを指定位置へ移動widget.move(100, 50)
4setFixedSize(w, h)サイズを固定widget.setFixedSize(200, 150)
5setMinimumSize(w, h) / setMaximumSize(w, h)サイズの最小値・最大値を指定widget.setMinimumSize(100, 80)
6update()ウィジェットの再描画を要求widget.update()
7repaint()即座に再描画を実行widget.repaint()
8paintEvent(event)ウィジェットの描画処理を定義def paintEvent(self, e): …
9setStyleSheet(css)CSS風の装飾を設定widget.setStyleSheet(“background-color: lightgreen;”)
10setEnabled(bool)ウィジェットの有効/無効を切り替えwidget.setEnabled(False)
11setVisible(bool) / show() / hide()表示/非表示を切り替えwidget.hide()
12setToolTip(text)ツールチップを設定widget.setToolTip(“これは説明です”)
13setCursor(cursor)カーソル形状を変更widget.setCursor(Qt.PointingHandCursor)
14mousePressEvent(event)マウスクリックイベント処理def mousePressEvent(self, e): …
15keyPressEvent(event)キー入力イベント処理def keyPressEvent(self, e): …
16closeEvent(event)ウィンドウ閉じるときの処理def closeEvent(self, e): …

各プロパティ・メソッド 詳細解説

【1】位置とサイズの設定

  • 概要: ウィジェットの表示位置とサイズを一度に設定します。配置の座標系は親ウィジェットの左上が基準になります。
  • メソッド:setGeometry(x, y, width, height)
  • 使い方:
# QWidgetをクラス継承
def __init__(self):
    self.setGeometry(100, 50, 600, 200)

【2】サイズの変更

  • 概要: ウィジェットのサイズだけを変更します。位置は変わりません。
  • メソッドresize(width, height)
  • 使い方
# QWidgetをクラス継承
def __init__(self):
    self.resize(400, 300)

【3】位置の移動

  • 概要: ウィジェットを指定した座標に移動します。サイズは変わりません。
  • メソッドmove(x, y)
  • 使い方
# QWidgetをクラス継承
def __init__(self):
    self.move(300, 50)

【4】サイズの固定

  • 概要: ウィジェットのサイズを固定し、リサイズできないようにします。
  • メソッドsetFixedSize(width, height)
  • 使い方
# QWidgetをクラス継承
def __init__(self):
    self.setFixedSize(250, 150)

【5】最小サイズ・最大サイズの設定

  • 概要: ウィジェットのサイズ変更範囲を制限します。レイアウトを使用している場合にも有効です。
  • メソッドsetMinimumSize(width, height) / setMaximumSize(width, height)
  • 使い方
# QWidgetをクラス継承
def __init__(self):
    self.setMinimumSize(100, 80)
    self.setMaximumSize(500, 400)
setMinimumSizesetMaximumSize

【6】再描画要求

概要update() は、「このウィジェットの見た目が変わったから、もう一度描画して!」とQtにお願いするメソッドです。
このメソッドを呼んだ瞬間に直接描画するわけではなく、Qtのイベントループを通して非同期的に paintEvent() が呼び出されます。
そのため、画面の更新が必要な場面(色、形、文字、位置などが変わった時)で使用します。

  • メソッドupdate()
  • 使い方
self.update()  # paintEvent() が再度呼ばれる
  • ウィジェットの状態が変化して描画内容も変える必要がある時に使います。
  • 初期表示のときはQtが自動的に描画するので不要。
  • update() は「お願い」だけで、すぐに描画しない → 安全に再描画ができる。
  • もし即座に描画したい場合は repaint() を使いますが、基本は update() 推奨。

【7】即時再描画

概要repaint() は、「今すぐ描画をやり直せ!」とQtに直接指示するメソッドです。
update() が「後で再描画してね」という予約型なのに対して、repaint() は呼び出した瞬間に paintEvent()即座に実行します。
そのため、重い処理の途中などで使いすぎるとパフォーマンスが落ちる可能性があります。

  • メソッドrepaint()
  • 使い方
self.repaint()  # すぐに再描画
  • 即時描画が必要な場面(ユーザーに処理の進捗をリアルタイムに見せたいなど)で使う。
  • update() よりも描画回数が増えやすく、処理負荷が高くなる場合がある。
  • 基本的には update() 推奨。repaint() は例外的な状況でのみ使用する。

【8】描画イベント

  • 概要: カスタムウィジェットの見た目を描画するメソッドです。QPainter を使って自由に図形を描けます。
  • メソッドpaintEvent(event)
  • 使い方
def paintEvent(self, event):
    painter = QPainter(self)
    painter.setBrush(QColor("yellow"))
    painter.drawEllipse(50, 50, 100, 100)

【9】スタイルシート設定

  • 概要: CSS風の書式で見た目を変更します。色、枠線、背景などを簡単にカスタマイズ可能です。
  • メソッドsetStyleSheet(css)
  • 使い方
# QWidgetをクラス継承
def __init__(self):
    self.setStyleSheet("border: 2px solid red; background-color: lightblue;")

【10】有効/無効の切り替え

  • 概要: ウィジェットを操作可能にするか、無効化してグレーアウトするかを設定します。
  • メソッドsetEnabled(bool)
  • 使い方
# QWidgetをクラス継承
def __init__(self):
    self.setEnabled(False)  # 無効化

【11】表示・非表示の切り替え

  • 概要: ウィジェットの表示状態を切り替えます。show() で表示、hide() で非表示になります。
  • メソッドsetVisible(bool) / show() / hide()
  • 使い方
window.hide()   # 非表示
window.show()   # 表示

【12】ツールチップ設定

  • 概要: ウィジェットにカーソルを合わせたときに表示される説明を設定します。
  • メソッドsetToolTip(text)
  • 使い方
# QWidgetをクラス継承
def __init__(self):
    self.setToolTip("これは説明文です")

【13】カーソル形状の変更

  • 概要: ウィジェット上にマウスカーソルがあるときの形を変更します。
  • メソッドsetCursor(cursor)
  • 使い方
from PySide6.QtCore import Qt
# QWidgetをクラス継承
def __init__(self):
    self.setCursor(Qt.PointingHandCursor)

※スクリーンショットでマウスカーソルをキャプチャーできませんでした

【14】マウスイベント処理

  • 概要: ウィジェットがクリックやドラッグされたときの動作を定義します。
  • メソッドmousePressEvent(event)
  • 使い方
def mousePressEvent(self, event):
    print(f"クリック位置: {event.position()}")

# クリック位置: PySide6.QtCore.QPointF(169.600000, 123.200000)

【15】キー入力イベント処理

  • 概要: ウィジェットがフォーカスを持っている状態でキーが押されたときに処理を行います。
  • メソッドkeyPressEvent(event)
  • 使い方
def keyPressEvent(self, event):
    print(f"押されたキー: {event.key()}")

# 押されたキー: 65
# 押されたキー: 70

【16】ウィンドウを閉じるイベント

  • 概要: ウィンドウが閉じられる前に実行される処理を定義します。確認ダイアログを出すときに便利です。
  • メソッドcloseEvent(event)
  • 使い方
from PySide6.QtWidgets import QMessageBox
def closeEvent(self, event):
    reply = QMessageBox.question(self, "確認", "本当に終了しますか?")
    if reply == QMessageBox.Yes:
        event.accept()
    else:
        event.ignore()

よくある質問(FAQ)

paintEvent() はいつ呼ばれるのですか?

ウィンドウ表示時や、update()resize() を呼んだときに自動的に呼ばれます。

QPainter の使い方で注意点は?

QPainterpaintEvent() の中でのみ有効に使用してください。

独自のシグナルを持つカスタムウィジェットは作れますか?

可能です。Signal() をクラス変数に定義し、必要なタイミングで emit() します。

複数のレイアウトを組み合わせたカスタムウィジェットは作れますか?

はい。QVBoxLayoutQHBoxLayout を使って複合UIを作成できます。

ウィジェットがちらつく場合の対策は?

setAttribute(Qt.WA_OpaquePaintEvent) を設定すると描画の最適化が可能です。


まとめ

今回は、QWidgetを継承したカスタムウィジェットの作り方を解説しました。paintEvent() を使えば自由な図形描画やデザインが可能で、シンプルなUIから高度なカスタムコンポーネントまで作成できます。

次回(第20回)は、「QGraphicsViewとQGraphicsSceneによるカスタム描画とシーン管理」について解説する予定です。

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

コメント

コメントする

目次