PySide Model/View【第1弾】表・一覧表示を本格運用!QTableView + QStandardItemModel

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

表や一覧表示を「とりあえず動かす」なら QTableWidget が手軽ですが、大量データ外部ソース(CSV/DB/API)再利用性 を考えると Model/View 方式が圧倒的に便利です。

本記事では QTableView(表示)QStandardItemModel(データ) を組み合わせ、拡張性の高い表UIを作る基礎を丁寧に解説します。
「セルをどう埋めるか」ではなく、「データをどう設計して表示に渡すか」という発想に切り替えるのがポイントです。

目次

QTableView + QStandardItemModelとは?

QTableView は「データを表(テーブル)として表示するための部品」です。
一方の QStandardItemModel は「表に入れるデータを管理する入れ物」です。

この2つを組み合わせると、ボタンを配置するのと同じ感覚で 表形式のデータ表示 が作れます。
たとえば、エクセルのように「行と列があって、その中に文字や数値を入れる」というイメージです。

初心者の方は、まず「QTableWidget」で表を作ってみて、
そのあと「QTableView + QStandardItemModel」に進むと、もっと自由度の高いアプリを作れるようになります。

基本コード

from PySide6.QtWidgets import QApplication, QMainWindow, QTableView
from PySide6.QtGui import QStandardItemModel, QStandardItem
from PySide6.QtCore import Qt
import sys

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QTableView + QStandardItemModel 入門")

        # 1) モデル作成(行3・列2)
        model = QStandardItemModel(3, 2, self)
        model.setHorizontalHeaderLabels(["名前", "年齢"])

        # 2) データ投入(QStandardItem を使う)
        model.setItem(0, 0, QStandardItem("Alice"))
        model.setItem(0, 1, QStandardItem("23"))
        model.setItem(1, 0, QStandardItem("Bob"))
        model.setItem(1, 1, QStandardItem("31"))
        model.setItem(2, 0, QStandardItem("Charlie"))
        model.setItem(2, 1, QStandardItem("28"))

        # 3) View にモデルをセット
        view = QTableView(self)
        view.setModel(model)

        # 4) 使い勝手向上(任意)
        view.setSortingEnabled(True)                     # ヘッダクリックでソート
        view.setSelectionBehavior(QTableView.SelectRows) # 行単位選択
        view.resizeColumnsToContents()                   # 列幅自動調整

        self.setCentralWidget(view)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MainWindow()
    w.resize(500, 300)
    w.show()
    sys.exit(app.exec())
  • View(見た目)Model(データ) を分離して扱うため、データ差し替えや複数ビュー共有が簡単。
  • QStandardItemModel は汎用モデル。自作データ構造と厳密に結びつけたい場合は QAbstractTableModel に発展できます。

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

Noメソッド / プロパティ説明
1view.setModel(model) / view.model()View に Model を設定 / 取得view.setModel(model)
2model.setRowCount(n) / model.setColumnCount(n)行・列数の設定model.setRowCount(10)
3model.rowCount() / model.columnCount()行・列数の取得print(model.rowCount())
4model.setHorizontalHeaderLabels(list)列ヘッダー名の一括設定model.setHorizontalHeaderLabels(["A","B"])
5model.setItem(r,c,QStandardItem) / model.item(r,c)Item の設定 / 取得model.setItem(0,0,QStandardItem("x"))
6model.index(r,c) / model.data(index, role) / model.setData(index, value, role)QModelIndex を介したデータ取得/設定model.setData(model.index(0,0),"x")
7model.insertRow(r) / model.removeRow(r) / insertColumn/ removeColumn行列の挿入・削除model.insertRow(1)
8model.clear()モデル内容をクリア(ヘッダ含む)model.clear()
9view.setSortingEnabled(True) / model.sort(col, order)ソートの有効化 / 実行model.sort(1, Qt.AscendingOrder)
10view.setEditTriggers(flags)編集可否(ダブルクリック等)view.setEditTriggers(QTableView.NoEditTriggers)
11view.setSelectionBehavior(mode) / view.setSelectionMode(mode)行/セル単位選択・単数/複数選択view.setSelectionBehavior(QTableView.SelectRows)
12view.resizeColumnsToContents() / resizeRowsToContents()内容に応じた自動サイズ調整view.resizeColumnsToContents()
13view.horizontalHeader() / view.verticalHeader()ヘッダーの詳細設定view.horizontalHeader().setStretchLastSection(True)
14item.setEditable(bool) / item.setCheckable(bool) などアイテムの属性(編集可・チェック等)item.setEditable(False)
15model.itemFromIndex(index) / model.indexFromItem(item)Index ⇔ Item 変換item = model.itemFromIndex(idx)
16model.findItems(text, flags, column)文言でアイテム検索model.findItems("Bob")

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

【1】Model を View に関連付ける

概要:表示(View)にデータ(Model)を渡します。
メソッドview.setModel(model) / view.model()
使い方

