Is there a way to calculate the height of the QStandardItem? - c++

I have created an expandable ListView which extends from the QListView, everything works well when I just want to show the Header data (Item which is not expanded) because I gave it a hard-coded height which is 64, the details appear when expanding the item. But the problem is I do not know the exact height of the details because the details can one line or more, I want to fit the Item height according to the item content.
Here the code which is handling click listener when the item expanding or collapsing:
LogListItemDelegate *delegate = static_cast<LogListItemDelegate *>(itemDelegate());
QStandardItem *item = static_cast<QStandardItemModel *>(model())->itemFromIndex(index);
bool expand = delegate->isExpandable() && mapFromGlobal(QCursor::pos()).x() >= visualRect(index).width() - 48;
bool expanded = index.data(LogListItemDelegate::DT_Expanded).toBool();
// here the height returned is header height, no containing the details which it is in expanding mode
int height = item->sizeHint().height();
if (!expanded) {
item->setData(true, LogListItemDelegate::DT_Expanded);
item->setSizeHint(QSize(0, 150)); // 150 here must be dynamically calculated
} else {
item->setData(false, LogListItemDelegate::DT_Expanded);
item->setSizeHint(QSize(0, 64)); // 64 is the header height, no prolem
}
Now the question is: How to calculate the height when item expanded?
Result:
Edit:
It is when I want to add the message to the list
void LogListView::addMessage(const QJsonObject &msg, const bool append)
{
static int id = 1; // unique id for log items
auto *item = new QStandardItem();
item->setEditable(false);
item->setData(QString("%1").arg(id++, 5, 10, QChar('0')), LogListItemDelegate::DT_Id);
item->setData(msg["icon"], LogListItemDelegate::DT_ICON);
item->setData(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"), LogListItemDelegate::DT_Timestamp);
item->setData(msg["title"], LogListItemDelegate::DT_Title);
item->setData(msg["subtitle"], LogListItemDelegate::DT_Subtitle);
item->setData(msg["details"], LogListItemDelegate::DT_Details);
item->setData(false, LogListItemDelegate::DT_Expanded);
// here I am unable to calculate the height, because the details does not have a specific height to set here,
// so when append the item to the list it is unvisible. If set the height 64, it is the exact height of the item without details, which is good
//item->setSizeHint(QSize(0, 64));
static_cast<QStandardItemModel *>(model())->appendRow(item);
scrollToBottom();
}
It is the code in sizeHint()
QSize LogListItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
bool expanded = index.data(DT_Expanded).toBool();
QFont fntDetials = option.font;
fntDetials.setPointSize(12);
QRect r = option.rect;
QFontMetrics fm(fntDetials);
QString details = index.data(DT_Details).toString();
QRect br = fm.boundingRect(r, Qt::TextWordWrap, details);
return QSize(option.rect.width(), br.height()+64);
}
Unfortunately not working..., I think Qt can look the Android ListView and its recycle functionality to solve the ListView problem, in this way, I think it is very very painful.

