Hi!

I want to make a table which contains in first column QComboBox and in last QCheckBox, but centered in a cell and without text.
I've followed few topics and everywhere the behaviour of such components is strange - sometimes QComboBox/QCheckBox is invisible - it appears only after DOUBLE clicking the cell where it should be, or it appears all the time, but still double click is needed.
Can it be done better? By better I mean showing control all over the time and let it react after single click?

And the other thing I am thinking about:
I want QComboBox to load data to the rest of its row cells. So checking option in QComboBox sets the values of the whole row, allowing user to change only one cell. Should I make it in TableView? This was my first idea, but now I am thinking about creating my own row that has nothing in common with QTableView and propagate it x times on my layout. One thing - the data will be finally exported to csv file. If I should stay with QComboBox can you tell me how to set other cells in a row after choosing QComboBox option? By signal - slot mechanism or in model's function?

Here is my current code, where the QCheckBox doesn't appear in the last column (never - even after double clicking a cell) and QComboBox shows up after double click.

datamodel.h

Qt Code:
  1. #ifndef DATAMODEL_H
  2. #define DATAMODEL_H
  3.  
  4. #include <QAbstractTableModel>
  5. #include <QStringList>
  6.  
  7. class DataModel : public QAbstractTableModel
  8. {
  9. Q_OBJECT
  10. public:
  11. explicit DataModel(QObject *parent = 0);
  12. int rowCount(const QModelIndex &parent = QModelIndex()) const ;
  13. int columnCount(const QModelIndex &parent = QModelIndex()) const;
  14. QVariant headerData(int section, Qt::Orientation orientation, int role) const;
  15. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
  16. bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
  17. Qt::ItemFlags flags(const QModelIndex & index) const ;
  18.  
  19. private:
  20. QStringList headers_;
  21. QString dataBase[8][7];
  22.  
  23. signals:
  24. void editCompleted(const QString &);
  25.  
  26. public slots:
  27.  
  28. };
  29.  
  30. #endif // DATAMODEL_H
To copy to clipboard, switch view to plain text mode 

datamodel.cpp
Qt Code:
  1. #include "datamodel.h"
  2. #include <QStringList>
  3.  
  4. DataModel::DataModel(QObject *parent) :
  5. {
  6. headers_ = QStringList();
  7. headers_ << "Nazwa, opis" << "Kod towaru" << "Ilość" << "JM" << "Cena netto" << "Wartość netto" << "Refaktura";
  8. }
  9.  
  10. int DataModel::rowCount(const QModelIndex & /*parent*/) const
  11. {
  12. return 8;
  13. }
  14.  
  15. int DataModel::columnCount(const QModelIndex & /*parent*/) const
  16. {
  17. return 7;
  18. }
  19.  
  20. QVariant DataModel::headerData(int section, Qt::Orientation orientation, int role) const
  21. {
  22. if (orientation == Qt::Horizontal) {
  23. if( role == Qt::DisplayRole) {
  24. return headers_.at(section);
  25. }
  26. } else {
  27. if( role == Qt::DisplayRole) {
  28. return section + 1;
  29. }
  30. }
  31. }
  32.  
  33. QVariant DataModel::data(const QModelIndex &index, int role) const
  34. {
  35. if (role == Qt::DisplayRole)
  36. {
  37. return dataBase[index.row()][index.column()];
  38. }
  39. return QVariant();
  40. }
  41.  
  42. bool DataModel::setData(const QModelIndex & index, const QVariant & value, int role)
  43. {
  44. if (role == Qt::EditRole)
  45. {
  46. //save value from editor to member m_gridData
  47. dataBase[index.row()][index.column()] = value.toString();
  48. //for presentation purposes only: build and emit a joined string
  49. QString result;
  50. for(int row= 0; row < 8; row++)
  51. {
  52. for(int col= 0; col < 7; col++)
  53. {
  54. result += dataBase[row][col] + " ";
  55. }
  56. }
  57. emit editCompleted( result );
  58. }
  59. return true;
  60. }
  61.  
  62. Qt::ItemFlags DataModel::flags(const QModelIndex &index) const
  63. {
  64. if (index.column() == 0 || index.column() == 2 || index.column() == 6)
  65. return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
  66. else
  67. return QAbstractTableModel::flags(index);
  68. }
To copy to clipboard, switch view to plain text mode 

comboboxdelegate.h (name is confusing - it should be rather mytabledelegate as it supports both QComboBox and QCheckBox)
Qt Code:
  1. #ifndef COMBOBOXDELEGATE_H
  2. #define COMBOBOXDELEGATE_H
  3.  
  4. #include <QStyledItemDelegate>
  5.  
  6. class ComboBoxDelegate : public QStyledItemDelegate
  7. {
  8. Q_OBJECT
  9. public:
  10. explicit ComboBoxDelegate(QObject *parent = 0);
  11.  
  12. virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
  13. void setEditorData(QWidget *editor, const QModelIndex &index) const;
  14. void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
  15. QRect CheckBoxRect(const QStyleOptionViewItem &view_item_style_options) const;
  16. void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
  17.  
  18. private:
  19.  
  20. signals:
  21.  
  22. public slots:
  23.  
  24. };
  25.  
  26. #endif // COMBOBOXDELEGATE_H
