【问题标题】:Why the icon in QListWidget is displayed only for the first element?为什么 QListWidget 中的图标只显示第一个元素?
【发布时间】:2018-09-19 19:10:11
【问题描述】:

目标:我希望继承自 QGraphicsItem 的类对象在 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);
}

【问题讨论】:

  • 显示完整的课程MyItem
  • 什么是Str()
  • 编辑了问题
  • MyIconEngine::paint 接受 rect 作为参数。所有绘画都应在rect 内完成。而你忽略它。您绘制图标的局部坐标 (painter->drawRect(boundingRect());)。作为一个选项,您可以在将painter 的坐标系传递给myItem->paint(painter,nullptr,nullptr); 之前对其进行调整。使用painter->translate(rect.topLeft());
  • @scopchanov 你是完全正确的。

标签: c++ qt qicon


【解决方案1】:
QRectF MyItem::boundingRect() const
{
  return QRectF(0,0,w,h);
}

我相信你把所有的积木都画在同一个左上角。

【讨论】:

    【解决方案2】:

    原因

    你把矩形和文字画错地方了:

    painter->drawRect(boundingRect());
    painter->drawText(QPointF(w / 2,h / 2),mySrt);
    

    因为您不知道在哪里绘制它们。

    而您没有此信息,因为 QGraphicsItem::paint 接受 QStyleOptionGraphicsItem 作为第二个参数,但您在调用中传递了 nullptr

    myItem->paint(painter,nullptr,nullptr);
    

    解决方案

    创建QStyleOptionGraphicsItem 类型的对象,设置它并将其传递给paint 方法。然后使用传递的信息在正确的位置用painter绘制。

    这将允许您进一步调整装饰的外观,具体取决于QIcon::ModeQIcon::State

    示例

    这是我为您创建的一个最小示例,用于演示如何实施建议的解决方案:

    1. 像这样更改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);
      }
      
    2. 像这样更改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 进行进一步调整,以使其适合您的应用程序的特定需求。

    结果

    正如所写,给定的示例产生以下结果:

    【讨论】:

    • 非常感谢
    猜你喜欢
    • 2018-10-07
    • 1970-01-01
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    • 1970-01-01
    • 2017-09-18
    • 2022-11-22
    • 1970-01-01
    相关资源
    最近更新 更多