Как создать делегат для QTreeWidget? - PullRequest
15 голосов
/ 24 августа 2011

Вот что я пытаюсь сделать (все родители и дети должны иметь кнопку закрыть справа, в будущем только ** находящийся в состоянии элемент сможет показать ** закрыть * * кнопка):

enter image description here

Мой код делегата:

class CloseButton : public QItemDelegate
{
     Q_OBJECT

public:
     CloseButton( QObject* parent = 0 )
          : QItemDelegate( parent )
     {};

     QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
     {
          if ( index.column() == 1 )
          {
               QToolButton* button = new QToolButton( parent );
               button->setIcon( QIcon( CLOSE_ICON ) );
               //button->setFixedSize( 16, 16 );
               //button->setAutoRaise( true );
               //button->setVisible( true );

               CONNECT( button, SIGNAL( clicked() ), this, SLOT( emitCommitData() ) );

               return button;
          }
          return ( new QWidget );
     }

private slots:
     void emitCommitData()
     {
          emit commitData( qobject_cast< QWidget* >( sender() ) );
     }

private:
     //Q_DISABLE_COPY( CloseButton );
};

С QTreeWidget код подключения:

recipientsView()->setItemDelegateForColumn( 1, new CloseButton( this ) );

, где recipientsView() - это простое QTreeWidget.

Проблема в том, что QToolButton не отображаются вообще (он должен быть во втором столбце, то есть индекс столбца в дереве равен 1). Что я делаю не так?

Я уже проверил все демонстрационные примеры Qt о делегатах и ​​первый результат Google о QItemDelegate и подобных вещах.

Ответы [ 3 ]

19 голосов
/ 24 августа 2011

Вы можете использовать функцию QStyledDelegate::paint, чтобы нарисовать значок закрытия, без использования какого-либо виджета, и editorEvent, чтобы получать события мыши для элемента, даже если вы не используете редактор или не редактируете элемент.

class CloseButton : public QStyledItemDelegate {
    Q_OBJECT
public:

    explicit CloseButton(QObject *parent = 0, 
                         const QPixmap &closeIcon = QPixmap())
        : QStyledItemDelegate(parent)
        , m_closeIcon(closeIcon)
    {
        if(m_closeIcon.isNull())
        {
            m_closeIcon = qApp->style()
                ->standardPixmap(QStyle::SP_DialogCloseButton);
        }
    }

    QPoint closeIconPos(const QStyleOptionViewItem &option) const {
        return QPoint(option.rect.right() - m_closeIcon.width() - margin,
                      option.rect.center().y() - m_closeIcon.height()/2);
    }

    void paint(QPainter *painter, const QStyleOptionViewItem &option,
               const QModelIndex &index) const {
        QStyledItemDelegate::paint(painter, option, index);
        // Only display the close icon for top level items...
        if(!index.parent().isValid()
                // ...and when the mouse is hovering the item
                // (mouseTracking must be enabled on the view)
                && (option.state & QStyle::State_MouseOver))
        {
            painter->drawPixmap(closeIconPos(option), m_closeIcon);
        }
    }

    QSize sizeHint(const QStyleOptionViewItem &option,
                   const QModelIndex &index) const
    {
        QSize size = QStyledItemDelegate::sizeHint(option, index);

        // Make some room for the close icon
        if(!index.parent().isValid()) {
            size.rwidth() += m_closeIcon.width() + margin * 2;
            size.setHeight(qMax(size.height(),
                                m_closeIcon.height() + margin * 2));
        }
        return size;
    }

    bool editorEvent(QEvent *event, QAbstractItemModel *model,
                     const QStyleOptionViewItem &option,
                     const QModelIndex &index)
    {
        // Emit a signal when the icon is clicked
        if(!index.parent().isValid() &&
                event->type() == QEvent::MouseButtonRelease) {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);

            QRect closeButtonRect = m_closeIcon.rect()
                    .translated(closeIconPos(option));

            if(closeButtonRect.contains(mouseEvent->pos()))
            {
                emit closeIndexClicked(index);
            }
        }
        return false;
    }

signals:
    void closeIndexClicked(const QModelIndex &);
private:
    QPixmap m_closeIcon;
    static const int margin = 2; // pixels to keep arount the icon

    Q_DISABLE_COPY(CloseButton)
};
1 голос
/ 24 августа 2011

Во-первых, я должен спросить, действительно ли вы используете QTreeWidget или, скорее, QTreeView? Вы не можете использовать пользовательские делегаты с QTreeWidget в соответствии с документацией для QTreeView, и вам придется использовать QTree * View * и некоторую форму QAbstractItemModel, чтобы вы могли использовать пользовательский делегат.

Ах, поцарапайте это. Я вижу, что вы вызываете setItemDelegateForColumn, который является функцией QTreeView, но вы должны знать о разнице, поэтому я сохраняю вышеприведенный абзац. :)

Я бы проверил, что функция flags () вашей модели возвращает Qt :: ItemIsEditable как часть своих флагов элементов. Метод createEditor () вызывается всякий раз, когда представление сообщает о событии редактирования. (События просмотра, которые будут инициировать редактирование, зависят от EditTriggers модели). Как правило, двойной щелчок на делегате вызывает редактирование по умолчанию, среди прочего.

Я сомневаюсь, что вы хотите, чтобы кнопка закрытия появлялась только при двойном щелчке. Чтобы кнопка отображалась постоянно, вам придется переопределить функцию paint () делегата, чтобы нарисовать кнопку, среди прочего. Мне показалось, что StarDelegate пример Qt весьма полезен в этом отношении, и я подозреваю, что он вам тоже пригодится.

0 голосов
/ 06 сентября 2011

Вы можете использовать QItemDelegate с QTreeWidget следующим образом (пример в PyQt, извините):

myTreeWidget = QtGui.QTreeWidget()
myTreeWidget.setItemDelegate(myDelegate())

class myDelegate(QtGui.QItemDelegate):
    def paint(self, painter, option, index):

        #Custom Draw Column 1
        if index.column() == 1:
            icon = QtGui.QIcon(index.data(QtCore.Qt.DecorationRole))
            if icon:
                icon.paint(painter, option.rect)
                #You'll probably want to pass a different QRect

        #Use the standard routine for other columns
        else:
            super(myDelegate, self).paint(painter, option, index)
...