How to make a fast QTableView with HTML-formatted and clickable cells?

后端 未结 4 1107

I\'m making a dictionary program that displays word definitions in a 3-column QTableView subclass, as user types them, taking data from a QAbstractTableModel<

4条回答
  •  北海茫月
    2021-01-31 01:06

    Many thanks for these code examples, it helped me implement similar functionalaity in my application. I'm working with Python 3 and QT5 and I would like to share my Python code, is case it may be helpful implementing this in Python.

    Note that if you are using QT Designer for the UI design, you can use "promote" to change a regular "QTableView" widget to use your custom widget automatically when converting the XML to Python code with "pyuic5".

    Code as follows:

    from PyQt5 import QtCore, QtWidgets, QtGui
    
    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.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())
    

提交回复
热议问题