My delegate doesn't display checkboxes - c++

Guys I've implemented my delegate class based on QStyledItemDelegate and the problem I have is that it doesn't display checkboxes next to the text which is displayed in the listView.
Before I've used my delegate I've those checkboxes displayed in my listView so I know that's the problem lays in this delegate class.
Any thoughts?
EDIT
void Display_Delegate::paint( QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex &index) const
{
QString model_data = index.data().toString();
QFontMetrics metrics = view_->fontMetrics();
int view_width = view_->width();
auto modified_str = adjust_text(metrics,model_data,view_width);//this just makes the string to fit into view, don't bother about it.
QStyleOptionViewItemV4 style_option = option;
initStyleOption(&style_option,index);
QPalette::ColorGroup color_group = style_option.state & QStyle::State_Selected ? QPalette::Active : QPalette::Inactive;
if (style_option.state & QStyle::State_Selected)
{
// painter->setPen(style_option.palette.color(color_group, QPalette::Highlight));
painter->setBackgroundMode(Qt::OpaqueMode);
QColor color(148,231,245,100);
painter->setBackground(QBrush(color));
}
else
{
painter->setPen(style_option.palette.color(color_group, QPalette::Text));
}
painter->drawText(option.rect,modified_str);
}

Qt::CheckState QStyleOptionViewItemV4::checkState
If this view item is checkable, i.e., ViewItemFeature::HasCheckIndicator is true, checkState is true if the item is checked; otherwise, it is false.
I found in the methods this fairly obscure reference to having a check indicator. It says that if you want to make the item "checkable" then set this style option. So try something like:
style_option.ViewItemFeatures = QStyleOptionViewItemV2::HasCheckIndicator;

Related

How to get selected items from a QListView which uses custom QAbstractListModel in C++

I have created a custom list model following this guide Creating a cusotm model for a QListView. I am able to show a list of custom objects (such as the Employee as in the example) but I don't know how to retrieve back the selected ones (can I retrieve back the "linked" objects directly?).
Maybe do I have to do something with this command:
myLV->selectionModel()->selectedIndexes();
But I don't really know how to retrieve back the original custom objects.
[EDIT]
So far I have solved retrieving back the object adding a custom method inside my custom list model:
Employee* MyEmployeeListModel::getAtSelectedIndex(const QModelIndex& index){
return employees_.at(index.row());
}
And then calling this on the main window:
QModelIndexList selectedRows;
QItemSelectionModel * selmodel = ui->employeesLV->selectionModel();
selectedRows = selmodel->selectedRows();
MyEmployeeListModel* currModel = dynamic_cast <MyEmployeeListModel*>(ui->employeesLV->model());
for (const QModelIndex & index : selectedRows){
Employee* item=currModel->getAtSelectedIndex(index);
if (item) {
// do something with the item
}
}
Now what I am willing to know is if this is the real best practice or not.
I'm using the following code with a QTreeView (ui->treeMessages), but this should work with a QListView as well:
QModelIndexList selectedRows;
QItemSelectionModel * selmodel = ui->treeMessages->selectionModel();
selectedRows = selmodel->selectedRows();
for (const QModelIndex & index : selectedRows)
{
const QModelIndex sourceIndex = m_sortFilterModel->mapToSource(index);
ItemData * item = sourceIndex.internalPointer();
if (item) {
// do something
}
}

Qt checkboxes in QTableView

I'm using this code to query sqlite and put the results in a QTableView.
//MainWindow.cpp
void MainWindow::on_pushButton_clicked()
{
QSqlQueryModel * modal=new QSqlQueryModel();
connOpen();
QSqlQuery* qry=new QSqlQuery(mydb);
qry->prepare("select * from database");
qry->exec();
modal->setQuery(*qry);
//from stack
modal->insertColumn(0);
ui->tableView->setModel(modal);
//from stack
ui->tableView->resizeColumnsToContents();
int p;
for(p=0; p<modal->rowCount(); p++)
{
ui->tableView->setIndexWidget(modal->index(p,0),new QCheckBox());
}
connClose();
qDebug() <<(modal->rowCount());
}
I've seen several examples of the web for adding checkboxes to a column, but I'm not quite sure what to use for my simple example.
This answer suggests a few lines that doesn't seem standard.
There are more examples like this and this one that appear to outline what I need, but it's unclear to where you place the code.
What I intend to do is to have column 1 checkable. On next btn press, If checked those rows of data get written to a file.
I still need to understand how to loop thru the selected data, or perhaps I need to get the ids of the checked rows and do another query.
Questions:
How do you add 1 column of editable checkboxes to QTableView?
How do you loop through values in the QTableView data, so values of the checked rows can be accessed?
How do you check all/none?
I think the best way to have a column of checkable cells is to create your item model, e.g. by subclassing the QSqlQueryModel.
You must reimplement the flags() method to make checkable the cells.
Also you need to reimplement the data() method to return the check state and the setData() method and to set the check state. You must implement your own logic to keep track of the check state of every rows (e.g. using an array of Qt::CheckState that you must initialize and resize when the model data changes).
Yuo can start with something like this:
class MyModel : public QSqlQueryModel
{
public:
Qt::ItemFlags flags(const QModelIndex & index) const
{
if(index.column() == 0)
return QSqlQueryModel::flags(index) | Qt::ItemIsUserCheckable;
return QSqlQueryModel::flags(index);
}
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const
{
if(index.column() == 0 && role == Qt::CheckStateRole)
{
//implement your logic to return the check state
//....
}
else
return QSqlQueryModel::data(index, role);
}
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole)
{
if(index.column() == 0 && role == Qt::CheckStateRole)
{
//implement your logic to set the check state
//....
}
else
QSqlQueryModel::setData(index, value, role);
}
};
Se also:
Model Subclassing
QAbstractItemModel documentation

