Почему значок в QListWidget отображается только для первого элемента? - PullRequest
0 голосов
/ 19 сентября 2018

Цель: Я хочу, чтобы объект класса, унаследованный от 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);
}

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Причина

Вы рисуете прямоугольник и текст не в том месте:

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

, поскольку у вас нет информации, где их рисовать.

И выне имеют этой информации, потому что QGraphicsItem :: paint принимает QStyleOptionGraphicsItem в качестве второго аргумента, но вы передаете nullptr в своем вызове:

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

Solution

Создайте объект типа QStyleOptionGraphicsItem, настройте его и передайте методу paint.Затем используйте переданную информацию для рисования с painter в правильных местах.

Это позволит вам сделать дополнительные корректировки того, как выглядит украшение, в зависимости от QIcon :: Mode и QIcon :: 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, чтобы он соответствовал конкретным потребностям вашего приложения.

Результат

Как написано, данный пример дает следующий результат:

Window with QListWidget with three custom decorated items

0 голосов
/ 19 сентября 2018
QRectF MyItem::boundingRect() const
{
  return QRectF(0,0,w,h);
}

Я полагаю, что вы рисуете все свои блоки в одном верхнем левом углу.

...