QTableView 和 QStyledItemDelegate 类的使用 (PyQt5)
Posted
技术标签:
【中文标题】QTableView 和 QStyledItemDelegate 类的使用 (PyQt5)【英文标题】:Usage of QTableView and QStyledItemDelegate classes (PyQt5) 【发布时间】:2021-12-26 15:44:08 【问题描述】:我从这里 (https://***.com/a/44365155/12875212) 找到了一个 PyQt5 代码,其中包括两个类 CustomTableView(QtWidgets.QTableView)
和 CustomDelegate(QtWidgets.QStyledItemDelegate)
。
如何将它们用于 QMainWindow 中的 QTableView 与我的数据?
代码:
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableView
import sys
class CustomTableView(QtWidgets.QTableView):
link_activated = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
self.parent = parent
super().__init__(parent)
self.setMouseTracking(True)
self._mousePressAnchor = ''
self._lastHoveredAnchor = ''
def mousePressEvent(self, event):
anchor = self.anchorAt(event.pos())
self._mousePressAnchor = anchor
def mouseMoveEvent(self, event):
anchor = self.anchorAt(event.pos())
if self._mousePressAnchor != anchor:
self._mousePressAnchor = ''
if self._lastHoveredAnchor != anchor:
self._lastHoveredAnchor = anchor
if self._lastHoveredAnchor:
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
else:
QtWidgets.QApplication.restoreOverrideCursor()
def mouseReleaseEvent(self, event):
if self._mousePressAnchor:
anchor = self.anchorAt(event.pos())
if anchor == self._mousePressAnchor:
self.link_activated.emit(anchor)
self._mousePressAnchor = ''
def anchorAt(self, pos):
index = self.indexAt(pos)
if index.isValid():
delegate = self.itemDelegate(index)
if delegate:
itemRect = self.visualRect(index)
relativeClickPosition = pos - itemRect.topLeft()
html = self.model().data(index, QtCore.Qt.ItemDataRole.DisplayRole)
return delegate.anchorAt(html, relativeClickPosition)
return ''
class CustomDelegate(QtWidgets.QStyledItemDelegate):
def anchorAt(self, html, point):
doc = QtGui.QTextDocument()
doc.setHtml(html)
textLayout = doc.documentLayout()
return textLayout.anchorAt(point)
def paint(self, painter, option, index):
options = QtWidgets.QStyleOptionViewItem(option)
self.initStyleOption(options, index)
if options.widget:
style = options.widget.style()
else:
style = QtWidgets.QApplication.style()
doc = QtGui.QTextDocument()
doc.setHtml(options.text)
options.text = ''
style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, options, painter)
ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
textRect = style.subElementRect(QtWidgets.QStyle.SE_ItemViewItemText, options)
painter.save()
painter.translate(textRect.topLeft())
painter.setClipRect(textRect.translated(-textRect.topLeft()))
painter.translate(0, 0.5 * (options.rect.height() - doc.size().height()))
doc.documentLayout().draw(painter, ctx)
painter.restore()
def sizeHint(self, option, index):
options = QtWidgets.QStyleOptionViewItem(option)
self.initStyleOption(options, index)
doc = QtGui.QTextDocument()
doc.setHtml(options.text)
doc.setTextWidth(options.rect.width())
return QtCore.QSize(doc.idealWidth(), doc.size().height())
数据和 QMainWindow:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.table = CustomTableView
data = [
['<p style="color: #ffffff; background-color: #ff0000">test</p>', 9, 2],
[1, '<b>Hello</b>', -1],
[3, '<a href="https://***.com/">***</a>', 2],
['<a href="https://www.google.com/">Google</a>', 3, 2],
[5, 8, 9],
]
#self.table.setItemDelegate(CustomDelegate()) # not working
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
【问题讨论】:
错字:更改为self.table = CustomTableView()
。要基于基本 python 数据对象设置模型,请参阅***.com/questions/63012839/…
【参考方案1】:
谢谢musicamante,正如我建议的那样,我通过添加一个QAbstractTableModel 解决了这个问题:
class PandasModel(QAbstractTableModel):
def __init__(self, data):
super().__init__()
self._data = data
def rowCount(self, index):
# The length of the outer list.
return len(self._data)
def columnCount(self, index):
# The following takes the first sub-list, and returns
# the length (only works if all rows are an equal length)
return len(self._data[0])
def data(self, index, role=QtCore.Qt.ItemDataRole.DisplayRole):
if index.isValid():
if role == QtCore.Qt.ItemDataRole.DisplayRole or role == QtCore.Qt.ItemDataRole.EditRole:
value = self._data[index.row()][index.column()]
return str(value)
# return str(value)
def setData(self, index, value, role):
if role == QtCore.Qt.ItemDataRole.EditRole:
self._data[index.row()][index.column()] = value
return True
return False
def flags(self, index):
return QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsEditable
并通过以下方式调用它:
self.model = PandasModel(data)
self.table.setModel(self.model)
self.table.setItemDelegate(CustomDelegate())
self.setCentralWidget(self.table)
【讨论】:
以上是关于QTableView 和 QStyledItemDelegate 类的使用 (PyQt5)的主要内容,如果未能解决你的问题,请参考以下文章
QTreeView 和 QTableView 的 Qt 模型