QT图形视图框架:自定义列表图形项

#ifndef LISTGRAPHICSPIXMAPITEM_H
#define LISTGRAPHICSPIXMAPITEM_H

#include <QGraphicsObject>

//列表图形项
class listGraphicsPixmapItem : public QGraphicsObject
{
    Q_OBJECT
public:
    listGraphicsPixmapItem(QString uuid,QGraphicsItem *parent = nullptr);
    void setTitle(QString title)
    {
        this->title = title;
    }
    void setContentList(const QStringList & list)
    {
        this->contentList = list;
    }
protected:
    QVariant itemChange(GraphicsItemChange change, const QVariant &value)override;
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)override;
    virtual QRectF boundingRect()const override;
    void mousePressEvent(QGraphicsSceneMouseEvent *event)override;
    void hoverMoveEvent(QGraphicsSceneHoverEvent* event)override;
    void mouseMoveEvent(QGraphicsSceneMouseEvent* event)override;
    void mouseReleaseEvent(QGraphicsSceneMouseEvent* event)override;
private:
    bool IsInResizeArea(const QPointF& pos);
    QSizeF itemSize;
    bool isResizing;  //是否正在改变大小的过程中
    QString uuid;
    QString title{"测试标题"};
    QStringList contentList;
    enum class pressBtnType //按下的是哪个按钮
    {
        previousPage = 0,
        nextPage,
        None
    };
    QRect pressedBtnRect[2];
    pressBtnType pressThisBtnType{pressBtnType::None};
    QVector<QRect> textListVector;
    int pressedTextRectIndex{-1};
    void onBtnPressed();
    int paintShowContentIndex{0};//当前绘制的首个列表项是contentList的第几个
    int nowPaintSize;//当前每页绘制的数目
    int nowPage{0};//当前页数
    int fullPages{0};//总页数
};

#endif // LISTGRAPHICSPIXMAPITEM_H
#include "listgraphicspixmapitem.h"
#include <QGraphicsScene>
#include <QDebug>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QGraphicsSceneMouseEvent>

const qreal g_cResizePos[] = {9, 6, 3};

listGraphicsPixmapItem::listGraphicsPixmapItem(QString uuid, QGraphicsItem *parent)
    :QGraphicsObject(parent)
{
    setAcceptHoverEvents(true);
    setFlag(QGraphicsItem::ItemIsMovable);
    setFlag(QGraphicsItem::ItemSendsScenePositionChanges);//图形项可发送位置变化信号
    setFlag(QGraphicsItem::ItemIsSelectable);
    setFlag(QGraphicsItem::ItemIsFocusable);
    this->uuid = uuid;
    this->itemSize = QSizeF(160,200);
    isResizing = false;
    setZValue(1);

    for (int i = 0;i < 100;++i)
    {
        contentList << QString("测试内容%1").arg(i);
    }
    paintShowContentIndex = 0;
}

QRectF listGraphicsPixmapItem::boundingRect() const
{
    return  QRectF(0, 0, itemSize.width() + 10, itemSize.height() + 10);
}

void listGraphicsPixmapItem::onBtnPressed()
{
    if(pressThisBtnType == pressBtnType::previousPage)
    {
        --nowPage;
        if(nowPage < 0)
            nowPage = 0;

        paintShowContentIndex = paintShowContentIndex - nowPaintSize;
    }
    else if(pressThisBtnType == pressBtnType::nextPage)
    {
        ++nowPage;
        if(nowPage > fullPages)
            nowPage = fullPages;

        paintShowContentIndex = paintShowContentIndex + nowPaintSize;
    }

    if(paintShowContentIndex > contentList.size() - 1)
        paintShowContentIndex = contentList.size() - 1;
    if(nowPage == 0)
        paintShowContentIndex = 0;

    qDebug()<<"当前页:"<<nowPage<<"当前绘制个数:"<<nowPaintSize<<"首个index"<<paintShowContentIndex;

    update();
}

void listGraphicsPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        if(IsInResizeArea(event->pos()))
            isResizing = true;

        QGraphicsObject::mousePressEvent(event);
        QPoint position = event->pos().toPoint();
        for (int i = 0;i < 2;++i)
        {
            if(pressedBtnRect[i].contains(position))
            {
                pressThisBtnType = static_cast<pressBtnType>(i);
                onBtnPressed();
                update();
                return;
            }
        }

        for (int i = 0;i < textListVector.size();++i)
        {
            if(textListVector[i].contains(position))
            {
                pressedTextRectIndex = i;
                update();
                return;
            }
        }

        return;
    }
    else if(event->button() == Qt::RightButton)
    {
        return;
    }
    return QGraphicsObject::mousePressEvent(event);
}

void listGraphicsPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
    if(pressThisBtnType != pressBtnType::None)
    {
        pressThisBtnType = pressBtnType::None;
        update();
    }

    if(pressedTextRectIndex != -1)
    {
        pressedTextRectIndex = -1;
        update();
    }

    if (event->button() == Qt::LeftButton && isResizing)
        isResizing = false;
    else
        QGraphicsObject::mouseReleaseEvent(event);
}

QVariant listGraphicsPixmapItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if ((change == ItemPositionChange || change == ItemPositionHasChanged) && scene()) // 控件发生移动
    {
        QPointF newPos = value.toPointF();
        QRectF rect(0, 0, scene()->width(), scene()->height());
        if (!rect.contains(newPos))//左上角
        {
            newPos.setX(qMin(rect.width(), qMax(newPos.x(), 0.0)));
            newPos.setY(qMin(rect.height(), qMax(newPos.y(), 0.0)));

//            newPos.setX(qMin(rect.right(), qMax(newPos.x(), rect.left())));
//            newPos.setY(qMin(rect.bottom(), qMax(newPos.y(), rect.top())));
            return newPos;
        }

        QRectF thisRectF = boundingRect();
        QPointF nowPos = QPointF(newPos.x() + thisRectF.width(),newPos.y());
        if(!rect.contains(nowPos))//右上角
        {
            newPos.setX(rect.width() - thisRectF.width());
            this->setPos(newPos);
            return newPos;
        }

        nowPos = QPointF(newPos.x(),newPos.y() + thisRectF.height());
        if(!rect.contains(nowPos))//左下角
        {
            newPos.setY(rect.height() - thisRectF.height());
            this->setPos(newPos);
            return newPos;
        }
    }
    return QGraphicsItem::itemChange(change, value);
}

void listGraphicsPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(widget);
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing,true);
    painter->setRenderHint(QPainter::SmoothPixmapTransform,true);
    painter->setRenderHint(QPainter::TextAntialiasing,true);

    QRectF thisRectF = boundingRect();
    if(option->state & QStyle::State_Selected)
    {
        painter->setPen(QColor("#D8D8D8"));
        painter->drawRect(thisRectF);
        setZValue(2);
    }
    else
    {
        setZValue(1);
        painter->fillRect(thisRectF, QBrush(Qt::transparent));
    }

    QRect rect = thisRectF.toRect();
    int titleHeight = rect.height()*0.15;

    QRect titleRect = QRect(0,0,rect.width(),titleHeight);
    painter->save();
    painter->drawRoundRect(thisRectF.adjusted(5,5,-5,-5));
    painter->restore();


    painter->save();
    if(!title.isEmpty())
    {
        painter->setPen(QColor("#333333"));
        QFont font = painter->font();
        font.setPixelSize(24);
        painter->setFont(font);
        painter->drawText(titleRect, Qt::AlignCenter, title);//在此区域的中间位置绘制文字
    }
    painter->restore();

    painter->save();
    QPen p;
    p.setWidth(2);
    p.setColor(QColor("#555555"));
    painter->setPen(p);

    painter->drawLine(QPoint(15,titleRect.bottomLeft().y()),
                      QPoint(titleRect.width() - 15,titleRect.bottomLeft().y()));
    painter->restore();

    painter->save();
    p.setWidth(1);
    p.setColor(QColor("#888888"));
    QFont font = painter->font();
    font.setPixelSize(20);
    painter->setFont(font);
    painter->setPen(p);
    int textListHeight = rect.height() * 0.65;//绘制区域的高度
    nowPaintSize = textListHeight / 40/* - 1*/; //每一项高40  当前绘制的个数
    fullPages = contentList.size() / nowPaintSize;// 总页数
