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 use index.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

    Row and column system

    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.



  • @SRaD

    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())
        {
        // ...


  • @SRaD

    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)

    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

    result_image

    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()
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.