2011-08-24 47 views
12

这是我正在做的事情(所有的父母和孩子必须有一个关闭按钮在未来,只有悬停的项目将能够显示**关闭**按钮):如何为QTreeWidget创建委托?

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演示示例,以及有关QItemDelegate和类似内容的第一个Google结果。

+0

在VS2008调试器构造函数执行,但'createEditor()'方法都没有。首先,Thrx, – mosg

回答

17

您可以使用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) 
}; 
+0

伟大的全面,qt-idiomatic和准确的代码! –

+0

alexisdm,thnx。明天将测试你的代码! – mosg

+0

alexisdm,我必须说,你的代码很棒!这对我来说是非常完美的解决方案! – mosg

1

首先,我应该问你是否真的在使用QTreeWidget,或者说是QTreeView?根据QTreeView的文档,您不能使用QTreeWidget的自定义委托,并且必须使用QTree * View *和某种形式的QAbstractItemModel才能使用自定义委托。

啊,划伤了。我看到你正在调用setItemDelegateForColumn,它是一个QTreeView函数,但你应该知道它的区别,所以我保留上面的段落。 :)

我会检查您的模型的flags()函数返回Qt :: ItemIsEditable作为其项目标志的一部分。只要编辑事件由视图报告,就会调用createEditor()方法。 (触发编辑的视图事件取决于模型的EditTriggers)通常,双击委托会默认触发编辑,等等。

虽然我怀疑你只想在关闭按钮上双击出现。为了让按钮始终显示,您必须重新实现委托的paint()函数以绘制按钮等等。我发现Qt的StarDelegate example在这方面相当有帮助,我怀疑你会发现它也很有用。

+0

!回答你的问题 - 是的,我正在使用'QTreeWidget'!但是,也许你的主题是正确的,自定义委托不能与'QTreeWidget'一起使用,但是例子呢?我的意思是在* StarDelegate示例中*'QTableWidget'成功用于自定义委托?!这怎么可能? – mosg

+0

关于从'QTreeWidget'到'QTreeView'的迁移:在我的情况下,MVC不是正确的方式,因为我使用这个小部件,我的意思是'QTreeWidget',只保留4-5行, 2位父母,那就是所有的,这就是所谓的收件人列表,而不是地址簿... – mosg

+0

我想这方面的文档是不准确的。 (关于在基于项目的视图中使用自定义委托是不可能的。)QTreeWidget和freinds基于QTreeView类(仅提供使用QTreeItems的简化界面),所以它似乎可以设置自定义委托等。 无论如何,你仍然可能需要看看委托的paint()函数。如果您在第二列的每个项目上都执行了setFlags(flags()| = Qt :: ItemIsEditable),则现有代码可能会双击显示该工具按钮。 –

0

您可以使用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)