我正在嘗試使用 QStyledItemDelegate 構建自定義 TreeWidget 來繪制自定義復選框。一切正常,除非我調整 TreeWidget 列的大小。正如您將在下面看到的,當“年齡”列一直向左移動時,第一個子項的“名稱”復選框“顯示通過”(即使所有文本都被正確省略和隱藏)。
誰能建議為什么會這樣?
我嘗試為 QStyledItemDelegate 設定大小提示,但這沒有效果。這是一個最小的可重現示例:
import sys
from PyQt5 import QtCore, QtWidgets
class CustomTreeWidgetDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self, parent=None) -> None:
super().__init__(parent)
def paint(self, painter, option, index):
options = QtWidgets.QStyleOptionViewItem(option)
self.initStyleOption(options, index)
if options.widget:
style = option.widget.style()
else:
style = QtWidgets.QApplication.style()
# lets only draw checkboxes for col 0
if index.column() == 0:
item_options = QtWidgets.QStyleOptionButton()
item_options.initFrom(options.widget)
if options.checkState == QtCore.Qt.Checked:
item_options.state = (
QtWidgets.QStyle.State_On | QtWidgets.QStyle.State_Enabled
)
else:
item_options.state = (
QtWidgets.QStyle.State_Off | QtWidgets.QStyle.State_Enabled
)
item_options.rect = style.subElementRect(
QtWidgets.QStyle.SE_ViewItemCheckIndicator, options
)
QtWidgets.QApplication.style().drawControl(
QtWidgets.QStyle.CE_CheckBox, item_options, painter
)
if index.data(QtCore.Qt.DisplayRole):
rect = style.subElementRect(QtWidgets.QStyle.SE_ItemViewItemText, options)
painter.drawText(
rect,
QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter,
options.fontMetrics.elidedText(
options.text, QtCore.Qt.ElideRight, rect.width()
),
)
if __name__ == "__main__":
class MyTree(QtWidgets.QTreeWidget):
def __init__(self):
super().__init__()
self.setItemDelegate(CustomTreeWidgetDelegate())
header = self.header()
head = self.headerItem()
head.setText(0, "Name")
head.setText(1, "Age")
parent = QtWidgets.QTreeWidgetItem(self)
parent.setCheckState(0, QtCore.Qt.Unchecked)
parent.setText(0, "Jack Smith")
parent.setText(1, "30")
child = QtWidgets.QTreeWidgetItem(parent)
child.setCheckState(0, QtCore.Qt.Checked)
child.setText(0, "Jane Smith")
child.setText(1, "10")
self.expandAll()
# create pyqt5 app
App = QtWidgets.QApplication(sys.argv)
# create the instance of our Window
myTree = MyTree()
myTree.show()
# start the app
sys.exit(App.exec())
列調整大小之前的 Treewidget

列調整大小后的 Treewidget

uj5u.com熱心網友回復:
與小部件繪畫(總是被裁剪到小部件幾何圖形)不同,委托繪畫不限于專案邊界矩形。
從理論上講,這允許在專案矩形之外進行繪制,例如在專案周圍顯示“擴展”裝飾,但通常不鼓勵這樣做,因為不能保證繪制順序并且可能會導致一些圖形偽影。
解決方案是始終將畫家剪輯到選項 rect,這應該始終發生在已保存的畫家狀態中:
class CustomTreeWidgetDelegate(QtWidgets.QStyledItemDelegate):
def paint(self, painter, option, index):
painter.save()
painter.setClipRect(option.rect)
# ...
painter.restore()
注意:
- 這兩個
if options.ViewItemFeature檢查是無用的,因為它們是常量(并且它們大于 0,它們將始終是“真實的”); - 您應該始終繪制專案的“基礎”,以始終顯示其選定/懸停狀態;
- 當您宣告要繪制自定義復選框時,請注意您應該始終考慮專案的狀態(即,如果它被選中或禁用);
- 以上對于繪制專案文本也是有效的:最重要的是,所選專案具有不同的顏色,因為它必須與選擇背景有足夠的對比度,所以通常最好使用 QStyle
drawItemText();
考慮到上述情況,這是您的代表的修訂版:
class CustomTreeWidgetDelegate(QtWidgets.QStyledItemDelegate):
def paint(self, painter, option, index):
painter.save()
painter.setClipRect(option.rect)
option = QtWidgets.QStyleOptionViewItem(option)
self.initStyleOption(option, index)
widget = option.widget
if widget:
style = widget.style()
else:
style = QtWidgets.QApplication.style()
# draw item base, including hover/selected highlighting
style.drawPrimitive(
style.PE_PanelItemViewItem, option, painter, widget
)
if option.features & option.HasCheckIndicator:
item_option = QtWidgets.QStyleOptionButton()
if widget:
item_option.initFrom(widget)
item_option.rect = style.subElementRect(
QtWidgets.QStyle.SE_ViewItemCheckIndicator, option
)
item_option.state = option.state
# disable focus appearance
item_option.state &= ~QtWidgets.QStyle.State_HasFocus
if option.checkState == QtCore.Qt.Checked:
item_option.state |= QtWidgets.QStyle.State_On
else:
item_option.state |= QtWidgets.QStyle.State_Off
QtWidgets.QApplication.style().drawControl(
QtWidgets.QStyle.CE_CheckBox, item_option, painter
)
# "if index.data():" doesn't work if the value is a *numeric* zero
if option.text:
alignment = (
index.data(QtCore.Qt.TextAlignmentRole)
or QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter
)
rect = style.subElementRect(
QtWidgets.QStyle.SE_ItemViewItemText, option, widget
)
margin = style.pixelMetric(
style.PM_FocusFrameHMargin, None, widget) 1
rect.adjust(margin, 0, -margin, 0)
text = option.fontMetrics.elidedText(
option.text, QtCore.Qt.ElideRight, rect.width()
)
if option.state & style.State_Selected:
role = QtGui.QPalette.HighlightedText
else:
role = QtGui.QPalette.Text
style.drawItemText(painter, rect,
alignment, option.palette,
index.flags() & QtCore.Qt.ItemIsEnabled,
text, role
)
painter.restore()
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/518489.html
標籤:qtpyqt代表qtreewidgetqtreewidgetitem
