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):
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...
-
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
Here is an example of reimplementation of a QStyledItemDelegate drawing a progress bar usingQStyleOptionProgressBar
. 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));
-
Hi,
It's a custom macro based on the Creating Shared Libraries chapter in Qt's documentation.
-
If you have that class directly in your application project, yes.
-
@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 isindex.model()
without passing from the view -
@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 isindex.model()
without passing from the viewThanks for signaling the issue. I have fixed my sample code above.