# 1) モデル作成(行3・列2)
model = QStandardItemModel(3, 2, self)

# 3) View にモデルをセット
view = QTableView(self)
view.setModel(model)
m = view.model()
print(m)

# <PySide6.QtGui.QStandardItemModel(0x183ed8921c0) at 0x00000183EDF54C40>

要点:複数の View で1つの Model を共有できます。

【2】行数・列数の設定

概要:表のサイズを変更します。
メソッドsetRowCount(int) / setColumnCount(int)
使い方

model.setRowCount(8)
model.setColumnCount(5)

【3】行数・列数の取得

概要:現在のサイズを調べます。
メソッドrowCount() / columnCount()
使い方

rows = model.rowCount()
cols = model.columnCount()
print(f'列数:{rows}')
print(f'行数:{cols}')

# 列数:8
# 行数:5

【4】列ヘッダーの設定

概要:見出しを一括設定します。
メソッドsetHorizontalHeaderLabels(list)
使い方

model.setHorizontalHeaderLabels(["名前", "年齢", "部署"])

補足:個別に設定したい場合は setHeaderData(col, Qt.Horizontal, value, role=Qt.DisplayRole) も可。

【5】Item の設定・取得

概要QStandardItem を直接入れたり取り出します。
メソッドsetItem(row, col, QStandardItem) / item(row, col)
使い方

item = QStandardItem("MIsa")
item.setEditable(False)
model.setItem(0, 0, item)
text = model.item(0, 0).text()
print(text)

# Misa

【6】QModelIndex を介したデータ入出力

概要index(row,col) でインデックスを作り、data/setData で値や表示属性(role)を操作します。
メソッドindex() / data(index, role) / setData(index, value, role)
使い方

idx = model.index(0, 1)
model.setData(idx, 42, role=Qt.DisplayRole)
val = model.data(idx, Qt.DisplayRole)
print(f'idx = {idx}')
print(f'val = {val}')

# idx = <PySide6.QtCore.QModelIndex(0,1,0x173c3e01df0,QStandardItemModel(0x173c4959020)) at 0x00000173C5044840>
# val = 42

補足:色やフォントは Qt.ForegroundRole / Qt.FontRole などの Role を使います。

【7】行・列の挿入/削除

概要:途中行・列の追加や削除。
メソッドinsertRow() / removeRow() / insertColumn() / removeColumn()
使い方

model.insertRow(1)
model.removeColumn(0)

【8】モデルのクリア

概要:中身を全消去(ヘッダーも消える)。
メソッドclear()
使い方

model.clear()

注意:ヘッダーも消えるため、必要なら再設定が必要。

【9】ソートの有効化/実行

概要:ヘッダークリックでソート、またはコードで明示的にソート。
メソッドview.setSortingEnabled(True) / model.sort(column, order)
使い方

view.setSortingEnabled(True)                  # UIでソート可能
model.sort(2, Qt.AscendingOrder)              # コードで実行

【10】編集可否

概要:セルを編集可能にする条件(クリック操作など)を制御。
メソッドview.setEditTriggers(flags)
使い方

from PySide6.QtWidgets import QAbstractItemView as AIV
view.setEditTriggers(AIV.NoEditTriggers)      # 編集不可
# 例: AIV.DoubleClicked, AIV.SelectedClicked, AIV.AllEditTriggers など
説明
view.setEditTriggers(QAbstractItemView.DoubleClicked)編集できるタイミングを設定
view.setEditTriggers(QAbstractItemView.NoEditTriggers)編集不可
view.setEditTriggers(QAbstractItemView.CurrentChanged)カレントセルが変わった時に編集可
view.setEditTriggers(QAbstractItemView.DoubleClicked)ダブルクリックで編集可
view.setEditTriggers(QAbstractItemView.SelectedClicked)選択中のセルをクリックで編集可
view.setEditTriggers(QAbstractItemView.EditKeyPressed)EnterキーやF2キーで編集可
view.setEditTriggers(QAbstractItemView.AnyKeyPressed)文字入力で即編集開始
view.setEditTriggers(QAbstractItemView.AllEditTriggers)すべてのトリガーで編集可
view.setSelectionMode(QAbstractItemView.SingleSelection)選択方法を設定
view.setSelectionMode(QAbstractItemView.NoSelection)選択不可
view.setSelectionMode(QAbstractItemView.SingleSelection)1セルのみ選択可
view.setSelectionMode(QAbstractItemView.MultiSelection)複数セル選択可(Ctrlクリック)
view.setSelectionMode(QAbstractItemView.ExtendedSelection)複数セル選択可(ShiftやCtrl併用)
view.setSelectionBehavior(QAbstractItemView.SelectRows)選択対象(セル・行・列)を設定
view.setSelectionBehavior(QAbstractItemView.SelectItems)セル単位で選択
view.setSelectionBehavior(QAbstractItemView.SelectRows)行単位で選択
view.setSelectionBehavior(QAbstractItemView.SelectColumns)列単位で選択

