代码在 http://download.csdn.net/detail/firebolt2002/8782273
一、给图形对象加控制点,用户通过鼠标来操作控制点来编辑图形,参考MFC drawcli的实现。
很多人通过QGraphicsItem的派生类,然后重载几个函数来处理鼠标消息:
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) Q_DECL_OVERRIDE;
void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) Q_DECL_OVERRIDE;
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvet) Q_DECL_OVERRIDE;
这种在图元对象内部处理鼠标消息的方法我使用过,感觉不太好用,主要是鼠标消息有时候收不到,操作比方麻烦。所以我现在通过派生一个QGraphicsScene对象,重载它的鼠标处理函数来操作图元对象,这样感觉更合理一些。
先来看看控制点对象,我从QtCreator里抄的:
下面看看图元对象。
//控制手柄的大小
enum { SELECTION_HANDLE_SIZE = 6, SELECTION_MARGIN = 10 };
enum SelectionHandleState { SelectionHandleOff, SelectionHandleInactive, SelectionHandleActive };
//通过QGraphicsRectItem派生,它本来就是个矩形嘛。
class SizeHandleRect :public QGraphicsRectItem
{ //控制点的操作方向。
enum Direction { None = -1 , LeftTop , Top, RightTop, Right, RightBottom, Bottom, LeftBottom, Left , Extra };
SizeHandleRect(QGraphicsItem* parent , Direction d, QGraphicsItem *resizable);
Direction dir() const { return m_dir; }
void updateCursor();
void setState(SelectionHandleState st);
bool hitTest( const QPointF & point );
void move(qreal x, qreal y );
protected:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
private:
const Direction m_dir;
QGraphicsItem *m_resizable;
SelectionHandleState m_state;
QColor borderColor;
};
<pre name="code" class="cpp">//手柄的绘制部分,挺简单,就是画个6x6的小矩形。
void SizeHandleRect::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
//不知道为啥,打开反走样后,如果加框,会很难看。
painter->setPen(Qt::NoPen);
painter->setBrush(QBrush(borderColor));
if ( m_dir >= Extend )
{
// painter->setBrush(QBrush("lightseagreen"));
//如果是额外的控制点,就画圈。
painter->drawEllipse(rect());
}else
painter->drawRect(rect());
}
//父对象状态改变,根据状态决定是否可见。
void SizeHandleRect::setState(SelectionHandleState st)
{
if (st == m_state)
return;
switch (st) {
case SelectionHandleOff:
hide();
break;
case SelectionHandleInactive:
case SelectionHandleActive:
show();
break;
}
m_state = st;
}
//检查是否选中。
bool SizeHandleRect::hitTest(const QPointF &point)
{
QPointF pt = mapFromScene(point);
bool result = rect().contains(pt);
return result;
}
//移动到指定的位置。
void SizeHandleRect::move(qreal x, qreal y)
{
setPos(x,y);
}
//使用QGraphicsObject做父类,主要是想利用一下它的元属性,这样可以做一个通用的属性编辑器,后来发现很鸡肋,QPen,QBrush居然不支持,还得自己写,用它就
不划算了。
class GraphicsBasicItem : public QGraphicsObject
{
Q_OBJECT
Q_PROPERTY(QColor pen READ penColor WRITE setPen )
Q_PROPERTY(QColor brush READ brush WRITE setBrush )
public:
explicit GraphicsBasicItem(QGraphicsItem * parent);
explicit GraphicsBasicItem(const QString &name ,QGraphicsItem *parent );
virtual ~GraphicsBasicItem();
QColor brush() const {return m_brush.color();}
QPen pen() const {return m_pen;}
QColor penColor() const {return m_pen.color();}
void setPen(const QPen & pen ) { m_pen = pen;}
void setBrush( const QBrush & brush ) { m_brush = brush ; }
protected:
QBrush m_brush;
QPen m_pen ;
};
//这个才图元对象。
class GraphicsItem : public GraphicsBasicItem
{
Q_OBJECT
public:
GraphicsItem(QGraphicsItem * parent );
enum {Type = UserType+1};
int type() const { return Type; }
//返回选中的控制点
virtual SizeHandleRect::Direction hitTest( const QPointF & point ) const;
//根据控制点当前的位置改变对象的大小。
virtual void resizeTo(SizeHandleRect::Direction dir, const QPointF & point );
//返回控制点的光标<span style="white-space:pre"> </span>
virtual Qt::CursorShape getCursor(SizeHandleRect::Direction dir );
//返回本地坐标
virtual QRectF rect() const { return m_localRect;}
//当释放鼠标完成size操作后,重建本地坐标。
virtual void changeSize () {}</span>
virtual void move( const QPointF & point ){}
int getHandleCount() const { return m_handles.count(