如何使用Qt委托进行自定义绘制?

1 投票
1 回答
3632 浏览
提问于 2025-04-16 10:21

我正在尝试改变 QTreeWidgetItems 在拖动时的显示方式。我重写了拖动事件,把我想要绘制的 QTreeWidgetItems 的 Qt.UserRole 数据设置为 1。在项目代理中,我读取这个 UserRole,然后进行相应的绘制。

我的自定义绘制效果正如我所期待的那样(也就是加粗的那条线);不过,我还没找到办法去抑制标准绘图工具在拖动时的绘制(也就是那个小矩形),而不影响其他的绘制(比如文本等)。

如果有任何想法,我会很感激。

alt text

示例:

def dragMoveEvent(self, event):
    pos = event.pos()
    item = self.myTreeWidget.itemAt(pos)

    # If hovered over an item during drag, set UserRole = 1
    if item:
        index = self.myTreeWidget.indexFromItem(item)
        self.myTreeWidget.model().setData(index, 1, Qt.UserRole)

    # reset UserRole to 0 for all other indices
    for i in range(self.myTreeWidget.model().rowCount()):
        _index = self.myTreeWidget.model().index(i, 0)
        if not item or index != _index:
            self.myTreeWidget.model().setData(_index, 0, Qt.UserRole)


class MyDelegate(QStyledItemDelegate):

    def paint( self, painter, option, index ):
        QStyledItemDelegate.paint(self, painter, option, index)
        painter.save()
        data = index.model().data( index, Qt.UserRole ).toInt()
            # if UserRole = 1 draw custom line
        if data[1] and data[0] == 1:
            line = QLine( option.rect.topLeft(), option.rect.topRight() )
            painter.drawLine( line )
        painter.restore()

1 个回答

2

这个问题可以通过使用C++的Qt轻松解决:你可以定义一个新的样式,重写drawPrimitive方法,然后在接收到QStyle::PE_IndicatorItemViewItemDrop常量时,进行自定义绘制(或者什么都不做)。下面是一个例子:

class TestStyle : public QProxyStyle
{
public:
    TestStyle(QStyle *baseStyle = 0) : QProxyStyle(baseStyle) {}

    void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
    {
        if (element == QStyle::PE_IndicatorItemViewItemDrop)
        {
            //?? do nothing or do custom painting here
        }
        else
        {
            QProxyStyle::drawPrimitive(element, option, painter, widget);
        }
    }
};

.. 

ui->treeView->setStyle(new TestStyle(ui->treeView->style()));

不过坏消息是,pyqt似乎对QProxyStyle一无所知;看起来它没有被封装,所以为了让这个工作,你需要自己封装样式类。

另一个解决方案是创建一个自定义的QTreeView子类,并重写它的paintEvent方法。默认的实现会调用drawTree和paintDropIndicator;其中paintDropIndicator负责处理拖放指示器,而drawTree则负责绘制树形项目。drawTree是受保护的,你可以在你的paintEvent中调用它:

class TestTreeView : public QTreeView
{
public:
    explicit TestTreeView(QWidget *parent = 0) : QTreeView(parent) {}

    void paintEvent(QPaintEvent * event)
    {
        QPainter painter(viewport());
        drawTree(&painter, event->region());
    }
};

这样应该可以抑制默认的拖放指示器。如果你在把它转换成Python时遇到问题,告诉我一声。

希望这能帮到你,祝好

撰写回答