PyQt5 QTableViewのサンプル

Share on:

PyQt5でQTableViewのサンプルを作ってみました。

機能

  • QTableViewの表示、編集
  • 行の挿入
  • 行の削除
  • コンテキストメニュー

列数の設定

1self.model.column = 100

表の列数は上記のコードで設定していて、行の挿入を行ったときにself.model.columnの要素数を持ったリストを行に追加します。

行の挿入

 1def insertRow(self):
 2    indexes = self.ui.tableView.selectedIndexes()
 3    
 4    if len(indexes) == 0:
 5        item = [ str(self.model.rowCount()) + str(i) for i in range(self.model.column) ]
 6        self.model.addItem( self.model.rowCount(), item )
 7        return
 8    
 9    indexes2 = []
10    for index in indexes[::-1]:
11        if not index.row() in [ index2.row() for index2 in indexes2 ]:
12            indexes2.append(index)
13
14    for index in indexes2[::-1]:
15        item = [ str(self.model.rowCount()) + str(i) for i in range(self.model.column) ]
16        self.model.addItem( index.row() + 1, item )

処理内容は下記の通りです。

  • 選択しているセルのインデックス(QModelIndex)を取得
  • 選択してるインデックスが0個=何も選択されていなければ最後の行に追加
  • 選択されているセルがあれば、行の重複がないインデックスのリストを作成して、そのインデックスの次の行に行を挿入

行の削除

 1def delItem(self):
 2    indexes = self.ui.tableView.selectedIndexes()
 3    
 4    if self.model.rowCount() == 0:
 5        return
 6
 7    if len(indexes) == 0:
 8        self.model.removeItem( self.model.rowCount()-1 )
 9        return
10    
11    rows = set( [ index.row() for index in indexes ] )
12    for row in list(rows)[::-1]:
13        self.model.removeItem( row )

処理内容は下記の通りです。

  • 表に行がなければ処理終了
  • 選択しているセルがなければ最後の行を削除
  • 選択しているセルがあれば、選択しているセルから重複無しの行番号のリストを作成して、そのリストの最後から行を削除

コンテキストメニュー

1def contextMenu(self, point):
2    self.menu = QtWidgets.QMenu(self)
3    self.menu.addAction('Insert', self.insertRow)
4    self.menu.addAction('Delete', self.delItem)
5    self.menu.exec_( self.focusWidget().mapToGlobal(point) )

コンテキストメニューには前述の行の追加、削除の機能を設定しています。

ソースコード

作成したコードはgithubにあります。

main.py

 1import sys
 2from mainwindow import Ui_MainWindow
 3from tableview import Model, Delegate, Item
 4from PyQt5 import QtWidgets, QtCore
 5
 6class MainWindow(QtWidgets.QMainWindow):
 7    def __init__(self):
 8        super().__init__()
 9
10        self.ui = Ui_MainWindow()
11        self.ui.setupUi(self)
12
13        self.model = Model(self)
14        self.model.column = 100
15
16        self.ui.tableView.setModel(self.model)
17        self.ui.tableView.setItemDelegate(Delegate())
18        self.ui.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
19        self.ui.tableView.customContextMenuRequested.connect(self.contextMenu)
20        self.ui.pushButton.clicked.connect(self.insertRow)
21        self.ui.pushButton_2.clicked.connect(self.delItem)
22
23    def contextMenu(self, point):
24        self.menu = QtWidgets.QMenu(self)
25        self.menu.addAction('Insert', self.insertRow)
26        self.menu.addAction('Delete', self.delItem)
27        self.menu.exec_( self.focusWidget().mapToGlobal(point) )
28 
29    def insertRow(self):
30        indexes = self.ui.tableView.selectedIndexes()
31        
32        if len(indexes) == 0:
33            item = [ str(self.model.rowCount()) + str(i) for i in range(self.model.column) ]
34            self.model.addItem( self.model.rowCount(), item )
35            return
36        
37        indexes2 = []
38        for index in indexes[::-1]:
39            if not index.row() in [ index2.row() for index2 in indexes2 ]:
40                indexes2.append(index)
41
42        for index in indexes2:
43            item = [ str(self.model.rowCount()) + str(i) for i in range(self.model.column) ]
44            self.model.addItem( index.row() + 1, item )
45
46    def delItem(self):
47        indexes = self.ui.tableView.selectedIndexes()
48        
49        if self.model.rowCount() == 0:
50            return
51
52        if len(indexes) == 0:
53            self.model.removeItem( self.model.rowCount()-1 )
54            return
55        
56        rows = set( [ index.row() for index in indexes ] )
57        for row in list(rows)[::-1]:
58            self.model.removeItem( row )
59 
60def main():
61    app = QtWidgets.QApplication(sys.argv)
62    window = MainWindow()
63    window.show()
64    app.exec_()
65 
66if __name__ == '__main__':
67    main()

