为什么QListWidget中的图标只显示第一个元素?
Why the icon in QListWidget is displayed only for the first element?
目标: 我希望从 QGraphicsItem 继承的 class 对象在 QListWidget 中显示为图标。
问题:在列表中,仅第一项显示图标。
外观如何
试图重新定义函数QIconEngine::pixmap,在上面打了断点,但是程序没有进去
画成这样
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);
}
为此我继承自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;
};
其实施
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);
}
这样使用
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);
}
QRectF MyItem::boundingRect() const
{
return QRectF(0,0,w,h);
}
我相信你在同一个左上角画了所有的块。
原因
您在错误的位置绘制了矩形和文本:
painter->drawRect(boundingRect());
painter->drawText(QPointF(w / 2,h / 2),mySrt);
因为你不知道在哪里绘制它们。
而您没有此信息,因为 QGraphicsItem::paint accepts a QStyleOptionGraphicsItem 作为第二个参数,但您在调用中传递了 nullptr
:
myItem->paint(painter,nullptr,nullptr);
解决方案
创建一个 QStyleOptionGraphicsItem
类型的对象,对其进行设置并将其传递给 paint
方法。然后使用传递的信息在正确的位置绘制painter
。
这将允许您进一步调整装饰的外观,具体取决于 QIcon::Mode and QIcon::State。
例子
这是我为您创建的一个最小示例,用于演示如何实施建议的解决方案:
像这样更改 MyIconEngine::paint
的实现:
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);
}
像这样更改 MyItem::paint
的实现:
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));
}
我冒昧地将示例扩展得比您所要求的更进一步,以便向您展示为什么使用 QStyleOptionGraphicsItem
是正确的解决方案,以及您如何利用它来实现更多目标。
这,即 painter->drawText(option->rect, mySrt, QTextOption(Qt::AlignCenter));
,也将解决文本定位问题。
注意:创建此示例用于演示目的。您可能需要进一步调整 QStyleOptionGraphicsItem option
以使其适合您的应用程序的特定需求。
结果
如所写,给定的示例产生以下结果:
目标: 我希望从 QGraphicsItem 继承的 class 对象在 QListWidget 中显示为图标。
问题:在列表中,仅第一项显示图标。
外观如何
试图重新定义函数QIconEngine::pixmap,在上面打了断点,但是程序没有进去
画成这样
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);
}
为此我继承自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;
};
其实施
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);
}
这样使用
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);
}
QRectF MyItem::boundingRect() const
{
return QRectF(0,0,w,h);
}
我相信你在同一个左上角画了所有的块。
原因
您在错误的位置绘制了矩形和文本:
painter->drawRect(boundingRect());
painter->drawText(QPointF(w / 2,h / 2),mySrt);
因为你不知道在哪里绘制它们。
而您没有此信息,因为 QGraphicsItem::paint accepts a QStyleOptionGraphicsItem 作为第二个参数,但您在调用中传递了 nullptr
:
myItem->paint(painter,nullptr,nullptr);
解决方案
创建一个 QStyleOptionGraphicsItem
类型的对象,对其进行设置并将其传递给 paint
方法。然后使用传递的信息在正确的位置绘制painter
。
这将允许您进一步调整装饰的外观,具体取决于 QIcon::Mode and QIcon::State。
例子
这是我为您创建的一个最小示例,用于演示如何实施建议的解决方案:
像这样更改
MyIconEngine::paint
的实现: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); }
像这样更改
MyItem::paint
的实现: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)); }
我冒昧地将示例扩展得比您所要求的更进一步,以便向您展示为什么使用 QStyleOptionGraphicsItem
是正确的解决方案,以及您如何利用它来实现更多目标。
这,即 painter->drawText(option->rect, mySrt, QTextOption(Qt::AlignCenter));
,也将解决文本定位问题。
注意:创建此示例用于演示目的。您可能需要进一步调整 QStyleOptionGraphicsItem option
以使其适合您的应用程序的特定需求。
结果
如所写,给定的示例产生以下结果: