Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use custom widget with events/signals as QStyledItemDelegates?

I am trying to make a QStyledItemDelegate behave like a custom QWidget I wrote, so I can switch my code to a model/view approach.

The custom QWidget is a complex button which shows four "sub buttons" in it's corners on mouse over (so all in all there are five signals). It's also drag&droppable with a custom drag pixmap. To achieve this I am using mousePressEvent, mouseReleaseEvent, mouseMoveEvent, enterEvent and leaveEvent. This is what it looks like with and without the "sub buttons" shown on mouse over: enter image description here

I have since switched my main code to use a model/view approach and am trying to use this widget as a QStyledItemDelegate for my customised ListView. I have tried assigning the custom Widget as an editor like this:

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

This seems promising as it draws the "FancyButton" class for the item I click on. However, I need this to be a mouse over event. After a bit more research I tried connecting the QAbstractItemView.entered slot to QAbstractItemView.edit signal:

self.entered.connect( self.edit )

This works only for the first item I move my mouse pointer over, then I get these errors:

edit: editing failed

So now I'm stuck again with these problems:

  • how to properly close the editor (there is no "QAbstractItemView.leave" event or similar).
  • how to ensure that the mouse clicks actually trigger the buttons in the FanyButton class rather than just interact with the QAbstractIremView

I have a feeling I'm heading into the wrong direction here.

like image 928
Frank Rueter Avatar asked Oct 20 '25 02:10

Frank Rueter


1 Answers

I'd urge you to go back to delegates instead of widgets, purely for performance reasons =)

You can work with delegates mouse over events in paint method using states, particularly QStyle::State_MouseOver. As for clicks on buttons you can override editorEvent which receives all mouse events and then work with regions of where mouse clicks occurred. For example:

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;
    }

Also you can check out this topic HowTo create delegate for QTreeWidget?, this is for QTreeWidget, but I think same methods would apply to your case too.

like image 195
BitFrozen Avatar answered Oct 22 '25 05:10

BitFrozen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!