2010-07-29 15 views
14

Wir verwenden eine QTableView mit Qt 4.6.3, und benötigen eine Spalte, die nur ein Kontrollkästchen in jeder Zelle hat. Wir verwenden eine benutzerdefinierte Unterklasse von QAbstractTableModel als Modell für die QTableView. Im Moment haben wir ein Kontrollkästchen, indem Sie das Flag Qt::ItemIsUserCheckable setzen. Aber wir können nicht herausfinden, wie wir die leere Textbox neben der Checkbox loswerden können!Qt QTableView, wie eine Checkbox nur Spalte

Wie können wir die Spalte nur haben ein Kontrollkästchen, sonst nichts?

Antwort

15

Hier ist eine Lösung. Damit dies ordnungsgemäß funktioniert, sollte Ihre Spalte nicht die Qt::ItemIsEditable oder Qt::ItemIsUserCheckable Flags gesetzt haben. Dieser liest die Boolesche Werte von Qt::DisplayRole und ruft setData() mit Qt::EditRole

#include "check_box_delegate.h" 

#include <QtGui/QApplication> 
#include <QtGui/QMouseEvent> 

static QRect CheckBoxRect(const QStyleOptionViewItem &view_item_style_options) { 
    QStyleOptionButton check_box_style_option; 
    QRect check_box_rect = QApplication::style()->subElementRect(
     QStyle::SE_CheckBoxIndicator, 
     &check_box_style_option); 
    QPoint check_box_point(view_item_style_options.rect.x() + 
         view_item_style_options.rect.width()/2 - 
         check_box_rect.width()/2, 
         view_item_style_options.rect.y() + 
         view_item_style_options.rect.height()/2 - 
         check_box_rect.height()/2); 
    return QRect(check_box_point, check_box_rect.size()); 
} 

CheckBoxDelegate::CheckBoxDelegate(QObject *parent) 
    : QStyledItemDelegate(parent) { 
} 

void CheckBoxDelegate::paint(QPainter *painter, 
          const QStyleOptionViewItem &option, 
          const QModelIndex &index) const { 
    bool checked = index.model()->data(index, Qt::DisplayRole).toBool(); 

    QStyleOptionButton check_box_style_option; 
    check_box_style_option.state |= QStyle::State_Enabled; 
    if (checked) { 
    check_box_style_option.state |= QStyle::State_On; 
    } else { 
    check_box_style_option.state |= QStyle::State_Off; 
    } 
    check_box_style_option.rect = CheckBoxRect(option); 

    QApplication::style()->drawControl(QStyle::CE_CheckBox, 
            &check_box_style_option, 
            painter); 
} 

// This is essentially copied from QStyledItemEditor, except that we 
// have to determine our own "hot zone" for the mouse click. 
bool CheckBoxDelegate::editorEvent(QEvent *event, 
            QAbstractItemModel *model, 
            const QStyleOptionViewItem &option, 
            const QModelIndex &index) { 
    if ((event->type() == QEvent::MouseButtonRelease) || 
     (event->type() == QEvent::MouseButtonDblClick)) { 
    QMouseEvent *mouse_event = static_cast<QMouseEvent*>(event); 
    if (mouse_event->button() != Qt::LeftButton || 
     !CheckBoxRect(option).contains(mouse_event->pos())) { 
     return false; 
    } 
    if (event->type() == QEvent::MouseButtonDblClick) { 
     return true; 
    } 
    } else if (event->type() == QEvent::KeyPress) { 
    if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space && 
     static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select) { 
     return false; 
    } 
    } else { 
    return false; 
    } 

    bool checked = index.model()->data(index, Qt::DisplayRole).toBool(); 
    return model->setData(index, !checked, Qt::EditRole); 
} 
1

Sie hatten das gleiche Problem bei qtcentre. Da kamen sie zu einer Lösung mit Delegierten, vielleicht sollten Sie sich diese ansehen.

+0

Scheint eher wie ein Kommentar als eine Antwort? – neuronet