//    if(contentList.size() % nowPaintSize != 0)//不能整除有余数
//    {
//        ++fullPages;
//    }

    QRect pressedTextRect;
    if(pressedTextRectIndex != -1)
    {
        pressedTextRect = textListVector[pressedTextRectIndex];
    }

    textListVector.clear();

    if(paintShowContentIndex <= contentList.size())
    {
        for (int i = paintShowContentIndex,j = 0;j < nowPaintSize && i < contentList.size();++i,++j)
        {
            QRect listRect = QRect(0,titleHeight + j * 40,rect.width(),40);
            painter->drawText(listRect, Qt::AlignCenter, contentList[i]);//在此区域的中间位置绘制文字
            painter->drawLine(QPoint(15,listRect.bottomLeft().y()),QPoint(listRect.width() - 15,listRect.bottomLeft().y()));
            textListVector << listRect;
        }
    }
    painter->restore();

    //拖动的时候nowPage 也要变化
    //前面的个数paintShowContentIndex,每页nowPaintSize个,
    nowPage = paintShowContentIndex / nowPaintSize;
    if(paintShowContentIndex % nowPaintSize != 0)
    {
        ++nowPage;
    }

    painter->save();
    QRect btnRect = QRect(0,rect.height() * 0.80,rect.width(),rect.height() * 0.2);
    int btnWidth = btnRect.width() * 0.15;
    int btnHeight = btnRect.height() * 0.5;
    int btnY = (btnRect.height() - btnHeight) / 2 + rect.height() * 0.80;
    pressedBtnRect[0] = QRect(btnRect.width() * 0.08 * 2 + btnWidth,btnY,btnWidth,btnHeight);
    pressedBtnRect[1] = QRect(btnRect.width() * 0.08 * 3 + btnWidth * 2,btnY,btnWidth,btnHeight);

    painter->setPen(QColor("#888888"));
    painter->drawRoundRect(pressedBtnRect[0],30,30);
    painter->drawRoundRect(pressedBtnRect[1],30,30);

    painter->setPen(QColor("#555555"));
    painter->drawText(pressedBtnRect[0],Qt::AlignCenter,QStringLiteral("<<"));
    painter->drawText(pressedBtnRect[1],Qt::AlignCenter,QStringLiteral(">>"));
    painter->restore();

    if(pressThisBtnType != pressBtnType::None)
    {
        painter->save();
        QColor slightlyOpaqueBlack(0, 0, 0, 63);
        painter->setBrush(slightlyOpaqueBlack);
        painter->setPen(Qt::transparent);
        painter->drawRoundRect(pressedBtnRect[static_cast<int>(pressThisBtnType)],30,30);
        painter->restore();
    }

    if(pressedTextRectIndex != -1)
    {
        painter->save();
        QColor slightlyOpaqueBlack(0, 0, 0, 63);
        painter->setBrush(slightlyOpaqueBlack);
        painter->setPen(Qt::transparent);
        painter->drawRect(pressedTextRect.adjusted(15,0,-15,0));
        painter->restore();
    }

    if(option->state & QStyle::State_Selected)
    {
        qreal w = thisRectF.width();
        qreal h = thisRectF.height();
        painter->setPen(Qt::red);
        for (int i = 0; i < 3; ++i)//三角形
            painter->drawLine(static_cast<int>(w - g_cResizePos[i]) , static_cast<int>(h), static_cast<int>(w), static_cast<int>(h - g_cResizePos[i]));
    }

    painter->restore();
}

void listGraphicsPixmapItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
{
    if (isResizing || (IsInResizeArea(event->pos()) && isSelected()))
        setCursor(Qt::SizeFDiagCursor);
    else
        setCursor(Qt::ArrowCursor);

    QGraphicsObject::hoverMoveEvent(event);
}

void listGraphicsPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
    if (isResizing)
    {
        qreal w = event->pos().x();
        qreal h = event->pos().y();
        if (w > 150)
            itemSize.setWidth(w);
        if (h > 150)
            itemSize.setHeight(h);
        prepareGeometryChange();
    }
    else
    {
        QGraphicsObject::mouseMoveEvent(event);
    }
}

bool listGraphicsPixmapItem::IsInResizeArea(const QPointF& pos)
{
    return (pos.x() - itemSize.width() + g_cResizePos[0]) > (itemSize.height() - pos.y());
}

效果:

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值