If you want to set a custom size you should use the sizeHint method of QStyledItemDelegate, for example:
#include <QApplication>
#include <QStyledItemDelegate>
#include <QListView>
#include <QStandardItemModel>
class HeightDelegate: public QStyledItemDelegate
{
public:
using QStyledItemDelegate::QStyledItemDelegate;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override{
QSize s = QStyledItemDelegate::sizeHint(option, index);
// some calculation
int h = (index.row()+1)*20;
s.setHeight(h);
return s;
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QListView w;
QStandardItemModel model;
HeightDelegate delegate;
w.setItemDelegate(&delegate);
w.setModel(&model);
for(int i=0; i<8; i++){
QStandardItem *it = new QStandardItem(QString::number(i));
it->setBackground(QBrush(QColor(qrand()%255, qrand()%255, qrand()%255)));
model.appendRow(it);
}
w.show();
return a.exec();
}

Related

Customizing QTableView grid style

I'm wondering several things. I have subclassed QTableView to make a custom table. I'd like to be able to do several things.
First of all, I wanted the selected cells not to all have the "selected" color (blue by default) but instead have a frame around the selected cells (just like in Excel). To do this, I've used the following (in my custom QItemDelegate):
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QModelIndex upIndex = index.sibling(index.row() - 1, index.column());
QModelIndex downIndex = index.sibling(index.row() + 1, index.column());
QModelIndex rightIndex = index.sibling(index.row(), index.column() + 1);
QModelIndex leftIndex = index.sibling(index.row(), index.column() - 1);
auto newOption = option;
if (option.state.testFlag(QStyle::State_Selected))
{
painter->save();
auto selIndexes = selM->selectedIndexes().toSet();
painter->setPen(QPen(Qt::red, 5));
if (!selIndexes.contains(rightIndex))
painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
if (!selIndexes.contains(upIndex))
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
if (!selIndexes.contains(downIndex))
painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
if (!selIndexes.contains(leftIndex))
painter->drawLine(option.rect.topLeft(), option.rect.bottomLeft());
painter->restore();
// newOption.palette.setBrush(QPalette::Normal, QPalette::Highlight, index.data(Qt::BackgroundRole).value<QColor>());
newOption.palette.setBrush(QPalette::Normal, QPalette::Highlight, Qt::gray);
}
QStyledItemDelegate::paint(painter, newOption, index);
}
This is probably not optimal, but I'd like to have something that works, before anything else.
Now it seems to be working, but it unfortunately isn't automatically repainted. What happens when I select cells is the following:
Which is not what I'm looking for at all. I guess it's not being repainted because (1) The points inside the zone are still red and (2) If I resize my window, I get the following:
Which is way closer to what I'm trying to achieve.
I've already tried to do this in my QTableView:
// selModel is my selection model
connect(selModel, &QItemSelectionModel::selectionChanged, [this]() {
for(const auto & selected : selModel->selectedIndexes())
{
update(visualRect(selected));
repaint(visualRect(selected));
}
}
(Before, I actually used setDirtyRegion but it didn't work either, so I figured I'd do something more... brutal.)
Finally, I have another question: why do I get those weird red "small lines" in my cell corners? Even on the "kind of" correct screenshot I get these lines that I can't explain:
Please suggest if you have any ideas for any of the issues.
The problem can be easily explained as follows.
Assume that the cell (0,0) is selected. Now the user selects the additional
cells (0,1), (1,0) and (1,1). Qt correctly repaints the additional 3 cells, that
became selected. But, it doesn't repaint the cell (0,0), as it was neither
selected nor deselected. Of course for your desired behavior you still need to redraw this cell.
This can easily be achieved by just redrawing all indices of your current selection.
MyDelegate.h
#pragma once
#include <QStyledItemDelegate>
#include <QItemSelectionModel>
class MyDelegate : public QStyledItemDelegate {
public:
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void setSelectionModel(QItemSelectionModel* selectionModel);
private:
QItemSelectionModel* mSelectionModel{ nullptr };
};
MyDelegate.cpp
#include "MyDelegate.h"
#include <QPainter>
#include <QDebug>
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (!mSelectionModel) return;
auto newOption = option;
auto normalText = newOption.palette.brush(QPalette::ColorGroup::Normal, QPalette::ColorRole::Text);
newOption.palette.setBrush(QPalette::ColorGroup::Normal, QPalette::ColorRole::Highlight, QBrush(Qt::GlobalColor::blue, Qt::BrushStyle::NoBrush));
newOption.palette.setBrush(QPalette::ColorGroup::Normal, QPalette::ColorRole::HighlightedText, normalText);
QStyledItemDelegate::paint(painter, newOption, index);
QModelIndex upIndex = index.sibling(index.row() - 1, index.column());
QModelIndex downIndex = index.sibling(index.row() + 1, index.column());
QModelIndex rightIndex = index.sibling(index.row(), index.column() + 1);
QModelIndex leftIndex = index.sibling(index.row(), index.column() - 1);
//auto newOption = option;
//newOption.palette.setBrush(QPalette::Normal, QPalette::Highlight, Qt::transparent);
if (option.state.testFlag(QStyle::State_Selected))
{
painter->save();
painter->setClipRect(option.rect);
auto selIndexes = mSelectionModel->selectedIndexes().toSet();
painter->setPen(QPen(Qt::red, 5));
if (!selIndexes.contains(rightIndex))
painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
if (!selIndexes.contains(upIndex))
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
if (!selIndexes.contains(downIndex))
painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
if (!selIndexes.contains(leftIndex))
painter->drawLine(option.rect.topLeft(), option.rect.bottomLeft());
painter->restore();
}
}
void MyDelegate::setSelectionModel(QItemSelectionModel* selectionModel)
{
mSelectionModel=selectionModel;
}
main.cpp
#include <QApplication>
#include <QDebug>
#include <QStandardItemModel>
#include <QTableWidget>
#include "MyDelegate.h"
int main(int argc, char** args) {
QApplication app(argc, args);
auto widget = new QTableView;
QStandardItemModel model;
model.setRowCount(10);
model.setColumnCount(10);
for (auto i = 0; i < 10; i++) {
for (auto j = 0; j < 10; j++) {
model.setItem(i, j, new QStandardItem("Test"));
}
}
auto selModel = new QItemSelectionModel;
selModel->setModel(&model);
widget->setModel(&model);
widget->setSelectionModel(selModel);
auto delegate = new MyDelegate;
delegate->setSelectionModel(selModel);
widget->setItemDelegate(delegate);
// Ensures that also items are repainted, that where neither selected nor deselect, but will stay selected
// This solutions eventually paints elements twice
QObject::connect(selModel, &QItemSelectionModel::selectionChanged, [widget,selModel](auto &selected, auto& deselected) {
for (auto item : selModel->selectedIndexes()) {
widget->update(item);
}
});
widget->show();
app.exec();
}
As for the strange red line artifacts, you should paint the red line inside the allowed rectangle I guess. This is easily achieved by clipping to the item boundaries.