【11】選択挙動

概要:行/セル単位の選択や複数選択可否を制御。
メソッドview.setSelectionBehavior(mode) / view.setSelectionMode(mode)
使い方

from PySide6.QtWidgets import QAbstractItemView as AIV
view.setSelectionBehavior(AIV.SelectRows)     # 行単位
view.setSelectionMode(AIV.SingleSelection)    # 単一選択

【12】列・行サイズの自動調整

概要:内容に合わせて列・行サイズを合わせる。
メソッドresizeColumnsToContents() / resizeRowsToContents()
使い方

view.resizeColumnsToContents()

【13】ヘッダーの詳細設定

概要:ヘッダーの表示制御や伸縮設定。
メソッドhorizontalHeader() / verticalHeader()
使い方

hh = view.horizontalHeader()
hh.setStretchLastSection(True)    # 最終列を余白に合わせる
view.verticalHeader().setVisible(False)  # 行番号非表示
説明
view.horizontalHeader().setVisible(False)ヘッダーを非表示にする
view.horizontalHeader().setStretchLastSection(True)最後の列を自動で幅調整する
view.horizontalHeader().setDefaultSectionSize(120)デフォルトの列幅を設定
view.horizontalHeader().resizeSection(0, 200)特定の列幅を変更
view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)列幅をウィンドウサイズに合わせて自動調整
view.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)内容に応じて列幅を自動調整
view.verticalHeader().setVisible(False)行番号を非表示にする
view.verticalHeader().setDefaultSectionSize(40)行の高さを設定
view.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)行の高さを固定
view.verticalHeader().hide()行ヘッダーを完全に隠す(ショートカット)

【14】アイテム属性(編集/チェック/フォント等)

概要QStandardItem に対して属性を設定。
メソッドitem.setEditable(bool) / item.setCheckable(bool) など
使い方

it = QStandardItem("完了")
it.setCheckable(True)
it.setEditable(False)
model.setItem(0, 2, it)

【15】Index ⇔ Item 変換

概要QModelIndexQStandardItem を相互に変換。
メソッドitemFromIndex(index) / indexFromItem(item)
使い方

idx = model.index(0, 0)          # QModelIndex
item = model.itemFromIndex(idx)  # QStandardItem
idx2 = model.indexFromItem(item) # QModelIndex

【16】アイテム検索

概要:モデル内から文字列を検索して、該当するアイテムをリストで返す
メソッドfindItems(text, flags=Qt.MatchContains, column=-1)

引数説明
text: str検索する文字列"Python"
flags: Qt.MatchFlagマッチ条件を指定Qt.MatchExactly(完全一致), Qt.MatchStartsWith(前方一致), Qt.MatchContains(部分一致), Qt.MatchEndsWith(後方一致), Qt.MatchRegExp(正規表現検索)など
column: int検索対象の列を指定0(1列目), 2(3列目)

使い方

hits = model.findItems("Bob", Qt.MatchContains, 0)  # 0列目から検索
for it in hits:
   print(it.text())

# Bob

よくある質問(FAQ)

QTableWidget との違いは?

QTableWidget は手軽ですが、データと見た目が密結合。QTableView は Model と分離でき、再利用・複数ビュー・外部データ連携で有利です。

セル編集を禁止したい

view.setEditTriggers(QAbstractItemView.NoEditTriggers) または個別アイテムで item.setEditable(False)

大量データで遅い

QStandardItemModel は汎用性重視。数十万行などは QAbstractTableModel(必要時に data を供給)+ QTableView を検討。

ソート/フィルタは?

ソートは view.setSortingEnabled(True)。フィルタは QSortFilterProxyModel を View と Model の間に挟みます。

文字色やフォントを変えたい

model.setData(index, QBrush(Qt.red), Qt.ForegroundRole)Qt.FontRole を使用。

チェック付きの列を作りたい

QStandardItemsetCheckable(True)。値は item.checkState() / item.setCheckState()

最終列をウィンドウ幅にフィットさせたい

view.horizontalHeader().setStretchLastSection(True)

CSV/DB を表示したい

CSV は読み込んで QStandardItemModel に流し込み、DB は QSqlTableModel + QTableView が便利

まとめ

QTableView + QStandardItemModel は、表・一覧表示を 拡張性高く 構築できる王道パターンです。
setModel で表示とデータを分け、setItem / setData / insertRow 等で柔軟に編集できます。
ソート・選択・編集可否・サイズ調整などの UI も QTableView 側で一括制御できて便利。

次のステップは QSortFilterProxyModel(ソート/フィルタ強化)や、QAbstractTableModel(独自データ源の高速表示)です。

「QTableWidgetは卒業して、Model/Viewで一段上の表UIへ」—そんな一歩をこの回でぜひ掴んでください!

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

コメント

コメントする

目次