8

Hinweis (d nichtQt::CheckStateRole.): Die Antwort von Dave arbeitet auch für Python mit pyside oder PyQt4. Ich habe es übersetzt und es funktioniert großartig. Außerdem fügte ich die Funktionalität hinzu, dass das Kontrollkästchen keine Benutzereingabe akzeptiert, und wird in einem ReadOnly-Status angezeigt, wenn die Zelle nicht bearbeitet werden kann. Danke Dave für deinen Code!

class CheckBoxDelegate(QStyledItemDelegate): 

    def createEditor(self, parent, option, index): 
     ''' 
     Important, otherwise an editor is created if the user clicks in this cell. 
     ''' 
     return None 

    def paint(self, painter, option, index): 
     ''' 
     Paint a checkbox without the label. 
     ''' 
     checked = bool(index.model().data(index, Qt.DisplayRole)) 
     check_box_style_option = QStyleOptionButton() 

     if (index.flags() & Qt.ItemIsEditable) > 0: 
      check_box_style_option.state |= QStyle.State_Enabled 
     else: 
      check_box_style_option.state |= QStyle.State_ReadOnly 

     if checked: 
      check_box_style_option.state |= QStyle.State_On 
     else: 
      check_box_style_option.state |= QStyle.State_Off 

     check_box_style_option.rect = self.getCheckBoxRect(option) 
      if not index.model().hasFlag(index, Qt.ItemIsEditable): 
      check_box_style_option.state |= QStyle.State_ReadOnly 

     QApplication.style().drawControl(QStyle.CE_CheckBox, check_box_style_option, painter) 


    def editorEvent(self, event, model, option, index): 
     ''' 
     Change the data in the model and the state of the checkbox 
     if the user presses the left mousebutton or presses 
     Key_Space or Key_Select and this cell is editable. Otherwise do nothing. 
     ''' 
     if not (index.flags() & Qt.ItemIsEditable) > 0: 
      return False 

     # Do not change the checkbox-state 
     if event.type() == QEvent.MouseButtonRelease or event.type() == QEvent.MouseButtonDblClick: 
      if event.button() != Qt.LeftButton or not self.getCheckBoxRect(option).contains(event.pos()): 
       return False 
      if event.type() == QEvent.MouseButtonDblClick: 
       return True 
     elif event.type() == QEvent.KeyPress: 
      if event.key() != Qt.Key_Space and event.key() != Qt.Key_Select: 
       return False 
     else: 
      return False 

     # Change the checkbox-state 
     self.setModelData(None, model, index) 
     return True 

    def setModelData (self, editor, model, index): 
     ''' 
     The user wanted to change the old state in the opposite. 
     ''' 
     newValue = not bool(index.model().data(index, Qt.DisplayRole)) 
     model.setData(index, newValue, Qt.EditRole) 


    def getCheckBoxRect(self, option): 
     check_box_style_option = QStyleOptionButton() 
     check_box_rect = QApplication.style().subElementRect(QStyle.SE_CheckBoxIndicator, check_box_style_option, None) 
     check_box_point = QPoint (option.rect.x() + 
          option.rect.width()/2 - 
          check_box_rect.width()/2, 
          option.rect.y() + 
          option.rect.height()/2 - 
          check_box_rect.height()/2) 
     return QRect(check_box_point, check_box_rect.size()) 
+0

raorao und @ Niklas, danke für diese Transliteration, aber ich kann den Code nicht funktionieren. Ich habe ein Follow-up [hier.] (Http://stackoverflow.com/questions/17748546/pyqt-column-of-checkboxes-in-a-qtableview) mit einem Beispiel meiner Implementierung gepostet. – drexiya

+0

@Dave Mateer Wirklich beeindruckend .... Ich bin ein wenig verwirrt von 'wenn nicht (index.flags() & Qt.ItemIsEditable)> 0:'. Warum sollte man auf die Existenz von Flaggen im Index achten? – neuronet

Verwandte Themen