Qt QTableView how to have a checkbox only column

匿名 (未验证) 提交于 2019-12-03 01:52:01

问题:

We are using a QTableView with Qt 4.6.3, and need a column that only has a checkbox in each cell. We're using a custom subclass of QAbstractTableModel as the model for the QTableView. Right now, we have a checkbox by setting the Qt::ItemIsUserCheckable flag. But we can't figure out how to get rid of the blank textbox next to the checkbox!

How can we make the column only have a checkbox, nothing else?

回答1:

Here is a solution. For this to work properly, your column should not have the Qt::ItemIsEditable or Qt::ItemIsUserCheckable flags set. This reads the boolean values from Qt::DisplayRole and calls setData() with Qt::EditRole (i.e. not Qt::CheckStateRole.)

#include "check_box_delegate.h"  #include  #include   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(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(event)->key() != Qt::Key_Space &&         static_cast(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); } 


回答2:

Note: The answer of Dave works also for Python using PySide or PyQt4. I translated it, and it works great. Additionally, I added the functionality that the checkbox does not accept user input and is shown in a ReadOnly state if the cell is not editable. Thanks Dave for your 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()) 


回答3:

They had the same issue at qtcentre. There they came to a solution with delegates, maybe you should have a look at those.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!