Qt图形视图框架:QGraphicsProxyWidget拖拽和移动(效果很完美)

#ifndef GRAPHICSPROXYWIDGET_H
#define GRAPHICSPROXYWIDGET_H

#include <QGraphicsProxyWidget>

class GraphicsProxyWidget : public QGraphicsProxyWidget
{
    Q_OBJECT
public:
    GraphicsProxyWidget(QGraphicsItem *parent = nullptr);
    void setCenterWidget(QWidget * w);
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;
    void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)override;
private:
    QSizeF itemSize;
    QSizeF itemMinSize;
    bool IsInResizeArea(const QPointF& pos);
    bool isResizing;
    QPointF dragPosition;
    bool grabbedByWidget;
};

#endif // GRAPHICSPROXYWIDGET_H
#include "graphicsproxywidget.h"
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsScene>
#include <QPainter>
#include <QStyleOptionGraphicsItem>

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

GraphicsProxyWidget::GraphicsProxyWidget(QGraphicsItem *parent)
    :QGraphicsProxyWidget(parent)
{
    setAcceptHoverEvents(true);
    setFlag(QGraphicsItem::ItemIsMovable);
    setFlag(QGraphicsItem::ItemSendsScenePositionChanges);//图形项可发送位置变化信号
    setFlag(QGraphicsItem::ItemIsSelectable);
    setFlag(QGraphicsItem::ItemIsFocusable);
    this->itemSize = QSizeF(100,100);
}

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

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

void GraphicsProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        QPointF pos = event->pos();
        if(IsInResizeArea(pos))
        {
            isResizing = true;
        }
        else
        {
            if (auto alienWidget = widget()->childAt(pos.toPoint()))
            {
                QGraphicsProxyWidget::mousePressEvent(event);
                grabbedByWidget = true;
            }
            else
            {
                QGraphicsItem::mousePressEvent(event);
                grabbedByWidget = false;
            }
        }
    }
}

void GraphicsProxyWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    if (auto alienWidget = widget()->childAt(event->pos().toPoint()))
    {
        QGraphicsProxyWidget::mouseDoubleClickEvent(event);
        grabbedByWidget = true;
    }
    else
    {
        QGraphicsItem::mouseDoubleClickEvent(event);
        grabbedByWidget = false;
    }
}

void GraphicsProxyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && isResizing)
        isResizing = false;
    else
    {
        if (grabbedByWidget)
            QGraphicsProxyWidget::mouseReleaseEvent(event);
        else
            QGraphicsItem::mouseReleaseEvent(event);
    }

    grabbedByWidget = false;
}

QVariant GraphicsProxyWidget::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)));
            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 GraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *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)
    {
        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();
    QGraphicsProxyWidget::paint(painter,option,widget);
}

void GraphicsProxyWidget::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
{
    if (isResizing || (IsInResizeArea(event->pos()) && isSelected()))
    {
        setCursor(Qt::SizeFDiagCursor);
        QGraphicsObject::hoverMoveEvent(event);
    }
    else
    {
        if (auto alienWidget = widget()->childAt(event->pos().toPoint()))
        {
            setCursor(alienWidget->cursor());
        }
        else
            setCursor(Qt::ArrowCursor);

        QGraphicsProxyWidget::hoverMoveEvent(event);
    }
}

void GraphicsProxyWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
    if (isResizing)
    {
        qreal w = event->pos().x();
        qreal h = event->pos().y();
        if (w > itemMinSize.width())
            itemSize.setWidth(w);
        if (h > itemMinSize.height())
            itemSize.setHeight(h);
        resize(w,h);
        prepareGeometryChange();
    }
    else
    {
        if (grabbedByWidget)
            return;
        QGraphicsItem::mouseMoveEvent(event);
    }
}

void GraphicsProxyWidget::setCenterWidget(QWidget * w)
{
    setWidget(w);
    itemSize = w->sizeHint();
    itemMinSize = w->minimumSize();
    update();
}

效果:

    QString style = "QPushButton{border-style: none;border: 0px;color: #FFFFFF;border-radius:6px;background: #00beac;font-size:22px;font-weight:bold;}"
                    "QPushButton:hover{background: #ff0000;}"
                    "QPushButton:pressed{background: #00ffff;}";
    QPushButton * btn = new QPushButton("GraphicsProxyWidget");
    btn->setCursor(Qt::PointingHandCursor);
    btn->setStyleSheet(style);

    QGroupBox *groupBox = new QGroupBox("group");
    QLabel *numberLabel = new QLabel("lable");
    QLineEdit *numberEdit = new QLineEdit;

    QFormLayout *layout = new QFormLayout;
    layout->addRow(numberLabel, numberEdit);
    layout->addRow(new QLabel("lable"), btn);
    groupBox->setLayout(layout);

    GraphicsProxyWidget *proxy = new GraphicsProxyWidget;
    proxy->setCenterWidget(groupBox);
    gphs->addItem(proxy);
    proxy->setPos(100,100);

    btn = new QPushButton("QGraphicsProxyWidget");
    btn->setCursor(Qt::PointingHandCursor);
    btn->setStyleSheet(style);

    groupBox = new QGroupBox("group");
    numberLabel = new QLabel("lable");
    numberEdit = new QLineEdit;

    layout = new QFormLayout;
    layout->addRow(numberLabel, numberEdit);
    layout->addRow(new QLabel("lable"), btn);
    groupBox->setLayout(layout);
    QGraphicsProxyWidget *proxy2 = new QGraphicsProxyWidget;
    proxy2->setWidget(groupBox);
    gphs->addItem(proxy2);
    proxy2->setPos(400,400);

下面的是QGraphicsProxyWidget作为对比。两者对于鼠标事件的响应看起来没有区别。效果完美\(^o^)/。

参考资料:Move QGraphicsProxyWidget

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值