Star Delegate の例
「Star Delegate」の例では、自身を描画でき、編集機能をサポートするデリゲートの作成方法を示しています。

QListView 、QTableView 、またはQTreeView でデータを表示する場合、個々の項目はデリゲートによって描画されます。また、ユーザーが項目の編集を開始すると(たとえば、項目をダブルクリックするなど)、デリゲートは編集が行われている間、その項目の上に配置されるエディタウィジェットを提供します。
デリゲートは `QAbstractItemDelegate` のサブクラスです。Qt では、`QAbstractItemDelegate ` を継承し、最も一般的なデータ型(特に `int ` および `QString`)を扱う `QStyledItemDelegate` が提供されています。 カスタムデータ型をサポートする必要がある場合や、既存のデータ型のレンダリングや編集をカスタマイズしたい場合は、QAbstractItemDelegate またはQStyledItemDelegate をサブクラス化することができます。デリゲートに関する詳細については「デリゲートクラス」を参照してください。また、Qtのモデル/ビューアーキテクチャ(デリゲートを含む)に関する概要を知りたい場合は、「モデル/ビュープログラミング」を参照してください。
この例では、「5つ星中1つ」などの値を格納できる「星評価」データ型をレンダリングおよび編集するためのカスタムデリゲートを実装する方法を説明します。
この例は、以下のクラスで構成されています。
StarRatingはカスタムデータ型です。「5つ星のうち2つ」や「6つ星のうち5つ」といった、星で表される評価を格納します。StarDelegateはQStyledItemDelegate を継承し、QStyledItemDelegate がすでに処理しているデータ型に加え、StarRatingのサポートを提供します。StarEditorQWidget を継承しており、 によって、ユーザーがマウスを使って星の評価を編集できるようにするために使用されます。StarDelegate
StarDelegate の動作を示すために、QTableWidget にデータを設定し、そのオブジェクトにデリゲートを登録します。
StarDelegate クラスの定義
StarDelegate クラスの定義は以下の通りです。
class StarDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
using QStyledItemDelegate::QStyledItemDelegate;
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const override;
private slots:
void commitAndCloseEditor();
};すべてのパブリック関数は、QStyledItemDelegate から再実装された仮想関数であり、カスタムな描画や編集機能を提供します。
StarDelegate クラスの実装
paint() 関数はQStyledItemDelegate から再実装されたもので、ビューがアイテムの再描画を必要とするたびに呼び出されます:
void StarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.data().canConvert<StarRating>()) {
StarRating starRating = qvariant_cast<StarRating>(index.data());
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.highlight());
starRating.paint(painter, option.rect, option.palette,
StarRating::EditMode::ReadOnly);
} else {
QStyledItemDelegate::paint(painter, option, index);
}この関数は、モデルからの `QModelIndex ` オブジェクトによって表される各アイテムに対して1回ずつ呼び出されます。アイテムに格納されているデータが `StarRating` である場合は、自ら描画を行い、そうでない場合は `QStyledItemDelegate ` に描画を任せます。これにより、StarDelegate が最も一般的なデータ型を確実に処理できるようになります。
アイテムがStarRating である場合、アイテムが選択されているときは背景を描画し、アイテム自体はStarRating::paint() を使用して描画します。これについては後で詳しく説明します。
StartRating starrating.h に定義されている ()マクロのおかげで、sを に格納することができます。これについては後で詳しく説明します。Q_DECLARE_METATYPE QVariant
createEditor() 関数は、ユーザーが項目の編集を開始した際に呼び出されます:
QWidget *StarDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.data().canConvert<StarRating>()) {
StarEditor *editor = new StarEditor(parent);
connect(editor, &StarEditor::editingFinished,
this, &StarDelegate::commitAndCloseEditor);
return editor;
}
return QStyledItemDelegate::createEditor(parent, option, index);
}そのアイテムがStarRating である場合、StarEditor を作成し、そのeditingFinished() シグナルをcommitAndCloseEditor() スロットに接続します。これにより、エディタが閉じられた際にモデルを更新できるようになります。
以下に、commitAndCloseEditor() の実装を示します:
void StarDelegate::commitAndCloseEditor()
{
StarEditor *editor = qobject_cast<StarEditor *>(sender());
emit commitData(editor);
emit closeEditor(editor);
}ユーザーが編集を完了すると、commitData() およびcloseEditor()(いずれもQAbstractItemDelegate 内で宣言されています)を発行し、モデルに対して編集されたデータがあることを通知するとともに、ビューに対してエディタが不要になったことを伝えます。
setEditorData() 関数は、エディタが作成された際に呼び出され、モデルからのデータでエディタを初期化します:
void StarDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
if (index.data().canConvert<StarRating>()) {
StarRating starRating = qvariant_cast<StarRating>(index.data());
StarEditor *starEditor = qobject_cast<StarEditor *>(editor);
starEditor->setStarRating(starRating);
} else {
QStyledItemDelegate::setEditorData(editor, index);
}
}エディタに対してsetStarRating() を呼び出すだけです。
編集が完了した際、エディタからモデルへデータを反映するために `setModelData()` 関数が呼び出されます:
void StarDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
if (index.data().canConvert<StarRating>()) {
StarEditor *starEditor = qobject_cast<StarEditor *>(editor);
model->setData(index, QVariant::fromValue(starEditor->starRating()));
} else {
QStyledItemDelegate::setModelData(editor, model, index);
}
}sizeHint() 関数は、項目の推奨サイズを返します:
QSize StarDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (index.data().canConvert<StarRating>()) {
StarRating starRating = qvariant_cast<StarRating>(index.data());
return starRating.sizeHint();
}
return QStyledItemDelegate::sizeHint(option, index);
}単に `StarRating` への呼び出しを転送します。
StarEditor クラスの定義
StarDelegate を実装する際には、StarEditor クラスが使用されました。クラス定義は以下の通りです:
class StarEditor : public QWidget
{
Q_OBJECT
public:
StarEditor(QWidget *parent = nullptr);
QSize sizeHint() const override;
void setStarRating(const StarRating &starRating) {
myStarRating = starRating;
}
StarRating starRating() { return myStarRating; }
signals:
void editingFinished();
protected:
void paintEvent(QPaintEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
private:
int starAtPosition(int x) const;
StarRating myStarRating;
};このクラスにより、ユーザーはエディタ上でマウスを動かすことでStarRating を編集できます。ユーザーがエディタをクリックすると、editingFinished() シグナルを発信します。
マウスイベントや描画イベントを処理するために、QWidget のprotected関数が再実装されています。private関数starAtPosition() は、マウスポインタの下にある星の番号を返すヘルパー関数です。
StarEditor クラスの実装
まず、コンストラクタから見ていきましょう:
StarEditor::StarEditor(QWidget *parent)
: QWidget(parent)
{
setMouseTracking(true);
setAutoFillBackground(true);
}ユーザーがマウスボタンを押していないときでもカーソルを追跡できるように、ウィジェットで `mouse tracking ` を有効にします。また、不透明な背景を得るために、QWidget の `auto-fill background ` 機能を有効にします。(この呼び出しがないと、ビューの背景がエディタを通して透けて見えてしまいます。)
paintEvent() 関数は、QWidget から再実装されています:
void StarEditor::paintEvent(QPaintEvent *)
{
QPainter painter(this);
myStarRating.paint(&painter, rect(), palette(),
StarRating::EditMode::Editable);
}StarDelegate を実装したときと同様に、星を描画するために単にStarRating::paint() を呼び出します。
void StarEditor::mouseMoveEvent(QMouseEvent *event)
{
const int star = starAtPosition(event->position().toPoint().x());
if (star != myStarRating.starCount() && star != -1) {
myStarRating.setStarCount(star);
update();
}
QWidget::mouseMoveEvent(event);
}マウスイベントハンドラ内では、現在のカーソル位置を反映させるために、プライベートデータメンバ `myStarRating ` に対して `setStarCount() ` を呼び出し、再描画を強制するために `QWidget::update()` を呼び出します。
void StarEditor::mouseReleaseEvent(QMouseEvent *event)
{
emit editingFinished();
QWidget::mouseReleaseEvent(event);
}ユーザーがマウスボタンを離したときは、単にeditingFinished() シグナルを発生させます。
int StarEditor::starAtPosition(int x) const
{
const int star = (x / (myStarRating.sizeHint().width()
/ myStarRating.maxStarCount())) + 1;
if (star <= 0 || star > myStarRating.maxStarCount())
return -1;
return star;
}starAtPosition() 関数は、基本的な線形代数を用いて、カーソルの下にある星を特定します。
StarRating クラスの定義
class StarRating
{
public:
enum class EditMode { Editable, ReadOnly };
explicit StarRating(int starCount = 1, int maxStarCount = 5);
void paint(QPainter *painter, const QRect &rect,
const QPalette &palette, EditMode mode) const;
QSize sizeHint() const;
int starCount() const { return myStarCount; }
int maxStarCount() const { return myMaxStarCount; }
void setStarCount(int starCount) { myStarCount = starCount; }
void setMaxStarCount(int maxStarCount) { myMaxStarCount = maxStarCount; }
private:
QPolygonF starPolygon;
QPolygonF diamondPolygon;
int myStarCount;
int myMaxStarCount;
};
Q_DECLARE_METATYPE(StarRating)StarRating クラスは、評価を星の数として表現します。データを保持するだけでなく、QPaintDevice (この例ではビューまたはエディタ)上に星を描画することもできます。myStarCount メンバ変数は現在の評価を格納し、myMaxStarCount は最高評価(通常は 5)を格納します。
Q_DECLARE_METATYPE() マクロは、型StarRating をQVariant に認識させ、StarRating の値をQVariant に格納できるようにします。
StarRating クラスの実装
コンストラクタは、myStarCount とmyMaxStarCount を初期化し、星やひし形を描画するために使用されるポリゴンを設定します。
StarRating::StarRating(int starCount, int maxStarCount)
: myStarCount(starCount),
myMaxStarCount(maxStarCount)
{
starPolygon << QPointF(1.0, 0.5);
for (int i = 1; i < 5; ++i)
starPolygon << QPointF(0.5 + 0.5 * std::cos(0.8 * i * 3.14),
0.5 + 0.5 * std::sin(0.8 * i * 3.14));
diamondPolygon << QPointF(0.4, 0.5) << QPointF(0.5, 0.4)
<< QPointF(0.6, 0.5) << QPointF(0.5, 0.6)
<< QPointF(0.4, 0.5);
}paint() 関数は、このStarRating オブジェクト内の星をペイントデバイス上に描画します:
void StarRating::paint(QPainter *painter, const QRect &rect,
const QPalette &palette, EditMode mode) const
{
painter->save();
painter->setRenderHint(QPainter::Antialiasing, true);
painter->setPen(Qt::NoPen);
painter->setBrush(mode == EditMode::Editable ?
palette.highlight() :
palette.windowText());
const int yOffset = (rect.height() - PaintingScaleFactor) / 2;
painter->translate(rect.x(), rect.y() + yOffset);
painter->scale(PaintingScaleFactor, PaintingScaleFactor);
for (int i = 0; i < myMaxStarCount; ++i) {
if (i < myStarCount)
painter->drawPolygon(starPolygon, Qt::WindingFill);
else if (mode == EditMode::Editable)
painter->drawPolygon(diamondPolygon, Qt::WindingFill);
painter->translate(1.0, 0.0);
}
painter->restore();
}まず、描画に使用するペンとブラシを設定します。mode パラメータには、Editable またはReadOnly のいずれかを指定できます。mode が編集可能な場合、星の描画にはWindowText の色ではなく、Highlight の色を使用します。
次に、星を描画します。Edit モードの場合、評価が最高評価を下回っているときは、星の代わりにひし形を描画します。
sizeHint() 関数は、星を描画するための領域の推奨サイズを返します:
この推奨サイズは、星を最大数だけ描画するのにちょうど十分なサイズです。この関数は、StarDelegate::sizeHint() およびStarEditor::sizeHint() の両方から呼び出されます。
main() 関数
以下に、プログラムの `main() ` 関数を示します:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QTableWidget tableWidget(4, 4);
tableWidget.setItemDelegate(new StarDelegate);
tableWidget.setEditTriggers(QAbstractItemView::DoubleClicked
| QAbstractItemView::SelectedClicked);
tableWidget.setSelectionBehavior(QAbstractItemView::SelectRows);
tableWidget.setHorizontalHeaderLabels({"Title", "Genre", "Artist", "Rating"});
populateTableWidget(&tableWidget);
tableWidget.resizeColumnsToContents();
tableWidget.resize(500, 300);
tableWidget.show();
return app.exec();
}main() 関数は、QTableWidget を作成し、そこにStarDelegate を設定します。DoubleClicked とSelectedClicked はedit triggers に設定されており、星評価項目が選択された際にワンクリックでエディタが開くようになっています。
populateTableWidget() 関数は、QTableWidget にデータを設定します:
void populateTableWidget(QTableWidget *tableWidget)
{
static constexpr struct {
const char *title;
const char *genre;
const char *artist;
int rating;
} staticData[] = {
{ "Mass in B-Minor", "Baroque", "J.S. Bach", 5 },
...
{ nullptr, nullptr, nullptr, 0 }
};
for (int row = 0; staticData[row].title != nullptr; ++row) {
QTableWidgetItem *item0 = new QTableWidgetItem(staticData[row].title);
QTableWidgetItem *item1 = new QTableWidgetItem(staticData[row].genre);
QTableWidgetItem *item2 = new QTableWidgetItem(staticData[row].artist);
QTableWidgetItem *item3 = new QTableWidgetItem;
item3->setData(0,
QVariant::fromValue(StarRating(staticData[row].rating)));
tableWidget->setItem(row, 0, item0);
tableWidget->setItem(row, 1, item1);
tableWidget->setItem(row, 2, item2);
tableWidget->setItem(row, 3, item3);
}
}StarRating をQVariant に変換するために、QVariant::fromValue が呼び出されている点に注意してください。
拡張の可能性と提案
Qtのモデル/ビューフレームワークをカスタマイズする方法は数多くあります。この例で採用されているアプローチは、ほとんどのカスタムデリゲートやエディタに適しています。starデリゲートやstarエディタでは使用されていない可能性のある例としては、次のようなものがあります:
- 編集トリガーに依存する代わりに、QAbstractItemView::edit() を呼び出すことで、プログラム的にエディタを開くことが可能です。これにより、QAbstractItemView::EditTrigger 列挙型で提供されるもの以外の編集トリガーをサポートできるようになります。例えば、Star Delegateの例では、マウスでアイテムにカーソルを合わせることでエディタをポップアップさせるといった方法が考えられます。
- QAbstractItemDelegate::editorEvent() を再実装することで、QWidget のサブクラスを別途作成する代わりに、デリゲート内で直接エディタを実装することが可能です。
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.