Custom delegate Paint persist when editing

I am trying to write custom delegate and custom model as a part of learning Qt.
I made a simple custom model based on QAbstractTableModel. I did not do anything complicated. It only generates the data in its constructor as well as minimally implement the pure virtual function.
I made a custom delegate which display numerical data in terms of bars. I also implemented a spin box as an editor to edit data.
The program works well. I can view, edit and modify data through a QTableView with the delegate set.
But there is a small problem. When I call the editor, the data bar persists, which means I see the data bar at the background and the spin box on top.
Initially, I think it is because the Qt::EditRole in the QAbstractTableModel::data() has not been set properly. But, surprisingly, I find that the Qt::EditRole has never been called.
So, there are two question:
How to remove the data bar when I am having the spin box editor?
Why is the EditRole never been called in my custom model?
Here is part of my code:
My Custom Model:
MyModel::MyModel(QObject* parent):QAbstractTableModel(parent)
{
for (int i = 0; i < 10; ++i)
localData.push_back(i*i);
}
QVariant MyModel::data(const QModelIndex &index, int role) const
{
switch(role)
{
case Qt::EditRole:
qDebug() << "EditRole"; //Never Print Out
return 0;
case Qt::DisplayRole :
if (index.column() == 0)
return (index.row());
if (index.column() == 1)
return (localData.at(index.row()));
default:
return QVariant();
}
}
My Custom Delegate:
void MyDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
painter->save();
painter->setPen(Qt::red);
painter->setBrush(Qt::red);
double factor = 0;
if (index.data().toDouble() > 100)
factor = 1;
else
factor = index.data().toDouble() / (double) (100.0);
painter->drawRect(option.rect.x()+5, option.rect.y()+3, (option.rect.width()-10)*factor, option.rect.height()-6);
painter->restore();
}
QWidget* MyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QSpinBox* box = new QSpinBox(parent);
box->setMinimum(0);
box->setMaximum(100);
return box;
}
Try to set setAutoFillBackground(true) for your view
Editrole is not called because your custom editor does not query the model for that data. You don not set any value for your spin box. Try to set it as:
box->setValue(model.data(Qt::EditRole));
in the MyDelegate::createEditor() function.

Changing data in a QTableView depending on the selection of a QComboBox

I have a QComboBox in one of the columns of a QTableView. How can I change the other columns depending on what I selected in the ComboBox? I am using the QComboBox as a delegate.
There are at least 2 approaches.
Use natural for Qt's model itemChanged signal.
emit signal from your delegate and catch it inside your main window.
If your delegate is standard which means that inside setModelData() method you have something like:
QComboBox *line = static_cast<QComboBox*>(editor);
QString data = line->currentText();
//...
model->setData(index, data);
then I think you should use just natural way. For example:
connect(model,&QStandardItemModel::itemChanged,[=](QStandardItem * item) {
if(item->column() == NEEDED_COLUMN)
{
//you found, just get data and use it as you want
qDebug() << item->text();
}
});
I used here C++11 (CONFIG += c++11 to .pro file) and new syntax of signals and slots, but of course you can use old syntax if you want.
I already reproduced your code(delegate with combobox) and my solution works if I select something in combobox and confirm that by enter clicking for example. But if you want to get solution where data will be changed automatically, when you select another item in combobox(without pressing enter) then see next case:
Create special signal onside delegate:
signals:
void boxDataChanged(const QString & str);
Create connection inside createEditor() method:
QWidget *ItemDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QComboBox *editor = new QComboBox(parent);
connect(editor,SIGNAL(currentIndexChanged(QString)),this,SIGNAL(boxDataChanged(QString)));
return editor;
}
And use it!
ItemDelegate *del = new ItemDelegate;
ui->tableView->setItemDelegate( del);
ui->tableView->setModel(model);
connect(del,&ItemDelegate::boxDataChanged,[=](const QString & str) {
//you found, just get data and use it as you want
qDebug() << str;
});

Qt - How can I make a particular Column of my QTableView as Non Editable?

I have a QTableView with 4 Rows and 4 columns each representing their data's in it. By default the QTableView is editable. Now I want to make any particular column as non editable in my QTableView.
How can I do it?
Thanks in Advance.
You can use the setItemDelegateForColumn() function. Implement a read-only delegate, and set it for the column you need.
You can also use the flags inside your model, and remove the Qt::ItemIsEditable flag for a specific column.
Something like that may also do it:
class NotEditableDelegate : public QItemDelegate
{
Q_OBJECT
public:
explicit NotEditableDelegate(QObject *parent = 0)
: QItemDelegate(parent)
{}
protected:
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{ return false; }
QWidget* createEditor(QWidget *, const QStyleOptionViewItem &, const QModelIndex &) const
{ return Q_NULLPTR; }
};
In use:
// Make all the columns except the second read only
for(int c = 0; c < view->model()->columnCount(); c++)
{
if(c != 1)
view->setItemDelegateForColumn(c, new NotEditableDelegate(view));
}
The easiest way is settting the flag of the item you don't want to be editable in this way:
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
You can also check this thread: Qt How to make a column in QTableWidget read only
May be this late, but for future reference. You should set the table view to NoEditTrigger like this:
myTableView->setModel(model);
myTableView->setEditTriggers(QAbstractItemView::NoEditTriggers)
You need to override the 'flags' method and specify the editability parameters of the element for the selected column
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
{
if(!index.isValid())
return Qt::NoItemFlags;
if(index.column() == SELECTED_COLUMN_NUM)
{
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
}
In the overide method just change it to if(!(index.column() == 0) and change the Flag value as Flag |= Qt::ItemisEditable.This Works Fine.