Target: I want the class object inherited from QGraphicsItem to be displayed as an icon in QListWidget.
Issue: In the list, the icon is displayed only for the first item.
how it looks
Tried to redefine the function QIconEngine:: pixmap, put a breakpoint on it, but the program does not go into it
Draw so
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setBrush(myColor);
painter->setPen(Qt::black);
painter->drawRect(boundingRect());
painter->drawText(QPointF(w / 2,h / 2),myStr);
}
For this I inherit from QIconEngine
class MyIconEngine : public QIconEngine
{
public:
MyIconEngine(MyItem* item);
// QIconEngine interface
public:
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override;
QIconEngine *clone() const override;
private:
MyItem* myItem;
};
Its implementation
MyIconEngine::MyIconEngine(MyItem* item): myItem(item)
{}
void MyIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
{
myItem->paint(painter,nullptr,nullptr);
}
QIconEngine *MyIconEngine::clone() const
{
return new MyIconEngine(myItem);
}
Use thus
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QListWidget* lw = new QListWidget();
int w = 45;
int h = 45;
lw->setIconSize(QSize(w,h));
MyItem* i1 = new MyItem(w,h,Qt::red,"red");
MyItem* i2 = new MyItem(w,h,Qt::green,"green");
MyItem* i3 = new MyItem(w,h,Qt::blue,"blue");
MyIconEngine* ie1 = new MyIconEngine(i1);
MyIconEngine* ie2 = new MyIconEngine(i2);
MyIconEngine* ie3 = new MyIconEngine(i3);
QIcon* icon1 = new QIcon(ie1);
QIcon* icon2 = new QIcon(ie2);
QIcon* icon3 = new QIcon(ie3);
QListWidgetItem* lwi1 = new QListWidgetItem(*icon1,i1->Str(),lw);
QListWidgetItem* lwi2 = new QListWidgetItem(*icon2,i2->Str(),lw);
QListWidgetItem* lwi3 = new QListWidgetItem(*icon3,i3->Str(),lw);
lw->show();
return a.exec();
}
MyItem.h
class MyItem : public QGraphicsItem
{
public:
MyItem(int width,int height, const QColor& color,const QString& text);
const QString& Str() const
{
return mySrt;
}
// QGraphicsItem interface
public:
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
private:
QColor myColor;
int w;
int h;
QString mySrt;
};
MyItem.cpp
MyItem::MyItem(int width, int height, const QColor &color,const QString& text):w(width),h(height),myColor(color),mySrt(text)
{}
QRectF MyItem::boundingRect() const
{
return QRectF(0,0,w,h);
}
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setBrush(myColor);
painter->setPen(Qt::black);
painter->drawRect(boundingRect());
painter->drawText(QPointF(w / 2,h / 2),mySrt);
}
You draw the rectangle and the text in the wrong place:
painter->drawRect(boundingRect());
painter->drawText(QPointF(w / 2,h / 2),mySrt);
since you do not have information where to draw them.
And you do not have this information, because QGraphicsItem::paint accepts a QStyleOptionGraphicsItem as a second argument, but you pass a nullptr
in your call:
myItem->paint(painter,nullptr,nullptr);
Create an object of type QStyleOptionGraphicsItem
, set it up and pass it to the paint
method. Then use the passed information to draw with the painter
in the correct places.
This will allow you to make further adjustments of how the decoration looks like, depending on the QIcon::Mode and QIcon::State.
Here is a minimal example I have created for you in order to demonstrate how you could implement the proposed solution:
Change your implementation of MyIconEngine::paint
like this:
void MyIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
{
QStyleOptionGraphicsItem option;
option.rect = rect;
if (mode == QIcon::Selected)
option.state = QStyle::State_Selected;
myItem->paint(painter, &option, nullptr);
}
Change your implementation of MyItem::paint
like this:
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setBrush(myColor);
painter->setPen(option->state == QStyle::State_Selected ? Qt::yellow : Qt::black);
painter->drawRect(option->rect);
painter->drawText(option->rect, mySrt, QTextOption(Qt::AlignCenter));
}
I took the liberty to extend the example a bit further than what you have asked in order to show you why using QStyleOptionGraphicsItem
is the right solution and how you can utilize it to achieve more.
This, i.e. painter->drawText(option->rect, mySrt, QTextOption(Qt::AlignCenter));
, will fix the problem with the text positioning as well.
Note: This example is created for demonstration purposes. You might want to make further adjustments to QStyleOptionGraphicsItem option
in order to make it suit the specific needs of your application.
As written, the given example produces the following result: