、drawDisplay
(あなたは、ほぼゼロからアイテムを再描画しなければならない、あなたは追加のクラスの導出が必要になりますQStyledItemDelegate
と)QProxyStyle
から:
- HTMLテキストが
QTextDocument
とQTextDocument.documentLayout().draw()
で描かれ、
- マウスが同じ項目が再描画されると
drawDisplay
が呼び出される、項目を入力したとき、我々は位置を保存し、我々はテキストを描画されました(したがって、保存された位置は常に
editorEvent
でその位置が使用され、ドキュメント内のマウスの相対位置が取得され、QAbstractTextDocumentLayout.anchorAt
のドキュメントのその位置でリンクが取得されます。
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class LinkItemDelegate(QItemDelegate):
linkActivated = Signal(str)
linkHovered = Signal(str) # to connect to a QStatusBar.showMessage slot
def __init__(self, parentView):
QItemDelegate.__init__(self, parentView)
assert isinstance(parentView, QAbstractItemView), \
"The first argument must be the view"
# We need that to receive mouse move events in editorEvent
parentView.setMouseTracking(True)
# Revert the mouse cursor when the mouse isn't over
# an item but still on the view widget
parentView.viewportEntered.connect(parentView.unsetCursor)
# documents[0] will contain the document for the last hovered item
# documents[1] will be used to draw ordinary (not hovered) items
self.documents = []
for i in range(2):
self.documents.append(QTextDocument(self))
self.documents[i].setDocumentMargin(0)
self.lastTextPos = QPoint(0,0)
def drawDisplay(self, painter, option, rect, text):
# Because the state tells only if the mouse is over the row
# we have to check if it is over the item too
mouseOver = option.state & QStyle.State_MouseOver \
and rect.contains(self.parent().viewport() \
.mapFromGlobal(QCursor.pos())) \
and option.state & QStyle.State_Enabled
if mouseOver:
# Use documents[0] and save the text position for editorEvent
doc = self.documents[0]
self.lastTextPos = rect.topLeft()
doc.setDefaultStyleSheet("")
else:
doc = self.documents[1]
# Links are decorated by default, so disable it
# when the mouse is not over the item
doc.setDefaultStyleSheet("a {text-decoration: none}")
doc.setDefaultFont(option.font)
doc.setHtml(text)
painter.save()
painter.translate(rect.topLeft())
ctx = QAbstractTextDocumentLayout.PaintContext()
ctx.palette = option.palette
doc.documentLayout().draw(painter, ctx)
painter.restore()
def editorEvent(self, event, model, option, index):
if event.type() not in [QEvent.MouseMove, QEvent.MouseButtonRelease] \
or not (option.state & QStyle.State_Enabled):
return False
# Get the link at the mouse position
# (the explicit QPointF conversion is only needed for PyQt)
pos = QPointF(event.pos() - self.lastTextPos)
anchor = self.documents[0].documentLayout().anchorAt(pos)
if anchor == "":
self.parent().unsetCursor()
else:
self.parent().setCursor(Qt.PointingHandCursor)
if event.type() == QEvent.MouseButtonRelease:
self.linkActivated.emit(anchor)
return True
else:
self.linkHovered.emit(anchor)
return False
def sizeHint(self, option, index):
# The original size is calculated from the string with the html tags
# so we need to subtract from it the difference between the width
# of the text with and without the html tags
size = QItemDelegate.sizeHint(self, option, index)
# Use a QTextDocument to strip the tags
doc = self.documents[1]
html = index.data() # must add .toString() for PyQt "API 1"
doc.setHtml(html)
plainText = doc.toPlainText()
fontMetrics = QFontMetrics(option.font)
diff = fontMetrics.width(html) - fontMetrics.width(plainText)
return size - QSize(diff, 0)
は、限り、あなたは(すべての項目についてのsizehintを呼ぶだろう)内容への自動列のサイズ変更を有効にしていないとして、デリゲートない場合よりも遅くなるとは思われません。
カスタムモデルを使用すると、モデル内の一部のデータを直接キャッシュする(たとえば、QTextDocumentの代わりに隠されていないアイテムにQStaticTextを使用して格納するなど)ことでスピードアップすることができます。
素晴らしいです、これを試してみましょう!ちなみに、私は実際にQStyledItemDelegateを使用していました。私は実際にモデル内にテキストを設定していません。モデルアイテムにはデータ変数があり、テキスト(プラスアイコン、カラーリング、グリッドラインなど)はすべてデータに基づいて描画されます。だから、私はすでに基本的に最初からアイテムを再描画しています。 QProxyStyleを使用するのは初めてですが、以前はこれまで使用したことがなく、PyQtでラップされているようにも見えません。 QProxyStyleが必要なのはなぜですか? –
@Brendan QStyledItemDelegateはQStyle関数を使用してアイテムを描画し、QProxyStyleは別のスタイルクラスの一部を再利用してQStyle派生クラスを書き込むことができます。 – alexisdm
ありがとう、私はこれを試して、それは素晴らしい作品! –