How to add progress bar to specific treeview row,column?
-
Using Qt5. I'm trying to add a progress bar to the second column of a QTreeView, but only to a specific row, not the entire second column. Below is what I have, but nothing shows other than what I put in the first columns.
//progress.h class ProgressDelegate : public QStyledItemDelegate { Q_OBJECT public: ProgressDelegate(QObject *parent = 0); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const override; }; //progress.cpp ProgressDelegate::ProgressDelegate(QObject *parent) : QStyledItemDelegate(parent) { } void ProgressDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const // override { if (index.column() == 2) { QStyleOptionProgressBar progressBarOption; progressBarOption.state = QStyle::State_Enabled; progressBarOption.direction = QApplication::layoutDirection(); progressBarOption.rect = option.rect; progressBarOption.fontMetrics = QApplication::fontMetrics(); progressBarOption.minimum = 0; progressBarOption.maximum = 100; progressBarOption.textAlignment = Qt::AlignCenter; progressBarOption.textVisible = true; QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter); } else QStyledItemDelegate::paint(painter, option, index); return; } // main-window.cpp testModel = new QStandardItemModel(2, 2); testModel->setHorizontalHeaderLabels(headers); treeView = new QTreeView; delegate = new ProgressDelegate(this); treeView->setModel(testModel); QString a = QString::fromStdString("stringA"); QStandardItem *ai = new QStandardItem(a); QString b = QString::fromStdString("stringB"); QStandardItem *bi = new QStandardItem(b); ai->appendRow(bi); testModel.setItem(1, 0, ai);
I can see that I don't have a call to somehow put the progress bar in the column, but I'm not sure how that works.
-
@SRaD Hi there.
Firstly, the counter of rows and columns begins in 0, so if you are trying to set a personal paint in the Second Column, you should to useindex.column() == 1
Don't forget that in Father and Children model, the count of row and column is reseted when you set an item as the child of another item.
Image from QT - Model/View Tutorial
QModexIndex has 3 important Attributes:
- row
- column
- parent
For default, if you call parent() function of an item that haven't father, it will return a standard QModexIndex
Below is an example of how you can set a progress bar in the item of first row, second column and in top father level.
void ProgressDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const // override { if (index.row() == 0 && index.column() == 1 && index.parent() == QModelIndex()) // first row, second column, at top father level { QStyleOptionProgressBar progressBarOption; progressBarOption.state = QStyle::State_Enabled; progressBarOption.direction = QApplication::layoutDirection(); progressBarOption.rect = option.rect; progressBarOption.fontMetrics = QApplication::fontMetrics(); progressBarOption.minimum = 0; progressBarOption.maximum = 100; progressBarOption.textAlignment = Qt::AlignCenter; progressBarOption.textVisible = true; QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter); } else QStyledItemDelegate::paint(painter, option, index); }
Read More:
http://doc.qt.io/qt-5/qmodelindex.html
http://doc.qt.io/qt-5/model-view-programming.html -
Still not seeing progress bars. Here is my tree, and my understanding of row/col id's.
Root Item (this is column 0) +- row = 0 (this is column 1) + row = 0 (column 2, progress bar here) + row = 1 (column 2, progress bar here) + row = 2 (column 2, progress bar here) +- row = 1 (this is column 1) + row = 0 (column 2, progress bar here) + row = 1 (column 2, progress bar here) + row = 2 (column 2, progress bar here)
Since I only want to have progress bars to the 3 items in the second column, here is how I set my paint method ...
void ProgressDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const // override { if (index.column() == 2 && index.parent() != QModelIndex()) { // ...
However, I still see nothing showing up in the second column of my treeview.
-
Is the element (row 0, column 2) a child of element ( row 0, column 1) ?
I am not understanding why your column index is incrementing...When an element is appended as child of another, their counters starts in (0,0) again.
-
"Is the element (row 0, column 2) a child of element ( row 0, column 1) ?"
Yes, row 0, column 2 is a child of row 0, column 1."I am not understanding why your column index is incrementing..."
Doesn't each new column to the right increment? I have 3 columns."When an element is appended as child of another, their counters starts in (0,0) again."
And I think I have that. I don't see where I'm going wrong.Edit:
I think I see where I might be going wrong. I thought each new append is a new column, but I see in my treevew, this hierarchy shows up in column 1 (or 0) of the treeview and I'm trying to put a progress bar in column 2 (or 1) of the treeview. I think I'm thinking each new child is a column.So therefore, I've changed index.column() == 1 thinking this is the 2nd column of my treeview, not the hierarchy above. But still not seeing a progress bar.
void ProgressDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const // override { if (index.column() == 1 && index.parent() != QModelIndex()) { // ...
-
Look, think in a tree model setted up as below example:
- Item A (0,0,0)
- Item 1 (0,0,1)
- Item P1 (0,0,2)
- Item P2 (1,0,2)
- Item P3 (2,0,2)
- Item 2 (1,0,1)
- Item P1 (0,0,2)
- Item P2 (1,0,2)
- Item P3 (2,0,2)
- Item 3 (2,0,1)
- Item P1 (0,0,2)
- Item P2 (1,0,2)
- Item P3 (2,0,2)
- Item 1 (0,0,1)
Note: Each child has a Z Level depending of their parent but the value of (X,Y) is reseted for each append.
To set the Progressbar if the element is grandchild, you could to calculate the Z Level using the Parent of this element.
Example:
void ProgressDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const // override { int z = 0; for(QModelIndex parentIndex = index.parent(); parentIndex.isValid(); z++){ parentIndex = parentIndex.parent(); } if (index.column() == 0 && z==2) { QStyleOptionProgressBar progressBarOption; progressBarOption.state = QStyle::State_Enabled; progressBarOption.direction = QApplication::layoutDirection(); progressBarOption.rect = option.rect; progressBarOption.fontMetrics = QApplication::fontMetrics(); progressBarOption.minimum = 0; progressBarOption.maximum = 100; bool isNumber; int number = index.data(Qt::DisplayRole).toInt(&isNumber); if(isNumber){ progressBarOption.progress = number; } progressBarOption.textAlignment = Qt::AlignCenter; progressBarOption.textVisible = true; QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter); } else QStyledItemDelegate::paint(painter, option, index); }
QStandardItemModel *model = new QStandardItemModel(0,1,this); model->setHorizontalHeaderItem(0, new QStandardItem("Main Column")); ProgressDelegate *delegate = new ProgressDelegate(this); ui->treeView->setItemDelegate(delegate); ui->treeView->setModel(model); QStandardItem *ia; QStandardItem *i1,*i2,*i3; QStandardItem *p1,*p2,*p3; // (Row , Column , Z Level) ia = new QStandardItem("Item A"); // (0,0,0) i1 = new QStandardItem("Item 1"); // (0,0,1) p1 = new QStandardItem("15"); // (0,0,2) p2 = new QStandardItem("30"); // (1,0,2) p3 = new QStandardItem("12"); // (2,0,2) i1->appendRow(p1); i1->appendRow(p2); i1->appendRow(p3); ia->appendRow(i1); i2 = new QStandardItem("Item 2"); // (1,0,1) p1 = new QStandardItem("35"); // (0,0,2) p2 = new QStandardItem("77"); // (1,0,2) p3 = new QStandardItem("12"); // (2,0,2) i2->appendRow(p1); i2->appendRow(p2); i2->appendRow(p3); ia->appendRow(i2); i3 = new QStandardItem("Item 3"); // (2,0,1) p1 = new QStandardItem("7"); // (0,0,2) p2 = new QStandardItem("22"); // (1,0,2) p3 = new QStandardItem("85");// (2,0,2) i3->appendRow(p1); i3->appendRow(p2); i3->appendRow(p3); ia->appendRow(i3); model->appendRow(ia); // (0,0,0)
Result
But this solution has a processing overhead to calculate the Z Level using the For Loop each time that paint event is called, so, seriously, the best solution is calculate the Z Level when the Data is appended on Model.
Pseudo-code - when insert the data or changing the root:
if has parent then Data[Z_Role] := parent_z_level + 1 else Data[Z_Role] := 0
You could easily get the Z Level on Delegate with this functionality
// Z_Role = Qt::UserRole+1 int zLevel = index.data(Qt::UserRole+1).toInt()
- Item A (0,0,0)