want to add a graphic to a table



  • Hi all -

    The app I'm working on contains a QTableView (I'm sure some of you are probably tired of seeing this already):
    0_1542383317408_ui.PNG
    I was thinking about adding a column to show the battery level for each device in the table. It doesn't need to be anything fancy, but a graphic representation might be nice.

    So, if you had to do something like this, what Qt construct(s) would you use to implement it? And, am I going to encounter any complication when I try to incorporate it into a column of my view?

    Thanks...



  • it should be really easy, it's just about subclassing QStyledItemDelegate and reimplement paint to paint a rectangle with the level of the battery



  • Heh...the words "Qt," "easy" and "mzimmers" don't often collide in the same sentence.

    I couldn't find an example with the word QStyledItemDelegate, so I've looked at the docs. So, do I create a QModelIndex, and somehow set the delegate onto that?

    Originally I was thinking of using a (readonly) QProgressBar for this, but that's probably overkill. I could just color the background and express the power level as a percentage.



  • @mzimmers Hi,

    If you want only to color the background, just return the color from the data() method of your model using the Qt::BackgroundRole, and the percentage value using Qt::DisplayRole.



  • @mzimmers
    Here is an example of reimplementation of a QStyledItemDelegate drawing a progress bar using QStyleOptionProgressBar. It may help you to make your own custom delegate. I think this is pretty close to what you are trying to achieve

    //.h
    #ifndef PROGRESSBARITEMDELEGATE_H
    #define PROGRESSBARITEMDELEGATE_H
    
    #include <QStyledItemDelegate>
    
    class ABSTRACTTASK_SHARED_EXPORT ProgressBarItemDelegate : public QStyledItemDelegate
    {
    public:
        ProgressBarItemDelegate(QObject *parent = 0);
        ~ProgressBarItemDelegate();
    
        QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
    
    protected:
        virtual void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
    
    
    };
    
    #endif // PROGRESSBARITEMDELEGATE_H
    //.cpp
    #include "progressbaritemdelegate.h"
    #include "taskfuturemodel.h"
    
    #include <QAbstractItemView>
    #include <QApplication>
    #include <QDebug>
    #include <QFontMetrics>
    
    ProgressBarItemDelegate::ProgressBarItemDelegate(QObject *parent) :
        QStyledItemDelegate(parent){}
    
    ProgressBarItemDelegate::~ProgressBarItemDelegate() {}
    
    QSize ProgressBarItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        QSize sizeHint = QStyledItemDelegate::sizeHint(option, index);
        QFont font;
        QFontMetrics fm(font);
        int width = qMax(20, fm.width(index.data(MyModel::ProgressTextRole).toString()));
        //qDebug() << "ProgressBarItemDelegate::sizeHint: " << sizeHint;
        sizeHint.setWidth(width);
        //qDebug() << "ProgressBarItemDelegate::sizeHint updated: " << sizeHint;
    
        return sizeHint;
    }
    
    void ProgressBarItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
    
        //Possible alternative using stylesheet
        //https://stackoverflow.com/questions/10630360/customized-color-on-progressbar-delegate
        if (index.column() == MyModel::COL_PROGRESS_VALUE) {
            int progress = index.data().toInt();
            bool failed = progress == -2;
            int min = 0;
            //Set undeterminate progress in case of -1 value
            int max = progress == -1 ? 0 : 100;
            QString result;
    
            //Get min & max values from the model data
            const QAbstractItemModel *model = view->model();
            if(model){
                min = index.data(MyModel::ProgressMinRole).toInt();
                max = index.data(MyModel::ProgressMaxRole).toInt();
                result = index.data(MyModel::ResultRole).toString();
            }
            
            if(result == "Failed")
                failed = true;
            QString progressText = index.data(TaskFutureModel::ProgressTextRole).toString();
    
            QStyleOptionProgressBar progressBarOption;
            progressBarOption.rect = option.rect;
            progressBarOption.minimum = min;
            progressBarOption.maximum = max;
            progressBarOption.progress = qMin(progress, progressBarOption.maximum);
    
            progressBarOption.text = progressText;
            progressBarOption.textVisible = true;
            progressBarOption.textAlignment = Qt::AlignCenter;
            if(failed || result == "Failed"){
                progressBarOption.palette.setColor(QPalette::Highlight, QColor("red"));
            } else if(result == "Aborted"){
                progressBarOption.palette.setColor(QPalette::Highlight, QColor("orange"));
            } else {
                progressBarOption.palette.setColor(QPalette::Highlight, QColor("#blue"));
            }
    
            if((min == 0 && max == 0 )|| progress == -1){
                progressBarOption.palette.setColor(QPalette::HighlightedText, QColor("white"));
                progressBarOption.palette.setColor(QPalette::WindowText, QColor("white"));
            }
    
            QApplication::style()->drawControl(QStyle::CE_ProgressBar,
                                               &progressBarOption, painter);
        } else
            QStyledItemDelegate::paint(painter, option, index);
    }
    

    Usage:

    ui->tvTasks->setItemDelegateForColumn(<Column_Index>,
                                              new ProgressBarItemDelegate(myTableView));
    


  • @Gojir4 thank you so much for the example. I've copied your code into my project. I'm getting an error about ABSTRACTTASK_SHARED_EXPORT, and I can't find anything online about that keyword. Can you tell me what it's used for?


  • Lifetime Qt Champion

    Hi,

    It's a custom macro based on the Creating Shared Libraries chapter in Qt's documentation.



  • Oh, OK, so I can probably skip it, then?


  • Lifetime Qt Champion

    If you have that class directly in your application project, yes.



  • @mzimmers Sorry I forgot to remove this keyword from my code.


  • Qt Champions 2017

    @mzimmers
    Just as a note.
    Very small small sample of delegate here.
    https://forum.qt.io/topic/96545/insert-fill-circle-into-cell-of-qtablewidget/8
    notice VRonin comment.



  • One more note: This QAbstractItemView *view = qobject_cast<QAbstractItemView *>(parent()); is unsafe as hell. Nothing says the delegate should be a child of the view. in fact you can use the same delegate in multiple views. the correct way to get the model is index.model() without passing from the view


  • Qt Champions 2017

    @VRonin said in want to add a graphic to a table:

    in fact you can use the same delegate in multiple views.

    You shouldn't though. There's a warning in the docs about it. I second your parent warning, however, it's quite correct as the view does not take ownership of the delegate.



  • @VRonin said in want to add a graphic to a table:

    One more note: This QAbstractItemView *view = qobject_cast<QAbstractItemView *>(parent()); is unsafe as hell. Nothing says the delegate should be a child of the view. in fact you can use the same delegate in multiple views. the correct way to get the model is index.model() without passing from the view

    Thanks for signaling the issue. I have fixed my sample code above.


Log in to reply
 

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