2011-08-24 9 views
12

Oto, co próbuję zrobić (wszyscy rodzice i dzieci muszą mieć przycisk zamknij po prawej stronie, w przyszłości tylko ukryta pozycja będzie mogła wyświetlić przycisk ** zamknij **):Jak utworzyć delegata dla QTreeWidget?

enter image description here

Mój kod delegat:

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

Z QTreeWidget kodu gra:

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

gdzie recipientsView() to prosty QTreeWidget.

Problem polega na tym, że s nie są w ogóle pokazywane (muszą znajdować się w drugiej kolumnie, tzn. Indeks kolumny w drzewie to 1). Co robię źle?

Sprawdziłem już wszystkie przykłady demonstracyjne Qt dotyczące delegatów i pierwszego wyniku Google o numerach QItemDelegate i podobnych.

+0

W VS2008 konstruktor debugger wykonuje, ale 'createEditor()' metody nie są. – mosg

Odpowiedz

17

Możesz użyć funkcji QStyledDelegate::paint, aby narysować ikonę zamykania, bez używania żadnego widżetu, i editorEvent, aby odbierać zdarzenia myszy dla przedmiotu, nawet jeśli nie używasz edytora lub nie można edytować elementu.

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

Świetny kompleksowy, qt-idiomatyczny i dokładny kod! –

+0

alexisdm, thnx. Jutro przetestuje twój kod! – mosg

+0

alexisdm, muszę powiedzieć, że twój kod działa świetnie! To naprawdę idealne rozwiązanie dla mnie! – mosg

1

Po pierwsze, powinienem zapytać, czy naprawdę używasz QTreeWidget, czy raczej QTreeView? Nie możesz używać niestandardowych delegatów z QTreeWidget zgodnie z dokumentacją dla QTreeView i będziesz musiał użyć QTree * View * i pewnej formy QAbstractItemModel, aby móc używać niestandardowego delegata.

Ah, zdrap to. Widzę, że wywołujesz setItemDelegateForColumn, która jest funkcją QTreeView, ale powinieneś być świadomy różnicy, więc trzymam powyższy akapit. :)

Sprawdziłbym, czy funkcja Twojego modelu flags() powraca Qt :: ItemIsEditable jako część jego flag elementu. Metoda createEditor() jest wywoływana za każdym razem, gdy w widoku jest zgłaszane zdarzenie edycji. (Zdarzenia widoku, które będą wyzwalać zmianę, zależą od opcji EditTriggers). Zazwyczaj dwukrotne kliknięcie delegata powoduje między innymi domyślną zmianę.

Wątpię, aby przycisk zamykania pojawił się tylko po dwukrotnym kliknięciu. Aby przycisk pojawiał się cały czas, musisz ponownie wdrożyć funkcję paint() dla delegata, aby narysować przycisk, między innymi. Zauważyłem, że Qt's StarDelegate example jest bardzo pomocny w tym względzie, i podejrzewam, że również okaże się przydatny.

+0

Thnx, po pierwsze! I odpowiadając na twoje pytanie - tak, używam 'QTreeWidget'! Ale może masz rację co do tematu, że niestandardowy delegat nie może być użyty z 'QTreeWidget', ale co z przykładem? Mam na myśli * w przykładzie StarDelegate * 'QTableWidget' z powodzeniem używanym z niestandardowym delegatem ?! Jak to może być? – mosg

+0

I o migracji z 'QTreeWidget' do' QTreeView': w moim przypadku MVC nie jest właściwą drogą, ponieważ używam tego widgetu, mam na myśli 'QTreeWidget', który ma tylko 4-5 wierszy, 1 2 rodziców i to wszystko, to tak zwana lista adresatów, a nie książka adresowa ... – mosg

+0

Przypuszczam, że dokumentacja jest niedokładna pod tym względem. (O niemożności używania niestandardowego elementu delegowanego z widokiem opartym na elementach). QTreeWidget i freinds są oparte na klasach QTreeView (oferując tylko uproszczony interfejs używania QTreeItems), więc wygląda na to, że można ustawić niestandardowych delegatów i takie . W każdym razie prawdopodobnie prawdopodobnie będziesz musiał rzucić okiem na funkcję paint() delegata. Jeśli zrobiłeś setFlags (flags() | = Qt :: ItemIsEditable) na każdym z elementów w drugiej kolumnie, twój istniejący kod prawdopodobnie wyświetliłby przycisk na podwójnym kliknięciu. –

0

Można użyć QItemDelegate z QTreeWidget ten sposób (przykład w PyQt, przepraszam):

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) 
Powiązane problemy