2010-07-29 12 views
14

Używamy QTableView z Qt 4.6.3, i potrzebujemy kolumny, która ma tylko pole wyboru w każdej komórce. Używamy niestandardowej podklasy QAbstractTableModel jako modelu dla QTableView. Teraz mamy pole wyboru, ustawiając flagę Qt::ItemIsUserCheckable. Ale nie możemy wymyślić, jak pozbyć się pustego pola tekstowego obok pola wyboru!Qt QTableView, aby mieć tylko pole wyboru tylko kolumna

W jaki sposób możemy uczynić kolumnę tylko mieć pole wyboru, nic więcej?

Odpowiedz

15

Oto rozwiązanie. Aby to działało poprawnie, Twoja kolumna powinna mieć , a nie mieć ustawione flagi Qt::ItemIsEditable lub Qt::ItemIsUserCheckable. Ten odczytuje wartości logicznych z Qt::DisplayRole i wzywa setData() z 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

Mieli ten sam problem pod numerem qtcentre. Tam doszli do rozwiązania z delegatami, może powinieneś na to spojrzeć.

+0

Wygląda bardziej na komentarz niż na odpowiedź? – neuronet

8

Note (tj nieQt::CheckStateRole.): Odpowiedź Dave działa również dla Pythona z wykorzystaniem PySide lub PyQt4. Przetłumaczyłem to i działa świetnie. Dodatkowo dodałem funkcję, której pole wyboru nie akceptuje danych wprowadzonych przez użytkownika i jest wyświetlane w stanie ReadOnly, jeśli komórka nie jest edytowalna. Dzięki Dave za Twój kod!

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 i @Niklas, dziękuję za tę transliterację, ale nie mogę uruchomić kodu. Wysłałem następującą odpowiedź [tutaj.] (Http://stackoverflow.com/questions/17748546/pyqt-column-of-checkboxes-in-a-qtableview) z przykładem mojej implementacji. – drexiya

+0

@Dave Mateer Naprawdę imponujące .... Jestem nieco zdezorientowany przez 'if not (index.flags() & Qt.ItemIsEditable)> 0:'. Po co sprawdzać istnienie flag na indeksie? – neuronet

Powiązane problemy