Как анимировать выделенный прямоугольник в QListView - PullRequest
0 голосов
/ 04 марта 2020

Прямоугольник на старом выбранном элементе должен перейти к текущему выбранному элементу, когда выбор был изменен. Я сделал это, но у меня есть проблемы.

  1. Использование SelectWidget дочерний виджет ListView. Прямоугольник, нарисованный в paintEvent из SelectWidget . Я изменяю геометрию (ось Y) на Выберите виджет , чтобы переместить его. Проблема заключается в том, что SelectWidget перекрывает текст элемента.
  2. Для решения проблемы # 1 я рисую прямоугольник в paint () функции ListItemDelegate , когда анимация закончена. Момент переключения между SelectWidget и stati c прямоугольник выбора элемента.

Как решить проблему № 1 и не получить проблему № 2.

Источник код:

listview.h

...
class SelectWidget;

class ListView : public QListView {

    Q_OBJECT
    Q_PROPERTY(int offset READ offset WRITE setOffset)

public:

    ListView(QWidget* parent = nullptr);

    void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override;

    int offset();

    void setOffset(int off);

    void animationFinished();

    bool canDrawSelected() const {
        return m_drawSelected;
    }

private:

    QPropertyAnimation* m_anim = nullptr;

    SelectWidget* m_selectWidget = nullptr;

    bool m_drawSelected = true;
};


class SelectWidget : public QWidget {

public:
    SelectWidget(QWidget* parent)
        : QWidget(parent)
    {

    }

    void paintEvent(QPaintEvent *event) override {

        if (!m_draw) return;

        QPainter painter(this);

        painter.setRenderHint(QPainter::Antialiasing);
        painter.setPen(Qt::NoPen);
        painter.setOpacity(0.5);
        painter.setBrush(QColor(47, 74, 90));
        painter.drawRect(QRectF(0, 0, width(), height()));

        QRectF lineRect(0, 0, 5, height());
        painter.setOpacity(1.0);
        painter.setBrush(QColor(0, 123, 255));
        painter.drawRect(lineRect);
    }

public:

    bool m_draw = true;
};

listview. cpp

...
ListView::ListView(QWidget *parent)
    : QListView(parent)
{
    setItemDelegate(new ListItemDelegate(this));

    m_selectWidget = new SelectWidget(this);

    m_anim = new QPropertyAnimation(this, "offset", this);

    connect(m_anim, &QPropertyAnimation::finished, this, &ListView::animationFinished);
}

void ListView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{

     m_selectWidget->m_draw = (selected.size() != 0);

    if (deselected.size() == 0) {
        if (selected.size() > 0) {
            setOffset(selected.indexes().begin()->row() *
                      itemDelegate(*selected.indexes().begin())->sizeHint(QStyleOptionViewItem(), QModelIndex()).height());
        }
        m_selectWidget->m_draw = false;
        return;
    }

    if (selected.size() > 0) {
        auto geom = m_selectWidget->geometry();
        geom.setWidth(visualRect(*selected.indexes().begin()).width());
        geom.setHeight(itemDelegate()->sizeHint(QStyleOptionViewItem(), QModelIndex()).height());
        m_selectWidget->setGeometry(geom);
    }

    if (deselected.indexes().begin()->row() == selected.indexes().begin()->row()) return;

    //move from deselected to selected

    int deselectedIndex = deselected.indexes().begin()->row();
    int selectedIndex = selected.indexes().begin()->row();

    m_anim->setStartValue(offset());
    m_anim->setEndValue(selectedIndex * itemDelegate(*selected.indexes().begin())->sizeHint(QStyleOptionViewItem(), QModelIndex()).height());
    m_anim->setDuration(100);
    m_anim->start();

    m_drawSelected = false;

}

int ListView::offset()
{
    return m_selectWidget->geometry().y();
}

void ListView::setOffset(int off)
{
    auto geometry = m_selectWidget->geometry();
    m_selectWidget->setGeometry(geometry.x(), off, geometry.width(), geometry.height());
    m_selectWidget->update();
}

void ListView::animationFinished()
{
    m_selectWidget->m_draw = false;
    m_drawSelected = true;

    m_selectWidget->update();
    update();
}

listitemdelegate . cpp

/* inherit QItemDelegate */
QSize ListItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const
{
    QSize itemSize(option.rect.size());
    itemSize.setHeight(35);
    return itemSize;
}


void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{

    if (index.column() != 0) {
        QItemDelegate::paint(painter, option, index);
        return;
    }

    QString text;

    QColor textColor = option.state & QStyle::State_Selected ? QColor(255, 255, 255) : QColor(255, 255, 255, 150);

    ListView* parentW = qobject_cast<ListView*>(parent());
    if (parentW->model()) {
        text = parentW->model()->data(index).toString();
    }

    painter->setRenderHint(QPainter::Antialiasing);

    if (option.state & QStyle::State_Selected) {
        if (parentW->canDrawSelected()) {
            painter->save();
            painter->fillRect(option.rect, QBrush(option.state & QStyle::State_MouseOver ? QColor(51, 82, 99) : QColor(47, 74, 90, 0.5 * 255)));

            QRectF lineRect;
            lineRect.setX(option.rect.x());
            lineRect.setY(option.rect.y());
            lineRect.setWidth(5);
            lineRect.setHeight(option.rect.height());
            painter->fillRect(lineRect, QBrush(QColor(0, 123, 255)));

            painter->restore();
        }
    }
    else if (option.state & QStyle::State_MouseOver) {
        painter->save();
        painter->fillRect(option.rect, QBrush(QColor(40, 60, 71)));
        painter->restore();
    }

    painter->save();
    painter->setPen(textColor);

    QRectF textRect(option.rect);
    textRect.setX(textRect.x() + 15);
    painter->drawText(textRect, Qt::AlignVCenter, text);

    painter->restore();

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...