#!python3
# -*- coding: utf-8 -*-
import sys
import os.path
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtUiTools import QUiLoader
CURRENT_PATH = os.path.dirname(os.path.abspath(sys.argv[0]))
class TextEditDialog(QtWidgets.QDialog):
def __init__(self, uiPos, parent=None):
super(TextEditDialog, self).__init__(parent)
layout = QtWidgets.QVBoxLayout()
self.textEdit = QtWidgets.QTextEdit(self)
layout.addWidget(self.textEdit)
self.setLayout(layout)
btn = QtWidgets.QPushButton("Close")
btn.clicked.connect(self.close)
layout.addWidget(btn)
self.uiPos = uiPos
self.setWindowFlags(QtCore.Qt.Popup)
def showEvent(self, event):
self.setGeometry(self.uiPos.x(), self.uiPos.y(), 400, 300)
super(TextEditDialog, self).showEvent(event)
# TableViewの1行ごとのItemを管理するクラス
class DataItem(object):
def __init__(self, name="", check=False, progress=0, text=""):
self.name = name
self.check = check
self.progess = progress
self.text = text
def data(self, column):
if column == 0:
return self.name
elif column == 1:
return self.check
elif column == 2:
return self.progess
elif column == 3:
return self.text
def setData(self, column, value):
if column == 0:
self.name = value
elif column == 1:
self.check = value
elif column == 2:
self.progess = value
elif column == 3:
self.text = value
class TableDelegate(QtWidgets.QItemDelegate):
def __init__(self, parent=None):
super(TableDelegate, self).__init__(parent)
def createEditor(self, parent, option, index):
"""
編集したいCellに対して、編集用のWidgetsを作成する
"""
if index.column() == 0:
return QtWidgets.QLineEdit(parent)
if index.column() == 2:
spin = QtWidgets.QSpinBox(parent)
spin.setMinimum(0)
spin.setMaximum(100)
return spin
if index.column() == 3:
edit = TextEditDialog(parent.mapToGlobal(option.rect.topLeft()), parent)
return edit
def setEditorData(self, editor, index):
"""
createEditorで作成したWidgetsを受け取って、
Editorにデフォルト値を設定する。
今回の場合、元々のCellに表示されていた内容を受け取り、
QLineEditに対してデフォルト値をセットしている
"""
if index.column() == 0:
value = index.model().data(index, QtCore.Qt.DisplayRole)
editor.setText(value)
if index.column() == 2:
value = index.model().data(index, QtCore.Qt.DisplayRole)
editor.setValue(value)
if index.column() == 3:
value = index.model().data(index, QtCore.Qt.DisplayRole)
editor.textEdit.setText(value)
def editorEvent(self, event, model, option, index):
"""
TableのCellに対してなにかしらのイベント(クリックした等)が発生したときに呼ばれる。
"""
if index.column() == 1:
if self.checkBoxRect(option).contains(event.pos().x(), event.pos().y()):
if event.type() == QtCore.QEvent.MouseButtonPress:
currentValue = model.items[index.row()].data(index.column())
model.items[index.row()].setData(index.column(), not currentValue)
model.layoutChanged.emit()
return True
return False
def setModelData(self, editor, model, index):
"""
編集した値を、Modelを経由して実体のオブジェクトに対してセットする
"""
value = None
if index.column() == 0:
value = editor.text()
if index.column() == 2:
value = editor.value()
if index.column() == 3:
value = editor.textEdit.toPlainText()
if value is not None:
model.setData(index, value)
def checkBoxRect(self, option):
rect = option.rect
rect.setX(rect.x() + 10)
rect.setWidth(rect.width() - 20)
return rect
def paint(self, painter, option, index):
"""
Cellの中の描画を行う
"""
if index.column() in [0, 3]:
painter.drawText(option.rect, QtCore.Qt.AlignCenter | QtCore.Qt.TextWordWrap, index.data())
if index.column() == 1:
btn = QtWidgets.QStyleOptionButton()
btn.state |= QtWidgets.QStyle.State_Enabled
if index.data() == True:
btn.state |= QtWidgets.QStyle.State_On
else:
btn.state |= QtWidgets.QStyle.State_Off
btn.rect = self.checkBoxRect(option)
btn.text = "hogehoge"
QtWidgets.QApplication.style().drawControl(QtWidgets.QStyle.CE_CheckBox, btn, painter)
if index.column() == 2:
bar = QtWidgets.QStyleOptionProgressBar()
bar.rect = option.rect
bar.rect.setHeight(option.rect.height() - 1)
bar.rect.setTop(option.rect.top() + 1)
bar.minimum = 0
bar.maximum = 100
bar.progress = int(index.data())
bar.textVisible = True
bar.text = str(index.data()) + '%'
bar.textAlignment = QtCore.Qt.AlignCenter
QtWidgets.QApplication.style().drawControl(QtWidgets.QStyle.CE_ProgressBar, bar, painter)
def sizeHint(self, option, index):
if index.column() == 0:
return QtCore.QSize(100, 30)
if index.column() == 2:
return QtCore.QSize(200, 30)
if index.column() == 3:
document = QtGui.QTextDocument(index.data())
document.setDefaultFont(option.font)
return QtCore.QSize(document.idealWidth() + 50, 15 * (document.lineCount() + 1))
return super(TableDelegate, self).sizeHint(option, index)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None):
super(TableModel, self).__init__(parent)
self.items = []
def headerData(self, col, orientation, role):
HEADER = ['名前', 'チェック', '進行状況', 'せつめい']
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return HEADER[col]
if orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole:
return str(col + 1).zfill(3)
def addItem(self, item):
self.items.append(item)
self.layoutChanged.emit()
def rowCount(self, parent=QtCore.QModelIndex()):
u"""行数を返す"""
return len(self.items)
def columnCount(self, parent):
u"""カラム数を返す"""
return 4
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return None
if role == QtCore.Qt.DisplayRole:
return self.items[index.row()].data(index.column())
if role == QtCore.Qt.UserRole:
return self.items[index.row()]
def setData(self, index, value, role=QtCore.Qt.EditRole):
if role == QtCore.Qt.EditRole:
index.data(QtCore.Qt.UserRole).setData(index.column(), value)
self.headerDataChanged.emit(QtCore.Qt.Vertical, index.row(), index.row())
self.dataChanged.emit(index, index)
def flags(self, index):
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
def upData(self, index):
"""
引数のIndexを1つ上に移動する
"""
row = index.row()
if row > 0:
buff = self.items.pop(row)
self.items.insert(row - 1, buff)
self.layoutChanged.emit()
def downData(self, index):
"""
引数のIndexを一つ下に移動する
"""
row = index.row()
if row < len(self.items):
buff = self.items.pop(row)
self.items.insert(row + 1, buff)
self.layoutChanged.emit()
class UISample(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(UISample, self).__init__(parent)
self.ui = QUiLoader().load(os.path.join(CURRENT_PATH, 'tableView.ui'))
self.resize(600, 400)
self.model = TableModel()
dataA = DataItem('A', False, 0, "")
dataB = DataItem('B', False, 0, "")
dataC = DataItem('C', False, 0, "")
self.model.addItem(dataA)
self.model.addItem(dataB)
self.model.addItem(dataC)
self.ui.tableView.setModel(self.model)
self.ui.tableView.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
self.ui.tableView.verticalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
self.delegate = TableDelegate()
self.ui.tableView.setItemDelegate(self.delegate)
self.setCentralWidget(self.ui)
self.ui.upBtn.clicked.connect(self.upBtnClicked)
self.ui.downBtn.clicked.connect(self.downBtnClicked)
def upBtnClicked(self):
index = self.ui.tableView.currentIndex()
self.model.upData(index)
chIndex = self.model.index(index.row() - 1, index.column())
if chIndex.isValid():
self.ui.tableView.setCurrentIndex(chIndex)
def downBtnClicked(self):
index = self.ui.tableView.currentIndex()
self.model.downData(index)
chIndex = self.model.index(index.row() + 1, index.column())
if chIndex.isValid():
self.ui.tableView.setCurrentIndex(chIndex)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
a = UISample()
a.show()
sys.exit(app.exec_())