I have a problem with QTableView. I want to have a table with QComboBox and QCheckBox in every row. That is why I created special class for checkbox and delegate.
BooleanWidget
#ifndef BOOLEANWIDGET_H
#define BOOLEANWIDGET_H
#include <QWidget>
#include <QCheckBox>
class BooleanWidget
: public QWidget{
Q_OBJECT
public:
BooleanWidget
(QWidget * parent
= 0);
bool isChecked(){return checkBox->isChecked();}
void setChecked(bool value){checkBox->setChecked(value);}
};
#endif // BOOLEANWIDGET_H
#include "booleanwidget.h"
#include <QHBoxLayout>
BooleanWidget
::BooleanWidget(QWidget *parent
) :{
layout->addWidget(checkBox,0, Qt::AlignCenter);
}
#ifndef BOOLEANWIDGET_H
#define BOOLEANWIDGET_H
#include <QWidget>
#include <QCheckBox>
class BooleanWidget : public QWidget
{
Q_OBJECT
QCheckBox * checkBox;
public:
BooleanWidget(QWidget * parent = 0);
bool isChecked(){return checkBox->isChecked();}
void setChecked(bool value){checkBox->setChecked(value);}
};
#endif // BOOLEANWIDGET_H
#include "booleanwidget.h"
#include <QHBoxLayout>
BooleanWidget::BooleanWidget(QWidget *parent) :
QWidget(parent)
{
checkBox = new QCheckBox(this);
QHBoxLayout * layout = new QHBoxLayout(this);
layout->addWidget(checkBox,0, Qt::AlignCenter);
}
To copy to clipboard, switch view to plain text mode
ComboBoxDelegate
#ifndef COMBOBOXDELEGATE_H
#define COMBOBOXDELEGATE_H
#include <QStyledItemDelegate>
#include <QTableView>
class ComboBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
void updateEditorGeometry
(QWidget *editor,
private:
signals:
public slots:
};
#endif // COMBOBOXDELEGATE_H
#include "comboboxdelegate.h"
#include <QComboBox>
#include <QCheckBox>
#include <QRect>
#include <QApplication>
#include <QSignalMapper>
#include "booleanwidget.h"
QStyledItemDelegate(parent), tableView_(tableView)
{
}
{
// ComboBox ony in column 1
if(index.column() == 0) {
// Create the combobox and populate it
connect(cb, SIGNAL(currentIndexChanged(int)), signalMapper, SLOT(map()));
signalMapper->setMapping(cb, index.row());
connect(signalMapper, SIGNAL(mapped(int)),
tableView_->model(), SLOT(changed(const int)));
return cb;
} else if (index.column() == 6)
return new BooleanWidget(parent);
else
return QStyledItemDelegate::createEditor(parent, option, index);
}
{
if(QComboBox *cb
= qobject_cast<QComboBox
*>
(editor
)) { // get the index of the text in the combobox that matches the current value of the itenm
QString currentText
= index.
data(Qt
::EditRole).
toString();
int cbIndex = cb->findText(currentText);
// if it is valid, adjust the combobox
if(cbIndex >= 0)
cb->setCurrentIndex(cbIndex);
} if (BooleanWidget *cb = qobject_cast<BooleanWidget *>(editor)) {
cb->setChecked(index.data(Qt::DisplayRole).toInt() == 1);
} else {
QStyledItemDelegate::setEditorData(editor, index);
}
}
{
if(QComboBox *cb
= qobject_cast<QComboBox
*>
(editor
)) // save the current text of the combo box as the current value of the item
model->setData(index, cb->currentText(), Qt::EditRole);
else if (BooleanWidget *cb = qobject_cast<BooleanWidget *>(editor)) {
model->setData(index, cb->isChecked() ? 1 : 0);
} else
QStyledItemDelegate::setModelData(editor, model, index);
}
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());
}
void ComboBoxDelegate
::updateEditorGeometry(QWidget *editor,
editor->setGeometry(option.rect);
}
if (index.column() == 6) {
int value = index.model()->data(index, Qt::DisplayRole).toInt();
check_box_style_option.
state |
= QStyle::State_Enabled;
if (value == 1) {
check_box_style_option.
state |
= QStyle::State_On;
} else {
check_box_style_option.
state |
= QStyle::State_Off;
}
check_box_style_option.rect = ComboBoxDelegate::CheckBoxRect(option);
QApplication::style()->drawControl
(QStyle::CE_CheckBox,
&check_box_style_option, painter
);
} else
QStyledItemDelegate::paint(painter, option, index);
}
#ifndef COMBOBOXDELEGATE_H
#define COMBOBOXDELEGATE_H
#include <QStyledItemDelegate>
#include <QTableView>
class ComboBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit ComboBoxDelegate(QTableView *tableView, QObject *parent = 0);
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
QRect CheckBoxRect(const QStyleOptionViewItem &view_item_style_options) const;
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
private:
QTableView *tableView_;
signals:
public slots:
};
#endif // COMBOBOXDELEGATE_H
#include "comboboxdelegate.h"
#include <QComboBox>
#include <QCheckBox>
#include <QRect>
#include <QApplication>
#include <QSignalMapper>
#include "booleanwidget.h"
ComboBoxDelegate::ComboBoxDelegate(QTableView *tableView, QObject *parent) :
QStyledItemDelegate(parent), tableView_(tableView)
{
}
QWidget* ComboBoxDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
// ComboBox ony in column 1
if(index.column() == 0) {
QSignalMapper* signalMapper = new QSignalMapper(const_cast<ComboBoxDelegate*>(this));
// Create the combobox and populate it
QComboBox *cb = new QComboBox(parent);
cb->addItem(QString(""));
cb->addItem(QString("Produkt 1"));
cb->addItem(QString("Produkt 2"));
cb->addItem(QString("Produkt 3"));
connect(cb, SIGNAL(currentIndexChanged(int)), signalMapper, SLOT(map()));
signalMapper->setMapping(cb, index.row());
connect(signalMapper, SIGNAL(mapped(int)),
tableView_->model(), SLOT(changed(const int)));
return cb;
} else if (index.column() == 6)
return new BooleanWidget(parent);
else
return QStyledItemDelegate::createEditor(parent, option, index);
}
void ComboBoxDelegate::setEditorData ( QWidget *editor, const QModelIndex &index ) const
{
if(QComboBox *cb = qobject_cast<QComboBox *>(editor)) {
// get the index of the text in the combobox that matches the current value of the itenm
QString currentText = index.data(Qt::EditRole).toString();
int cbIndex = cb->findText(currentText);
// if it is valid, adjust the combobox
if(cbIndex >= 0)
cb->setCurrentIndex(cbIndex);
} if (BooleanWidget *cb = qobject_cast<BooleanWidget *>(editor)) {
cb->setChecked(index.data(Qt::DisplayRole).toInt() == 1);
} else {
QStyledItemDelegate::setEditorData(editor, index);
}
}
void ComboBoxDelegate::setModelData ( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
{
if(QComboBox *cb = qobject_cast<QComboBox *>(editor))
// save the current text of the combo box as the current value of the item
model->setData(index, cb->currentText(), Qt::EditRole);
else if (BooleanWidget *cb = qobject_cast<BooleanWidget *>(editor)) {
model->setData(index, cb->isChecked() ? 1 : 0);
} else
QStyledItemDelegate::setModelData(editor, model, index);
}
QRect ComboBoxDelegate::CheckBoxRect(const QStyleOptionViewItem &view_item_style_options) const {
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());
}
void ComboBoxDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
editor->setGeometry(option.rect);
}
void ComboBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
if (index.column() == 6) {
int value = index.model()->data(index, Qt::DisplayRole).toInt();
QStyleOptionButton check_box_style_option;
check_box_style_option.state |= QStyle::State_Enabled;
if (value == 1) {
check_box_style_option.state |= QStyle::State_On;
} else {
check_box_style_option.state |= QStyle::State_Off;
}
check_box_style_option.rect = ComboBoxDelegate::CheckBoxRect(option);
QApplication::style()->drawControl(QStyle::CE_CheckBox, &check_box_style_option, painter);
} else
QStyledItemDelegate::paint(painter, option, index);
}
To copy to clipboard, switch view to plain text mode
It works ok! But now I want to add new row to the table every time I change a value of combobox in last row. That I do in my Model:
#ifndef DATAMODEL_H
#define DATAMODEL_H
#include <QAbstractTableModel>
#include <QStringList>
#include <QList>
#include "product.h"
{
Q_OBJECT
public:
explicit DataModel
(QObject *parent
= 0);
QVariant headerData
(int section, Qt
::Orientation orientation,
int role
) const;
private:
QList<Product*> dataBase_;
signals:
void editCompleted
(const QString &);
public slots:
void changed(const int);
};
#endif // DATAMODEL_H
#include "datamodel.h"
#include <QStringList>
#include <iostream>
DataModel
::DataModel(QObject *parent
) :{
headers_ << "Nazwa, opis" << "Kod towaru" << "Ilość" << "JM" << "Cena netto" << "Wartość netto" << "Refaktura";
dataBase_.push_back(new Product);
}
int DataModel
::rowCount(const QModelIndex & /*parent*/) const {
return dataBase_.size();
}
int DataModel
::columnCount(const QModelIndex & /*parent*/) const {
return 7;
}
QVariant DataModel
::headerData(int section, Qt
::Orientation orientation,
int role
) const {
if (orientation == Qt::Horizontal) {
if( role == Qt::DisplayRole) {
return headers_.at(section);
}
} else {
if( role == Qt::DisplayRole) {
return section + 1;
}
}
}
{
if (role == Qt::DisplayRole)
{
std::cout << index.row() << ", " << index.column() << std::endl;
return dataBase_.at(index.row())->getElement(index.column());
}
}
{
if (role == Qt::EditRole)
{
dataBase_.value(index.row())->setElement(index.column(), value.toString());
}
return true;
}
Qt
::ItemFlags DataModel
::flags(const QModelIndex &index
) const{
if (index.column() == 0 || index.column() == 2 || index.column() == 6)
else
}
void DataModel::changed(const int row) {
dataBase_.value(row)->setElement(1, "set");
emit dataChanged(index(row, 1), index(row, 6));
}
#ifndef DATAMODEL_H
#define DATAMODEL_H
#include <QAbstractTableModel>
#include <QStringList>
#include <QList>
#include "product.h"
class DataModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit DataModel(QObject *parent = 0);
int rowCount(const QModelIndex &parent = QModelIndex()) const ;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
Qt::ItemFlags flags(const QModelIndex & index) const ;
private:
QStringList headers_;
QList<Product*> dataBase_;
signals:
void editCompleted(const QString &);
public slots:
void changed(const int);
};
#endif // DATAMODEL_H
#include "datamodel.h"
#include <QStringList>
#include <iostream>
DataModel::DataModel(QObject *parent) :
QAbstractTableModel(parent)
{
headers_ = QStringList();
headers_ << "Nazwa, opis" << "Kod towaru" << "Ilość" << "JM" << "Cena netto" << "Wartość netto" << "Refaktura";
dataBase_.push_back(new Product);
}
int DataModel::rowCount(const QModelIndex & /*parent*/) const
{
return dataBase_.size();
}
int DataModel::columnCount(const QModelIndex & /*parent*/) const
{
return 7;
}
QVariant DataModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal) {
if( role == Qt::DisplayRole) {
return headers_.at(section);
}
} else {
if( role == Qt::DisplayRole) {
return section + 1;
}
}
}
QVariant DataModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
{
std::cout << index.row() << ", " << index.column() << std::endl;
return dataBase_.at(index.row())->getElement(index.column());
}
return QVariant();
}
bool DataModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
if (role == Qt::EditRole)
{
dataBase_.value(index.row())->setElement(index.column(), value.toString());
}
return true;
}
Qt::ItemFlags DataModel::flags(const QModelIndex &index) const
{
if (index.column() == 0 || index.column() == 2 || index.column() == 6)
return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
else
return QAbstractTableModel::flags(index);
}
void DataModel::changed(const int row) {
dataBase_.value(row)->setElement(1, "set");
emit dataChanged(index(row, 1), index(row, 6));
}
To copy to clipboard, switch view to plain text mode
I tried to make it in changed(const int row), but it doesn't work.
And here is code of product
#ifndef PRODUCT_H
#define PRODUCT_H
#include <QObject>
#include <QVariant>
class Product
{
public:
Product();
double buyingPrice,
QString category
);
void setElement
(int element,
QVariant value
);
return indexName_;
}
return productIndex_;
}
return index_;
}
return unit_;
}
return place_;
}
int getQuantity() const {
return quantity_;
}
double getSellingPrice() const {
return sellingPrice_;
}
double getBuyingPrice() const {
return buyingPrice_;
}
return category_;
}
bool getReInvoice() const {
return re_invoice_;
}
private:
int quantity_;
double sellingPrice_;
double buyingPrice_;
bool re_invoice_;
signals:
public slots:
};
#endif // PRODUCT_H
#include "product.h"
Product::Product() : quantity_(0), sellingPrice_(0), buyingPrice_(0), re_invoice_(false) {
}
double buyingPrice,
QString category
) : indexName_(indexName), productIndex_(productIndex), index_(index),
unit_(unit), place_(place), quantity_(quantity), sellingPrice_(sellingPrice),
buyingPrice_(buyingPrice), category_(category), re_invoice_(false) {
}
QVariant Product
::getElement(int element
) const { switch(element){
case 0:
return indexName_;
case 1:
return index_;
case 2:
return quantity_;
case 3:
return unit_;
case 4:
return sellingPrice_;
case 5:
return buyingPrice_;
case 6:
return re_invoice_;
}
}
void Product
::setElement(int element,
QVariant value
) { switch(element){
case 0:
indexName_ = value.toString();
break;
case 1:
index_ = value.toString();
break;
case 2:
quantity_ = value.toInt();
break;
case 3:
unit_ = value.toString();
break;
case 4:
sellingPrice_ = value.toDouble();
break;
case 5:
buyingPrice_ = value.toDouble();
break;
case 6:
re_invoice_ = value.toBool();
break;
}
}
#ifndef PRODUCT_H
#define PRODUCT_H
#include <QObject>
#include <QVariant>
class Product
{
public:
Product();
Product(QString indexName, QString productIndex, QString index,
QString unit, QString place, int quantity, double sellingPrice,
double buyingPrice, QString category);
QVariant getElement(int element) const;
void setElement(int element, QVariant value);
QString getIndexName() const {
return indexName_;
}
QString getProductIndex() const {
return productIndex_;
}
QString getIndex() const {
return index_;
}
QString getUnit() const {
return unit_;
}
QString getPlace() const {
return place_;
}
int getQuantity() const {
return quantity_;
}
double getSellingPrice() const {
return sellingPrice_;
}
double getBuyingPrice() const {
return buyingPrice_;
}
QString getCategory() const {
return category_;
}
bool getReInvoice() const {
return re_invoice_;
}
private:
QString indexName_;
QString productIndex_;
QString index_;
QString unit_;
QString place_;
int quantity_;
double sellingPrice_;
double buyingPrice_;
QString category_;
bool re_invoice_;
signals:
public slots:
};
#endif // PRODUCT_H
#include "product.h"
Product::Product() : quantity_(0), sellingPrice_(0), buyingPrice_(0), re_invoice_(false) {
}
Product::Product(QString indexName, QString productIndex, QString index,
QString unit, QString place, int quantity, double sellingPrice,
double buyingPrice, QString category) :
indexName_(indexName), productIndex_(productIndex), index_(index),
unit_(unit), place_(place), quantity_(quantity), sellingPrice_(sellingPrice),
buyingPrice_(buyingPrice), category_(category), re_invoice_(false) {
}
QVariant Product::getElement(int element) const {
switch(element){
case 0:
return indexName_;
case 1:
return index_;
case 2:
return quantity_;
case 3:
return unit_;
case 4:
return sellingPrice_;
case 5:
return buyingPrice_;
case 6:
return re_invoice_;
}
return QVariant();
}
void Product::setElement(int element, QVariant value) {
switch(element){
case 0:
indexName_ = value.toString();
break;
case 1:
index_ = value.toString();
break;
case 2:
quantity_ = value.toInt();
break;
case 3:
unit_ = value.toString();
break;
case 4:
sellingPrice_ = value.toDouble();
break;
case 5:
buyingPrice_ = value.toDouble();
break;
case 6:
re_invoice_ = value.toBool();
break;
}
}
To copy to clipboard, switch view to plain text mode
Bookmarks