Qt Quick TableView の例 - コンウェイの「ライフ」
「コンウェイのライフゲーム」のサンプルでは、QMLのTableView 型を使用して、ユーザーが画面をスクロールして閲覧できるC++モデルを表示する方法を示しています。

例の動作
以下の手順でサンプルを実行できます。
- Qt Creator
Welcome モードを開き、Examples からこのサンプルを選択します。詳細については、Qt Creator の「チュートリアル:ビルドと実行」を参照してください。
- Qt Extension for Visual Studio Code
Command Palette から `Qt: Open Qt examples ` コマンドを実行し、リストからサンプルを選択します。詳細については、Qt Extension for Visual Studio Code の「チュートリアル: ビルドと実行」を参照してください。
QML ユーザーインターフェース
TableView {
id: tableView
anchors.fill: parent
rowSpacing: 1
columnSpacing: 1
ScrollBar.horizontal: ScrollBar {}
ScrollBar.vertical: ScrollBar {}
delegate: Rectangle {
id: cell
implicitWidth: 15
implicitHeight: 15
required property var model
required property bool value
color: value ? "#f3f3f4" : "#b5b7bf"
MouseArea {
anchors.fill: parent
onClicked: parent.model.value = !parent.value
}
}このサンプルでは、TableView コンポーネントを使用してセルのグリッドを表示しています。各セルは、TableViewのデリゲートであるRectangle QMLコンポーネントによって画面上に描画されます。ユーザーがセルをクリックした際、その値を読み取り、model.value を使用して値を変更します。
contentX: (contentWidth - width) / 2;
contentY: (contentHeight - height) / 2;アプリケーションの起動時、TableView は、contentX およびcontentY プロパティを使用してスクロール位置を更新し、contentWidth およびcontentHeight を使用してビューをスクロールさせるべき位置を計算することで、中央にスクロールされます。
model: GameOfLifeModel {
id: gameOfLifeModel
}C++ モデル
class GameOfLifeModel : public QAbstractTableModel
{
Q_OBJECT
QML_ELEMENT
public:
enum Roles {
CellRole
};
Q_ENUM(Roles)
QHash<int, QByteArray> roleNames() const override {
return {
{ CellRole, "value" }
};
}
explicit GameOfLifeModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
Q_INVOKABLE void nextStep();
Q_INVOKABLE bool loadFile(const QString &fileName);
Q_INVOKABLE void loadPattern(const QString &plainText);
Q_INVOKABLE void clear();
private:
static constexpr int width = 256;
static constexpr int height = 256;
static constexpr int size = width * height;
using StateContainer = std::array<bool, size>;
StateContainer m_currentState;
int cellNeighborsCount(const QPoint &cellCoordinates) const;
static bool areCellCoordinatesValid(const QPoint &coordinates);
static QPoint cellCoordinatesFromIndex(int cellIndex);
static std::size_t cellIndex(const QPoint &coordinates);
};GameOfLifeModel クラスはQAbstractTableModel を継承しており、これによりTableView コンポーネントのモデルとして使用できます。 したがって、TableView コンポーネントがモデルとやり取りできるように、いくつかの関数を実装する必要があります。クラスのprivate 部分でわかるように、このモデルは固定サイズの配列を使用して、すべてのセルの現在の状態を格納しています。また、QMLからこのクラスを公開するために、QML_ELEMENT マクロを使用しています。
int GameOfLifeModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return height;
}
int GameOfLifeModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return width;
}ここでは、TableView コンポーネントがテーブルのサイズを把握できるように、rowCount およびcolumnCount メソッドが実装されています。これらは単に、width およびheight 定数の値を返すだけです。
QVariant GameOfLifeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || role != CellRole)
return QVariant();
return QVariant(m_currentState[cellIndex({index.column(), index.row()})]);
}このメソッドは、TableView コンポーネントがモデルからデータを要求した際に呼び出されます。 この例では、各セルにつき「生存しているか否か」という1つのデータのみを持っています。この情報は、C++コード内のRoles 列挙型のCellRole 値によって表されており、これはQMLコード内のvalue プロパティに対応しています(これら2つの関連付けは、C++クラスのroleNames() 関数によって行われます)。
GameOfLifeModel クラスは、index パラメータ(行と列を含むQModelIndex )を使用して、どのセルからデータが要求されたかを特定できます。
データの更新
bool GameOfLifeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role != CellRole || data(index, role) == value)
return false;
m_currentState[cellIndex({index.column(), index.row()})] = value.toBool();
emit dataChanged(index, index, {role});
return true;
}setData メソッドは、QMLインターフェースからプロパティの値が設定された際に呼び出されます。この例では、セルがクリックされた際にその状態を切り替えます。data() 関数と同様に、このメソッドもindex とrole パラメータを受け取ります。さらに、新しい値はQVariant として渡され、これをtoBool 関数を使用してブール値に変換します。
モデルオブジェクトの内部状態を更新する際は、TableView コンポーネントに対して、表示データを更新する必要があることを伝えるために、dataChanged シグナルを発行する必要があります。この場合、クリックされたセルのみが影響を受けるため、更新が必要なテーブルの範囲は、そのセルのインデックスを起点および終点とします。
void GameOfLifeModel::nextStep()
{
StateContainer newValues;
for (std::size_t i = 0; i < size; ++i) {
bool currentState = m_currentState[i];
int cellNeighborsCount = this->cellNeighborsCount(cellCoordinatesFromIndex(static_cast<int>(i)));
newValues[i] = currentState == true
? cellNeighborsCount == 2 || cellNeighborsCount == 3
: cellNeighborsCount == 3;
}
m_currentState = std::move(newValues);
emit dataChanged(index(0, 0), index(height - 1, width - 1), {CellRole});
}この関数は、定義内にQ_INVOKABLE マクロが含まれているため、QMLコードから直接呼び出すことができます。この関数は、ユーザーが「次へ」ボタンをクリックしたとき、またはタイマーがtriggered() シグナルを発行したときに、ゲームの1イテレーションを実行します。
コンウェイの「ライフ」のルールに従い、各セルの新しい状態は、その隣接セルの現在の状態に基づいて計算されます。グリッド全体の新しい状態が計算されると、現在の状態が置き換えられ、テーブル全体に対して`dataChanged`シグナルが発信されます。
bool GameOfLifeModel::loadFile(const QString &fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly))
return false;
QTextStream in(&file);
loadPattern(in.readAll());
return true;
}
void GameOfLifeModel::loadPattern(const QString &plainText)
{
clear();
QStringList rows = plainText.split("\n");
QSize patternSize(0, rows.count());
for (QString row : rows) {
if (row.size() > patternSize.width())
patternSize.setWidth(row.size());
}
QPoint patternLocation((width - patternSize.width()) / 2, (height - patternSize.height()) / 2);
for (int y = 0; y < patternSize.height(); ++y) {
const QString line = rows[y];
for (int x = 0; x < line.length(); ++x) {
QPoint cellPosition(x + patternLocation.x(), y + patternLocation.y());
m_currentState[cellIndex(cellPosition)] = line[x] == 'O';
}
}
emit dataChanged(index(0, 0), index(height - 1, width - 1), {CellRole});
}アプリケーションの起動時には、コンウェイのライフゲームの仕組みを示すパターンが読み込まれます。以下の2つの関数は、パターンが保存されているファイルを読み込み、解析します。「nextStep 」関数と同様に、パターンの読み込みが完了すると、テーブル全体に対してdataChanged シグナルが発信されます。
© 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.