2011-08-24 75 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)