tableview.py

  1# -*- coding: utf-8 -*-
  2from PyQt5 import QtWidgets, QtCore
  3 
  4class Item(object):
  5    def __init__(self, _parent=None):
  6        self._dict = {}
  7        self.parent_item = _parent
  8        self.children = []
  9    
 10    def appendChild(self, item):
 11        self.children.append(item)
 12
 13    def data(self, column):
 14        if column in self._dict.keys():
 15            return self._dict[column]
 16        return ''
 17 
 18    def setData(self, column, data):
 19        self._dict[column] = data
 20    
 21    def child(self, row):
 22        return self.children[row]
 23
 24    def childrenCount(self):
 25        return len(self.children)
 26
 27    def parent(self):
 28        return self.parent_item
 29
 30    def removeChild(self, row):
 31        del self.children[row]
 32
 33    def row(self):
 34        if self.parent_item:
 35            return self.parent_item.children.index(self)
 36        return 0
 37
 38class Model(QtCore.QAbstractItemModel):
 39    def __init__(self, parent_=None):
 40        super(Model, self).__init__(parent_)
 41        self.items = []
 42        self.column = 0
 43
 44    def addItem(self, row, item, parent=QtCore.QModelIndex()):
 45        self.beginInsertRows(parent, row, row)
 46        self.items.insert(row, item)
 47        self.endInsertRows()
 48
 49    def columnCount(self, parent=QtCore.QModelIndex()):
 50        if len(self.items) == 0:
 51            return self.column
 52        return len(self.items[0])
 53 
 54    def data(self, index, role):
 55        if role == QtCore.Qt.EditRole or role == QtCore.Qt.DisplayRole:
 56            return self.items[index.row()][index.column()]
 57        return QtCore.QVariant()
 58        
 59    def flags(self, index):
 60        return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
 61
 62    def headerData(self, i, orientation, role):
 63        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
 64            return i
 65        if orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole:
 66            return i
 67
 68    def index(self, row, column, parent=QtCore.QModelIndex()):
 69        return self.createIndex(row, column, parent)
 70
 71    def parent(self, index):
 72        return QtCore.QModelIndex()
 73        
 74    def removeItem(self, row, parent=QtCore.QModelIndex()):
 75        self.beginRemoveRows(parent, row, row)
 76        del self.items[row]
 77        self.endRemoveRows()
 78 
 79    def rowCount(self, parent=QtCore.QModelIndex()):
 80        return len(self.items)
 81
 82    def setData(self, index, value, role=QtCore.Qt.EditRole):
 83        if role == QtCore.Qt.EditRole:
 84            self.items[index.row()][index.column()] = value
 85            #index.internalPointer() = value
 86            return True
 87        return False
 88
 89class Delegate(QtWidgets.QStyledItemDelegate):
 90    def __init__(self, parent=None, setModelDataEvent=None):
 91        super(Delegate, self).__init__(parent)
 92        self.setModelDataEvent = setModelDataEvent
 93 
 94    def createEditor(self, parent, option, index):
 95        return QtWidgets.QLineEdit(parent)
 96 
 97    def setEditorData(self, editor, index):
 98        value = index.model().data(index, QtCore.Qt.DisplayRole)
 99        editor.setText(str(value))
100 
101    def setModelData(self, editor, model, index):
102        model.setData(index, editor.text())
103        if not self.setModelDataEvent is None:
104            self.setModelDataEvent()

関連記事