最近一直在做和QGraphics绘图框架相关的项目,在项目中需要通过鼠标控制图元的大小及形状。 鉴于在Qt开发中可能会经常用到,现将源码贴上,以求与众程序猿共勉! 头文件: sizegripitem.h - #ifndef SIZEGRIPITEM_H
#define SIZEGRIPITEM_H #include <QGraphicsItem> #include <QGraphicsRectItem> class SizeGripItem : public QGraphicsItem { private: enum { Top = 0x1, Bottom = 0x2, Left = 0x4, TopLeft = Top | Left, BottomLeft = Bottom | Left, Right = 0x8, TopRight = Top | Right, BottomRight = Bottom | Right }; class HandleItem : public QGraphicsRectItem { public: HandleItem(int positionFlags, SizeGripItem* parent); int positionFlags() const; protected: virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); private: QPointF restrictPosition(const QPointF& newPos); int positionFlags_; SizeGripItem* parent_; QPointF startPos_ ; protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); }; public: class Resizer { public: virtual void operator()(QGraphicsItem* item, const QRectF& rect) = 0; }; SizeGripItem(Resizer* resizer, QGraphicsItem* parent, QRectF rect); virtual ~SizeGripItem(); virtual QRectF boundingRect() const; virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); virtual void setScale(qreal scale); void setTopLeft(const QPointF& pos); void setTop(qreal y); void setTopRight(const QPointF& pos); void setRight(qreal x); void setBottomRight(const QPointF& pos); void setBottom(qreal y); void setBottomLeft(const QPointF& pos); void setLeft(qreal x); void changeRect(const QRectF& rect); void setColor(const QColor& color); void resetColor(); private: void doResize(); void updateHandleItemPositions(); QList<HandleItem*> handleItems_; QRectF rect_; Resizer* resizer_; }; #endif // SIZEGRIPITEM_H
sizegripitem.cpp - #include <QBrush>
#include <QPen> #include "SizeGripItem.h" #include <QtWidgets> SizeGripItem::HandleItem::HandleItem(int positionFlags, SizeGripItem* parent) : QGraphicsRectItem(-3, -3, 6, 6, parent), positionFlags_(positionFlags), parent_(parent) { setBrush(QBrush(QColor(173, 224, 255))); setPen(QPen(QColor::fromRgb(40, 146, 201), 0)); setFlags(ItemSendsGeometryChanges | ItemIgnoresTransformations); switch (positionFlags_) { case TopLeft: case BottomRight: setCursor( Qt::SizeFDiagCursor ) ; break; case Right: case Left: setCursor( Qt::SizeHorCursor ) ; break; case TopRight: case BottomLeft: setCursor(Qt::SizeBDiagCursor); break; case Top: case Bottom: setCursor(Qt::SizeVerCursor); break; default: setCursor(Qt::ArrowCursor); break; } } int SizeGripItem::HandleItem::positionFlags() const { return positionFlags_; } void SizeGripItem::HandleItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { startPos_ = pos() ; event->accept() ; } else { event->ignore(); } } void SizeGripItem::HandleItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { QPointF currentParentPos = mapToParent( mapFromScene(event->scenePos()) );; QPointF buttonDownParentPos = mapToParent( mapFromScene(event->buttonDownScenePos(Qt::LeftButton))); setPos( startPos_ + currentParentPos - buttonDownParentPos ); event->accept() ; } else { event->ignore(); } } void SizeGripItem::HandleItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { event->accept() ; } else { event->ignore(); } } QVariant SizeGripItem::HandleItem::itemChange(GraphicsItemChange change, const QVariant &value) { QVariant retVal = value; if (change == ItemPositionChange) { retVal = restrictPosition(value.toPointF()); } else if (change == ItemPositionHasChanged) { QPointF pos = value.toPointF(); switch (positionFlags_) { case TopLeft: parent_->setTopLeft(pos); break; case Top: parent_->setTop(pos.y()); break; case TopRight: parent_->setTopRight(pos); break; case Right: parent_->setRight(pos.x()); break; case BottomRight: parent_->setBottomRight(pos); break; case Bottom: parent_->setBottom(pos.y()); break; case BottomLeft: parent_->setBottomLeft(pos); break; case Left: parent_->setLeft(pos.x()); break; } } return retVal; } QPointF SizeGripItem::HandleItem::restrictPosition(const QPointF& newPos) { QPointF retVal = pos(); if (positionFlags_ & Top || positionFlags_ & Bottom) retVal.setY(newPos.y()); if (positionFlags_ & Left || positionFlags_ & Right) retVal.setX(newPos.x()); if (positionFlags_ & Top && retVal.y() > parent_->rect_.bottom()) retVal.setY(parent_->rect_.bottom()); else if (positionFlags_ & Bottom && retVal.y() < parent_->rect_.top()) retVal.setY(parent_->rect_.top()); if (positionFlags_ & Left && retVal.x() > parent_->rect_.right()) retVal.setX(parent_->rect_.right()); else if (positionFlags_ & Right && retVal.x() < parent_->rect_.left()) retVal.setX(parent_->rect_.left()); return retVal; } SizeGripItem::SizeGripItem(Resizer* resizer, QGraphicsItem* parent, QRectF rect) : QGraphicsItem(parent), resizer_(resizer) { rect_ = rect; handleItems_.append(new HandleItem(TopLeft, this)); handleItems_.append(new HandleItem(Top, this)); handleItems_.append(new HandleItem(TopRight, this)); handleItems_.append(new HandleItem(Right, this)); handleItems_.append(new HandleItem(BottomRight, this)); handleItems_.append(new HandleItem(Bottom, this)); handleItems_.append(new HandleItem(BottomLeft, this)); handleItems_.append(new HandleItem(Left, this)); updateHandleItemPositions(); } SizeGripItem::~SizeGripItem() { if (resizer_) delete resizer_; } void SizeGripItem::changeRect(const QRectF& rect) { this->prepareGeometryChange(); rect_ = rect; updateHandleItemPositions(); this->update(); } QRectF SizeGripItem::boundingRect() const { QRectF r = rect_; //r.adjust(-5, -5, 5, 5); return r; } void SizeGripItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { painter->save(); QPen pen(QColor(40, 146, 201), 0, Qt::SolidLine); pen.setStyle(Qt::DashLine); painter->setBrush(Qt::transparent); painter->setPen(pen); painter->drawRect(rect_); painter->restore(); } void SizeGripItem::setScale(qreal scale) { //QGraphicsItem::setScale(1.0); } #define IMPL_SET_FN(TYPE, POS) void SizeGripItem::set ## POS (TYPE v) { prepareGeometryChange(); rect_.set ## POS (v); doResize(); } IMPL_SET_FN(qreal, Top) IMPL_SET_FN(qreal, Right) IMPL_SET_FN(qreal, Bottom) IMPL_SET_FN(qreal, Left) IMPL_SET_FN(const QPointF&, TopLeft) IMPL_SET_FN(const QPointF&, TopRight) IMPL_SET_FN(const QPointF&, BottomRight) IMPL_SET_FN(const QPointF&, BottomLeft) void SizeGripItem::doResize() { if (resizer_) { (*resizer_)(parentItem(), rect_); updateHandleItemPositions(); } } void SizeGripItem::updateHandleItemPositions() { foreach (HandleItem* item, handleItems_) { item->setFlag(ItemSendsGeometryChanges, false); switch (item->positionFlags()) { case TopLeft: item->setPos(rect_.topLeft()); break; case Top: item->setPos(rect_.left() + rect_.width() / 2 - 1, rect_.top()); break; case TopRight: item->setPos(rect_.topRight()); break; case Right: item->setPos(rect_.right(), rect_.top() + rect_.height() / 2 - 1); break; case BottomRight: item->setPos(rect_.bottomRight()); break; case Bottom: item->setPos(rect_.left() + rect_.width() / 2 - 1, rect_.bottom()); break; case BottomLeft: item->setPos(rect_.bottomLeft()); break; case Left: item->setPos(rect_.left(), rect_.top() + rect_.height() / 2 - 1); break; } item->setFlag(ItemSendsGeometryChanges, true); } } void SizeGripItem::setColor(const QColor& color){ foreach (HandleItem* item, handleItems_){ item->setBrush(QBrush(color)); item->update(); } } void SizeGripItem::resetColor(){ foreach (HandleItem* item, handleItems_){ item->setBrush(QBrush(Qt::green)); item->update(); } }
|
似水流年:对啊,但是你的绘制的图形基础不就是rect吗,不管你要绘制的是什么复杂图形,都是一句rect而来的,所以可以说是都支持啊。
2013-10-10 09:43