#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^)/。