To copy to clipboard, switch view to plain text mode 

comboboxdelegate.cpp
Qt Code:
  1. #include "comboboxdelegate.h"
  2. #include <QComboBox>
  3. #include <QCheckBox>
  4. #include <QRect>
  5. #include <QApplication>
  6.  
  7. ComboBoxDelegate::ComboBoxDelegate(QObject *parent) :
  8. QStyledItemDelegate(parent)
  9. {
  10. }
  11.  
  12. QWidget* ComboBoxDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
  13. {
  14. // ComboBox ony in column 1
  15. if(index.column() == 0) {
  16.  
  17. // Create the combobox and populate it
  18. QComboBox *cb = new QComboBox(parent);
  19. cb->addItem(QString("Produkt 1"));
  20. cb->addItem(QString("Produkt 2"));
  21. cb->addItem(QString("Produkt 3"));
  22. return cb;
  23. } else if (index.column() == 6) {
  24. QCheckBox *cb = new QCheckBox(parent);
  25. return cb;
  26. } else
  27. return QStyledItemDelegate::createEditor(parent, option, index);
  28. }
  29.  
  30. void ComboBoxDelegate::setEditorData ( QWidget *editor, const QModelIndex &index ) const
  31. {
  32. if(QComboBox *cb = qobject_cast<QComboBox *>(editor)) {
  33. // get the index of the text in the combobox that matches the current value of the itenm
  34. QString currentText = index.data(Qt::EditRole).toString();
  35. int cbIndex = cb->findText(currentText);
  36. // if it is valid, adjust the combobox
  37. if(cbIndex >= 0)
  38. cb->setCurrentIndex(cbIndex);
  39. } if (QCheckBox *cb = qobject_cast<QCheckBox *>(editor)) {
  40. int val = index.data(Qt::DisplayRole).toInt();
  41. if (val == 1)
  42. cb->setCheckState(Qt::Checked);
  43. else
  44. cb->setCheckState(Qt::Unchecked);
  45. } else {
  46. QStyledItemDelegate::setEditorData(editor, index);
  47. }
  48. }
  49.  
  50. void ComboBoxDelegate::setModelData ( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
  51. {
  52. if(QComboBox *cb = qobject_cast<QComboBox *>(editor))
  53. // save the current text of the combo box as the current value of the item
  54. model->setData(index, cb->currentText(), Qt::EditRole);
  55. else if (QCheckBox *cb = qobject_cast<QCheckBox *>(editor)) {
  56. int value;
  57. if (cb->checkState())
  58. value = 1;
  59. else
  60. value = 0;
  61. model->setData(index, value);
  62. } else
  63. QStyledItemDelegate::setModelData(editor, model, index);
  64. }
  65.  
  66. QRect ComboBoxDelegate::CheckBoxRect(const QStyleOptionViewItem &view_item_style_options) const {
  67.  
  68. QStyleOptionButton check_box_style_option;
  69. QRect check_box_rect = QApplication::style()->subElementRect( QStyle::SE_CheckBoxIndicator, &check_box_style_option);
  70. QPoint check_box_point(view_item_style_options.rect.x() + view_item_style_options.rect.width() / 2 - check_box_rect.width() / 2,
  71. view_item_style_options.rect.y() + view_item_style_options.rect.height() / 2 -
  72. check_box_rect.height() / 2);
  73. return QRect(check_box_point, check_box_rect.size());
  74. }
  75.  
  76. void ComboBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
  77.  
  78. if (index.column() == 6) {
  79. int value = index.model()->data(index, Qt::DisplayRole).toInt();
  80.  
  81. QStyleOptionButton check_box_style_option;
  82. check_box_style_option.state |= QStyle::State_Enabled;
  83. if (value == 1) {
  84. check_box_style_option.state |= QStyle::State_On;
  85. } else {
  86. check_box_style_option.state |= QStyle::State_Off;
  87. }
  88. check_box_style_option.rect = ComboBoxDelegate::CheckBoxRect(option);
  89.  
  90. QApplication::style()->drawControl(QStyle::CE_CheckBox, &check_box_style_option, painter);
  91. } else
  92. QStyledItemDelegate::paint(painter, option, index);
  93. }
To copy to clipboard, switch view to plain text mode 

Looks like the problem with showing QCheckBox is that index is always invalid, so it never steps into the condition (index.column() == 6)