How to align a primitive checkbox with the center of QHeaderView's column header?

I have a custom QTableView model with a custom QHeaderView in order to render a checkbox used to perform a "select all" function on the table's contents.
In my header's overloaded paintSection() function, I successfully render the checkbox used to select all with:
QStyleOptionButton option;
option.rect = QRect(3,10,16,16);
option.state = QStyle::State_Enabled | QStyle::State_Active;
if (isChecked_)
option.state |= QStyle::State_On;
else
option.state |= QStyle::State_Off;
style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
Unfortunately, the checkbox is not rendered centered, and instead justified left. This completely clashes with the properly-centered QStyledItemDelegate checkboxes in the column for each table entry.
I know I can change the first two args of QRect to change the origin of the drawn primitive, but this isn't responsive to changes in column width. Although, making the column width fixed isn't the worst solution.
How can I properly center the checkbox in the column header?
Ancillary question: the checkbox in the header is able to be toggled by clicking anywhere in the cell, not just on the box itself (unlike those rendered in the table via delegates). Is there a way to fix this?
The solution of #scopchanov does not work for me since the checkbox covers the whole item of the header
A possible solution is to draw the CheckBox with styles, but apart from that you have to keep a memory of whether the element is checked or not, for this we use QMap<>, the first element is the logicalIndex since it does not change even when it is move the columns and the second element is the state.
#include <QApplication>
#include <QHeaderView>
#include <QMouseEvent>
#include <QPainter>
#include <QStandardItemModel>
#include <QTableView>
class CheckedHeaderView : public QHeaderView
{
Q_OBJECT
public:
using QHeaderView::QHeaderView;
protected:
void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const override
{
painter->save();
QHeaderView::paintSection(painter, rect, logicalIndex);
painter->restore();
QStyleOptionButton opt;
QRect checkbox_rect = style()->subElementRect(QStyle::SE_CheckBoxIndicator, &opt);
checkbox_rect.moveCenter(rect.center());
opt.rect = checkbox_rect;
opt.state = QStyle::State_Enabled | QStyle::State_Active;
if(logicalIndex == columnDown)
opt.state |= QStyle::State_Sunken;
if (states[logicalIndex])
opt.state |= QStyle::State_On;
else
opt.state |= QStyle::State_Off;
style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &opt, painter);
}
void mousePressEvent(QMouseEvent *event) override
{
QHeaderView::mousePressEvent(event);
int li = logicalIndexAt(event->pos());
if(li == -1) return;
columnDown = li;
updateSection(li);
}
void mouseReleaseEvent(QMouseEvent *event) override
{
QHeaderView::mouseReleaseEvent(event);
int li = logicalIndexAt(event->pos());
if(li == -1) return;
states[li] = !states[li];
Q_EMIT checked(li, states[li]);
columnDown = -1;
updateSection(li);
}
Q_SIGNALS:
void checked(int logicalIndex, bool state);
private:
QMap<int, bool> states;
int columnDown = -1;
};
class TableView : public QTableView
{
Q_OBJECT
public:
TableView(QWidget *parent = nullptr):
QTableView(parent)
{
CheckedHeaderView *header = new CheckedHeaderView(Qt::Horizontal, this);
setHorizontalHeader(header);
connect(header, &CheckedHeaderView::checked, this, &TableView::on_checked);
}
private Q_SLOTS:
void on_checked(int logicalIndex, bool state){
QItemSelectionModel::SelectionFlags command = state? QItemSelectionModel::Select : QItemSelectionModel::Deselect;
for(int r=0; r < model()->rowCount(); r++){
QModelIndex ix = model()->index(r, logicalIndex);
selectionModel()->select(ix, command);
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TableView w;
QStandardItemModel *model = new QStandardItemModel(8, 6, &w);
w.setModel(model);
w.show();
return a.exec();
}
Solution
QHeaderView::paintSection takes a QRect &rect as an argument. Set QStyleOption::rect to be equal to rect, i.e. replace
option.rect = QRect(3,10,16,16);
with
option.rect = rect;
Note: This solution is responsive to changes in column width.
Example
Using your implementation of paintSection I have created a minimal example in order to demonstrate how the proposed solution could be implemented. The code is available on GitHub.
Result
The provided example produces the following result on Windows 7:
The result on Windows 10:
Note: This solution does not work on Linux, as it produces the following result (Ubuntu 17):

How to override 'paint' function of custom delegate class to draw QSpinBox

I have added a custom delegator to the QTableView. When I double click on an item I see the editor widget which is a 'QSpinBox' and I am able to edit the value fine. This editor widget disappears once the focus is lost and I understand that. What I want is QSpinBox to be there all the time. Looking at the Qt example here I know I need to override the paint function of QAbstractItemDelegate class to draw the QSpinBox but I don't know how to that. In general, I want to know how any of the Qt widgets can be drawn inside a paint function.
For reference, I am having following test code:
#include <QtWidgets/QApplication>
#include <QtGui>
#include <QTableview>
#include <QLayout>
#include <QColor>
#include <QStyledItemDelegate>
#include <QSpinbox>
class SpinBoxDeligate : public QStyledItemDelegate {
public:
QWidget * createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
auto w = new QSpinBox(parent);
w->setFrame(false);
w->setMinimum(0);
w->setMaximum(100);
return w;
}
void setEditorData(QWidget *editor, const QModelIndex &index) const override {
static_cast<QSpinBox*>(editor)->setValue(index.data(Qt::EditRole).toInt());
}
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override {
model->setData(index, static_cast<QSpinBox*>(editor)->value(), Qt::EditRole);
}
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
// What to replace below line with to have a QSpinBox
QStyledItemDelegate::paint(painter, option, index);
}
};
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QStandardItemModel model(3, 1);
for (int r = 0; r < 3; ++r)
{
auto text = QString("%0").arg(r);
QStandardItem* item = new QStandardItem(text);
item->setFlags(Qt::ItemIsUserCheckable
| Qt::ItemIsEnabled
| Qt::ItemIsEditable
);
item->setData(Qt::Unchecked, Qt::CheckStateRole);
item->setData(text, Qt::ToolTipRole);
item->setData(QSize(100, 30), Qt::SizeHintRole);
item->setData(QIcon(":/QtMVC/Desert.jpg"), Qt::DecorationRole);
model.setItem(r, 0, item);
}
QTableView* table = new QTableView();
table->setModel(&model);
table->setItemDelegate(new SpinBoxDeligate());
QWidget w;
QVBoxLayout* containerLayout = new QVBoxLayout();
w.setLayout(containerLayout);
containerLayout->addWidget(table);
w.show();
return app.exec();
}
A possible solution for your background problem is to use paint() and for that you could create a QSpinBox and use grab to take an image, but before that you should calculate the geometry so that it does not cover the QCheckBox, as you see it is a tedious job, another way is using QStyle but it is still much more code.
A simple solution is to keep the editor open with the openPersistentEditor() method.
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QStandardItemModel model(3, 1);
QTableView* table = new QTableView();
table->setModel(&model);
table->setItemDelegate(new SpinBoxDeligate());
for (int r = 0; r < 3; ++r)
{
auto text = QString("%0").arg(r);
QStandardItem* item = new QStandardItem(text);
item->setFlags(Qt::ItemIsUserCheckable
| Qt::ItemIsEnabled
| Qt::ItemIsEditable
);
item->setData(Qt::Unchecked, Qt::CheckStateRole);
item->setData(text, Qt::ToolTipRole);
item->setData(QSize(100, 30), Qt::SizeHintRole);
item->setData(QIcon(":/QtMVC/Desert.jpg"), Qt::DecorationRole);
model.setItem(r, 0, item);
table->openPersistentEditor(model.indexFromItem(item));
}
QWidget w;
QVBoxLayout* containerLayout = new QVBoxLayout();
w.setLayout(containerLayout);
containerLayout->addWidget(table);
w.show();
return app.exec();
}
I can think of two possible solutions:
It is possible to insert widgets into table cells. I know this is not what you're trying to do but it can be a better solution for your problem. Check setIndexWidget.
If you really want to render QSpinBox, you should use the render method of QWidget. To try, in your paint method create a QSpinBox and call it's render method passing it the QPainter pointer. After you get it working this way, you can improve your design by possibly holding a 'template' QSpinBox instance in your QTableView and use it to render different QSpinBox values inside cells where required

