如何将自定义小部件与事件/信号一起用作QStyledItemDelegates?

时间:2012-06-25 03:58:16

标签: qt pyqt pyqt4 pyside

我试图使QStyledItemDelegate的行为类似于我编写的自定义QWidget,因此我可以将代码切换为模型/视图方法。

自定义QWidget是一个复杂的按钮,它在鼠标悬停的角落显示四个“子按钮”(所以总共有五个信号)。它还可以使用自定义拖动像素图进行拖放操作。为此,我使用了mousePressEvent,mouseReleaseEvent,mouseMoveEvent,enterEvent和leaveEvent。这是鼠标悬停时显示的“子按钮”的样子: enter image description here

我已经将我的主代码切换为使用模型/视图方法,并尝试将此小部件用作我的自定义ListView的QStyledItemDelegate。 我已经尝试将自定义Widget指定为这样的编辑器:

class ToolButtonDelegate( QStyledItemDelegate ):

    def __init__( self, parent=None ):
        super( ToolButtonDelegate, self).__init__( parent )
        self.parent = parent

    def createEditor( self, parent, option, index ):
        if not index.isValid():
            return False
        btn = FancyButton( index.data( Qt.UserRole ), parent=parent )
        return btn

这看起来很有希望,因为它为我点击的项目绘制了“FancyButton”类。但是,我需要这是一个鼠标悬停事件。 经过一番研究后,我尝试将QAbstractItemView.entered插槽连接到QAbstractItemView.edit信号:

self.entered.connect( self.edit )

这仅适用于我将鼠标指针移过的第一项,然后我收到这些错误:

edit: editing failed

所以现在我又遇到了这些问题:

  • 如何正确关闭编辑器(没有“QAbstractItemView.leave”事件或类似事件)。
  • 如何确保鼠标点击实际触发FanyButton类中的按钮而不是仅仅与QAbstractIremView进行交互

我有一种感觉,我正朝着错误的方向前进。

2 个答案:

答案 0 :(得分:1)

我敦促你回到代表而不是小部件,纯粹出于性能原因=)

您可以使用状态,特别是QStyle :: State_MouseOver,使用委托鼠标覆盖paint方法中的事件。对于按钮上的点击,您可以覆盖接收所有鼠标事件的editorEvent,然后处理发生鼠标点击的区域。例如:

void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (option.state & QStyle::State_MouseOver)
    {
        // draw stuff which appears on mouse over
    } else {
        // draw stuff that appears when mouse is not over control
    }
 }

bool editorEvent(QEvent *event, QAbstractItemModel*, const QStyleOptionViewItem &option, const QModelIndex &index)
{
        // Emit a signal when the icon is clicked
        if(event->type() == QEvent::MouseButtonRelease)
        {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
            QRect editButtonRect = editIcon.rect().translated(editIconPos(option));
            QRect deleteButtonRect = deleteIcon.rect().translated(deleteIconPos(option));

            if(editButtonRect.contains(mouseEvent->pos()))
            {
                emit editIndexClicked(index);
            } else if (deleteButtonRect.contains(mouseEvent->pos())) {
                emit deleteIndexClicked(index);
            }
        }
        return false;
    }

此外,您可以查看此主题HowTo create delegate for QTreeWidget?,这适用于QTreeWidget,但我认为同样的方法也适用于您的情况。

答案 1 :(得分:0)

AFAIK,您不能使用自定义小部件来查看List / Table / Tree-View-delegates中的项目。您可以使用它们进行编辑,但如果视图模式除了重绘之外还需要其他任何内容,那么您会非常难过。

我们通过拥有自己的容器小部件来解决这个问题,这些小部件可以监听模型事件并动态添加/删除项目小部件。真的很遗憾,因为它感觉很基本。

原因可能是视图应该很快且能够显示很多项目,并且拥有大量小部件并不快,所以他们选择只允许自定义重绘功能(允许他们使用justone容器小部件,在不同区域使用自定义绘画。)

也许有办法绕过它,如果有的话,我会很高兴听到它。

<强>更新

如果您需要捕获事件,也许您可​​以在容器视图中安装事件过滤器,然后使用QListView::indexAt找到要将事件发送到的正确项目/窗口小部件/委托?

然后您可以在mouseenter / leave上使用openPersistentEditor和closePersistentEditor来启用编辑,即显示/关闭项目上的自定义小部件。