PyQt5 QTableViewのサンプル
2020/01/26 categories:PyQt5| tags:Python|Python|QTableView|PyQt5|
PyQt5でQTableViewのサンプルを作ってみました。
機能
- QTableViewの表示、編集
- 行の挿入
- 行の削除
- コンテキストメニュー
列数の設定
self.model.column = 100
表の列数は上記のコードで設定していて、行の挿入を行ったときにself.model.columnの要素数を持ったリストを行に追加します。
行の挿入
def insertRow(self):
indexes = self.ui.tableView.selectedIndexes()
if len(indexes) == 0:
item = [ str(self.model.rowCount()) + str(i) for i in range(self.model.column) ]
self.model.addItem( self.model.rowCount(), item )
return
indexes2 = []
for index in indexes[::-1]:
if not index.row() in [ index2.row() for index2 in indexes2 ]:
indexes2.append(index)
for index in indexes2[::-1]:
item = [ str(self.model.rowCount()) + str(i) for i in range(self.model.column) ]
self.model.addItem( index.row() + 1, item )
処理内容は下記の通りです。
- 選択しているセルのインデックス(QModelIndex)を取得
- 選択してるインデックスが0個=何も選択されていなければ最後の行に追加
- 選択されているセルがあれば、行の重複がないインデックスのリストを作成して、そのインデックスの次の行に行を挿入
行の削除
def delItem(self):
indexes = self.ui.tableView.selectedIndexes()
if self.model.rowCount() == 0:
return
if len(indexes) == 0:
self.model.removeItem( self.model.rowCount()-1 )
return
rows = set( [ index.row() for index in indexes ] )
for row in list(rows)[::-1]:
self.model.removeItem( row )
処理内容は下記の通りです。
- 表に行がなければ処理終了
- 選択しているセルがなければ最後の行を削除
- 選択しているセルがあれば、選択しているセルから重複無しの行番号のリストを作成して、そのリストの最後から行を削除
コンテキストメニュー
def contextMenu(self, point):
self.menu = QtWidgets.QMenu(self)
self.menu.addAction('Insert', self.insertRow)
self.menu.addAction('Delete', self.delItem)
self.menu.exec_( self.focusWidget().mapToGlobal(point) )
コンテキストメニューには前述の行の追加、削除の機能を設定しています。
ソースコード
作成したコードはgithubにあります。
main.py
import sys
from mainwindow import Ui_MainWindow
from tableview import Model, Delegate, Item
from PyQt5 import QtWidgets, QtCore
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.model = Model(self)
self.model.column = 100
self.ui.tableView.setModel(self.model)
self.ui.tableView.setItemDelegate(Delegate())
self.ui.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.ui.tableView.customContextMenuRequested.connect(self.contextMenu)
self.ui.pushButton.clicked.connect(self.insertRow)
self.ui.pushButton_2.clicked.connect(self.delItem)
def contextMenu(self, point):
self.menu = QtWidgets.QMenu(self)
self.menu.addAction('Insert', self.insertRow)
self.menu.addAction('Delete', self.delItem)
self.menu.exec_( self.focusWidget().mapToGlobal(point) )
def insertRow(self):
indexes = self.ui.tableView.selectedIndexes()
if len(indexes) == 0:
item = [ str(self.model.rowCount()) + str(i) for i in range(self.model.column) ]
self.model.addItem( self.model.rowCount(), item )
return
indexes2 = []
for index in indexes[::-1]:
if not index.row() in [ index2.row() for index2 in indexes2 ]:
indexes2.append(index)
for index in indexes2:
item = [ str(self.model.rowCount()) + str(i) for i in range(self.model.column) ]
self.model.addItem( index.row() + 1, item )
def delItem(self):
indexes = self.ui.tableView.selectedIndexes()
if self.model.rowCount() == 0:
return
if len(indexes) == 0:
self.model.removeItem( self.model.rowCount()-1 )
return
rows = set( [ index.row() for index in indexes ] )
for row in list(rows)[::-1]:
self.model.removeItem( row )
def main():
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
if __name__ == '__main__':
main()
tableview.py
## -*- coding: utf-8 -*-
from PyQt5 import QtWidgets, QtCore
class Item(object):
def __init__(self, _parent=None):
self._dict = {}
self.parent_item = _parent
self.children = []
def appendChild(self, item):
self.children.append(item)
def data(self, column):
if column in self._dict.keys():
return self._dict[column]
return ''
def setData(self, column, data):
self._dict[column] = data
def child(self, row):
return self.children[row]
def childrenCount(self):
return len(self.children)
def parent(self):
return self.parent_item
def removeChild(self, row):
del self.children[row]
def row(self):
if self.parent_item:
return self.parent_item.children.index(self)
return 0
class Model(QtCore.QAbstractItemModel):
def __init__(self, parent_=None):
super(Model, self).__init__(parent_)
self.items = []
self.column = 0
def addItem(self, row, item, parent=QtCore.QModelIndex()):
self.beginInsertRows(parent, row, row)
self.items.insert(row, item)
self.endInsertRows()
def columnCount(self, parent=QtCore.QModelIndex()):
if len(self.items) == 0:
return self.column
return len(self.items[0])
def data(self, index, role):
if role == QtCore.Qt.EditRole or role == QtCore.Qt.DisplayRole:
return self.items[index.row()][index.column()]
return QtCore.QVariant()
def flags(self, index):
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
def headerData(self, i, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return i
if orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole:
return i
def index(self, row, column, parent=QtCore.QModelIndex()):
return self.createIndex(row, column, parent)
def parent(self, index):
return QtCore.QModelIndex()
def removeItem(self, row, parent=QtCore.QModelIndex()):
self.beginRemoveRows(parent, row, row)
del self.items[row]
self.endRemoveRows()
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
self.items[index.row()][index.column()] = value
#index.internalPointer() = value
return True
return False
class Delegate(QtWidgets.QStyledItemDelegate):
def __init__(self, parent=None, setModelDataEvent=None):
super(Delegate, self).__init__(parent)
self.setModelDataEvent = setModelDataEvent
def createEditor(self, parent, option, index):
return QtWidgets.QLineEdit(parent)
def setEditorData(self, editor, index):
value = index.model().data(index, QtCore.Qt.DisplayRole)
editor.setText(str(value))
def setModelData(self, editor, model, index):
model.setData(index, editor.text())
if not self.setModelDataEvent is None:
self.setModelDataEvent()