QStyledItemDelegate: commit QComboBox value to model on click

I am setting a QStyledItemDelegate on my model for a particular field, and returning a QComboBox from QStyledItemDelegate::createEditor
QComboBox* createEditor(QWidget* parent)
{
QComboBox* cb = new QComboBox(parent);
cb->addItem("UNDEFINED");
cb->addItem("TEST");
cb->addItem("OSE");
cb->addItem("TSE");
return cb;
}
void setEditorData(QWidget* editor, const QModelIndex& index)
{
QComboBox* cb = qobject_cast<QComboBox*>(editor);
if (!cb)
throw std::logic_error("editor is not a combo box");
QString value = index.data(Qt::EditRole).toString();
int idx = cb->findText(value);
if (idx >= 0)
cb->setCurrentIndex(idx);
cb->showPopup();
}
This is working fine, and when I select the field in question I am shown a combo box.
When I select an option from the drop-down list, the combobox closes and the item is displayed with a drop-down icon next to it:
At this point I would like the QStyledItemDelegate::setModelData function to be called, so that selecting an item in the list commits the data to the model.
However, I am required to first press Enter to commit the data (whereby the drop-down icon disappears)
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index)
{
QComboBox* cb = qobject_cast<QComboBox*>(editor);
if (!cb)
throw std::logic_error("editor is not a combo box");
model->setData(index, cb->currentText(), Qt::EditRole);
}
Question:
How can I configure my QComboBox to automatically commit the data when the user selects an item in the list and the combobox list closes, rather than requiring the additional press of Enter?
You have to issue the signal commitData and closeEditor when an item is selected as shown in the following example:
#include <QApplication>
#include <QStandardItemModel>
#include <QListView>
#include <QStyledItemDelegate>
#include <QComboBox>
class ComboBoxDelegate: public QStyledItemDelegate{
public:
using QStyledItemDelegate::QStyledItemDelegate;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const{
Q_UNUSED(option)
Q_UNUSED(index)
QComboBox* editor = new QComboBox(parent);
connect(editor, QOverload<int>::of(&QComboBox::activated),
this, &ComboBoxDelegate::commitAndCloseEditor);
editor->addItems({"UNDEFINED", "TEST", "OSE", "TSE"});
return editor;
}
void setEditorData(QWidget *editor, const QModelIndex &index) const{
QComboBox* cb = qobject_cast<QComboBox*>(editor);
if (!cb)
throw std::logic_error("editor is not a combo box");
QString value = index.data(Qt::EditRole).toString();
int idx = cb->findText(value);
if (idx >= 0)
cb->setCurrentIndex(idx);
cb->showPopup();
}
private:
void commitAndCloseEditor(){
QComboBox *editor = qobject_cast<QComboBox *>(sender());
emit commitData(editor);
emit closeEditor(editor);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QListView view;
QStandardItemModel model;
for(int i=0; i<10; i++){
model.appendRow(new QStandardItem("UNDEFINED"));
}
view.setItemDelegate(new ComboBoxDelegate(&view));
view.setModel(&model);
view.show();
return a.exec();
}

How do I animate the border of a list item in a QListView?

I am using a QListView with a custom delegate that extends from QStyledItemDelegate. I reimplemented the paint method to custom paint each item in the list. In the paint method, I am drawing a border around selected items in the list view.
I want to be able to animate the item border as I select an item. For example, if the intended item border is 5 pixels, I want to have it "animate in" from 0 pixels to 5 pixels when the item is selected.
My original idea was to hook up a timer to go off every 50 milliseconds and have the delegate paint every time the timer goes off until the full border width has been painted. However, the delegate's reimplemented paint method is const, so I can't save or update a border width member variable during each pass through of the paint method.
What is the best way of accomplishing this?
A possible solution is to create a role that manages the border size of the item, and update it using a QVariantAnimation:
#include <QApplication>
#include <QListView>
#include <QPainter>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QVariantAnimation>
int BorderSizeRole = Qt::UserRole+1;
class AnimationDelegate: public QStyledItemDelegate{
public:
using QStyledItemDelegate::QStyledItemDelegate;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const{
QStyledItemDelegate::paint(painter, option, index);
bool ok;
int borderSize = index.data(BorderSizeRole).toInt(&ok);
if(borderSize >0 && ok){
painter->save();
QPen pen(QBrush(Qt::red), borderSize);
painter->setPen(pen);
painter->drawRect(option.rect);
painter->restore();
}
}
};
class CustomAnimation: public QVariantAnimation{
QPersistentModelIndex m_index;
QAbstractItemModel *m_model;
public:
CustomAnimation(QAbstractItemModel *m_model, QPersistentModelIndex index, QObject *parent=nullptr)
: QVariantAnimation(parent),
m_index(index),
m_model(m_model)
{
setStartValue(0);
setEndValue(5);
setDuration(50*5);
connect(this, &CustomAnimation::valueChanged, this, &CustomAnimation::on_valueChanged);
// delete animation
start(QAbstractAnimation::DeleteWhenStopped);
}
private:
Q_SLOT void on_valueChanged(const QVariant & value){
if(m_model)
m_model->setData(m_index, value, BorderSizeRole);
else
stop();
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QListView view;
view.setItemDelegate(new AnimationDelegate(&view));
QStandardItemModel model;
for(int i=0; i<10; i++){
QStandardItem *item = new QStandardItem(QString("item %1").arg(i));
item->setData(-1, BorderSizeRole);
model.appendRow(item);
}
view.setModel(&model);
QObject::connect(view.selectionModel(), &QItemSelectionModel::selectionChanged,
[&model](const QItemSelection &selected, const QItemSelection & deselected){
for(const QModelIndex & index: selected.indexes()){
new CustomAnimation(&model, QPersistentModelIndex(index));
}
// remove border
for(const QModelIndex & index: deselected.indexes()){
model.setData(index, -1, BorderSizeRole);
}
});
view.show();
return a.exec();
}