PDA

View Full Version : How do I color a part of text in a QListView/QTableView



rawfool
30th May 2014, 11:28
If I have to change the color of a word inside the QListView, for example if in a string I get the word "outdated", how to change the color of that word alone ?



#include <QApplication>
#include <QListView>
#include <QStringListModel>

class CStringListModel : public QStringListModel
{
public:
CStringListModel()
{
;
}
QVariant data(const QModelIndex & index, int role) const
{
if(!index.isValid())
return QVariant();

int row = index.row();

switch(role)
{
case Qt::DisplayRole:
return this->stringList().at(row);
case Qt::ForegroundRole:
if(stringList().at(row).contains("outdated")) // But how to color the word "outdated" alone ?
return QBrush(Qt::red);
}

return QVariant();
}
};

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

QListView list;
CStringListModel * listModel = new CStringListModel;
listModel->setStringList(QStringList() << "Adobe Reader" << "Firefox" << "Windows XP (Outdated)" << "Skype"); // <-- 3rd item in the list
list.setModel(listModel);
list.setEditTriggers(QAbstractItemView::NoEditTrig gers);
list.show();

return a.exec();
}

Thank you.

anda_skoa
30th May 2014, 12:08
You will need your own custom delegete.

See QItemDelegate


Cheers,
_

rawfool
5th June 2014, 12:01
Thanks for the input. I tried using the same and almost got it, but with a minor (I guess) hiccup.

I tried to use the QItemDelegate, and I'm able to color the word of row which contains "(Outdated)" in red, but the rest part of the text is missing.

class CItemDelegate : public QItemDelegate
{
public:
CItemDelegate() { }
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
painter->save();

painter->setPen(Qt::NoPen);
if(option.state & QStyle::State_Selected)
{
painter->setBrush(Qt::lightGray);
}
else
{
painter->setBrush(Qt::white);
}
painter->drawRect(option.rect);

if(index.data().toString().contains("(Outdated)"))
{
painter->setPen(Qt::red);
painter->drawText(option.rect, "(Outdated)");
}
else
{
painter->setPen(Qt::black);
painter->drawText(option.rect, index.data().toString());
}

painter->restore();
}
};

My input string list is

QStringList stringList;
stringList << "Adobe Reader (Outdated)" << "CCleaner" << "Google Chrome" << "Firefox" << "Skype" << "Winamp (Outdated)";

What I'm seeing is
----------------------
(Outdated)
----------------------
CCleaner
----------------------
Google Chrome
----------------------
Firefox
----------------------
Skype
----------------------
(Outdated)
----------------------

Where am I doing wrong ?

I tried this also, but the row containing "(outdated)" is getting overlapped


if(index.data().toString().contains("(Outdated)"))
{
QStringList sList = index.data().toString().split(" "); // split by space character
for(int i = 0; i < sList.count(); i++)
{
if(sList.at(i).contains("Outdated"))
{
painter->setPen(Qt::red);
painter->drawText(option.rect, "(Outdated)");// I guess the problem lies with rect, but don't know what to do
}
else
{
painter->setPen(Qt::black);
painter->drawText(option.rect, sList.at(i));
}
}
}
else
{
painter->setPen(Qt::black);
painter->drawText(option.rect, index.data().toString());
}

anda_skoa
5th June 2014, 19:50
I am not sure what you mean.

In case that the data contains "(Outdated)" you are drawing "(Outdated)" in red.
If you want, for example "Adobe Reader", then you have to draw this as well.

QPainter:::drawText() can't draw anything it doesn't know about.

Cheers,
_

rawfool
6th June 2014, 07:40
Thanks for your help. I'm trying to draw the text and there by doing some mistake. So kindly help me in finding the RECTs for the texts


// Inside paint() function
if(index.data().toString().contains("(Outdated)"))
{
QStringList sList = index.data().toString().split(" "); // split by space character
for(int i = 0; i < sList.count(); i++)
{
if(sList.at(i).contains("Outdated"))
{
painter->setPen(Qt::red);
painter->drawText(option.rect, "(Outdated)");// <-------- rect ??
}
else
{
painter->setPen(Qt::black);
painter->drawText(option.rect, sList.at(i)); // <-------- This rect works fine if the input string has only one word.
}
}
}
else
{
painter->setPen(Qt::black);
painter->drawText(option.rect, index.data().toString());
}

anda_skoa
6th June 2014, 08:13
You are always drawing at the same position inside the loop.
You'll have to adjust the remaining space using the information on how much the last draw operation used.
There is a drawText() overload that has an output parameter for that.

However, since it looks like manual painting is too complicated for your current understanding of Qt/C++, maybe use a different approach.

Take the string, replace the word you want highlighted with a HTML snippet that contains the word and color markup and then hand that to a QTextDocument instance and let the text document do the painting.

See QTextDocument::setHtml() and QTextDocument::drawContents()


Cheers,
_