Fra*_*sco 7 qt selection qgraphicsitem
我试图了解如何重新定义项目的选择和转换方式(一旦被选中)QGraphicsScene.例如,更改线条的长度,移动线条,通过移动其中一个点来更改多边形.
我创建了一个孩子QGraphicsView并且已经开始重载它mousePressEvent,但似乎选择和移动动作都被捕获了QGraphicsItem.我怎样才能覆盖它,因为它们受到保护而且从孩子身上看不到QGraphicsView?
我可以想象我需要QGraphicsItem::mousePressEvent在a中重载myGraphicsItem,但那意味着我还必须重载以QGraphicsScene进行处理myGraphicsItem?如何移动场景中的选定项目位置?
有什么我可以看的例子吗?
我(显然)有点失落.
更新:根据反馈,我创建了一个QGraphicsItems如下的孩子:
class baseGraphicItem : public QGraphicsItem
{
public:
explicit baseGraphicItem(QVector<QPoint> data, operationType shape, QObject * parent = 0);
signals:
public slots:
public:
virtual QRectF boundingRect() const;
virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
QPainterPath shape() const;
virtual void hoverEnterEvent ( QGraphicsSceneHoverEvent * event );
virtual void hoverLeaveEvent ( QGraphicsSceneHoverEvent * event );
private:
QPolygon vertex;
operationType shapeType;
};
baseGraphicItem::baseGraphicItem(QVector<QPoint> data, operationType shape, QObject *parent) :
QGraphicsItem(), vertex(data), shapeType(shape)
{
qDebug() << vertex;
this->setAcceptHoverEvents(false);
}
Run Code Online (Sandbox Code Playgroud)
这些是用于油漆boundingRect和形状.
void baseGraphicItem::paint(QPainter * painter, const QStyleOptionGraphicsItem*, QWidget*)
{
int i=0;
// Following needs better code for polygons
do painter->drawLine(vertex.at(i), vertex.at(i+1));
while (i++<vertex.size()-2);
}
QRectF baseGraphicItem::boundingRect() const
{
return vertex.boundingRect();
}
QPainterPath baseGraphicItem::shape() const
{
QPainterPath path;
path.addPolygon(vertex);
return path;
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,选择适用于一行或多边形.但是当一条线在多边形内时,它几乎总是选择多边形而不是线.这是因为它boundingRect的形状?另外,我如何获得存储在QPolygon顶点中的新坐标?谢谢
这完全取决于您重新定义"选择和转换项目的方式"的具体含义
我们以QGraphicsLineItem为例.
如果我希望这个项是可移动的,我可以调用它的函数setFlag(QGraphicsItem :: ItemIsMovable).现在可以在场景中单击并移动项目.当然,这假设该项是可选的,这可以通过设置标志QGraphicsItem :: ItemIsSelectable来实现.
现在,如果我想能够改变一条线的点,我可以使用它的setLine函数并继续重新定义线.但是,最好直接从QGraphicsItem继承并创建自己的.
class MyLine : public QGraphicsItem
{
Q_OBJECT
public:
virtual QRectF boundingRect();
virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
};
Run Code Online (Sandbox Code Playgroud)
所以这是我从QGraphicsItem继承的最低要求,因为boundingRect和paint函数在QGraphicsItem中是纯虚拟的.
那么,现在我们可以在课程中添加起点和终点: -
class MyLine : public QGraphicsItem
{
Q_OBJECT
public:
virtual QRectF boundingRect();
virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
private:
QPointF m_pointA;
QPointF m_pointB;
};
Run Code Online (Sandbox Code Playgroud)
接下来,类需要在paint函数中绘制自己:
void MyLine::paint(QPainter * painter, const QStyleOptionGraphicsItem* , QWidget*)
{
// The painter's pen and brush could be set here first
// Draw the line
painter->drawLine(m_pointA, m_pointB);
}
Run Code Online (Sandbox Code Playgroud)
完成此类的最后一件事是boundingRect函数,它表示类的可见区域: -
QRectF MyLine::boundingRect()
{
return QRectF(m_pointA, m_pointB);
}
Run Code Online (Sandbox Code Playgroud)
虽然这个类在功能上是完整的,你会发现当行是水平时边界矩形非常大,这在选择对象时是个问题,所以我们可以覆盖形状函数来解决这个问题.
QPainterPath MyLine::shape() const
{
QPainterPath path;
path.moveTo(m_pointA);
path.lineTo(m_pointB);
return path;
}
Run Code Online (Sandbox Code Playgroud)
现在我们有了自己的行类,我们可以添加mouseEvent处理程序: -
class MyLine : public QGraphicsItem
{
Q_OBJECT
public:
virtual QRectF boundingRect();
QPainterPath shape() const
virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event);
virtual void mousePressEvent(QGraphicsSceneMouseEvent * event);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * event);
private:
QPointF m_pointA;
QPointF m_pointB;
};
Run Code Online (Sandbox Code Playgroud)
使用事件处理程序,您需要在mouseMoveEvent中单击鼠标时进行存储.鼠标事件最接近的点(m_pointA或m_PointB)是您可以在mouseMoveEvent中移动和更新的点,直到调用mouseReleaseEvent.
如果mousePressEvent中的原始mouseEvent更接近中心,而不是其中一个点,则只需将事件转发给父类,即可移动整行.
当然,您可以将此作为带有点列表的多边形的模板,然后在绘画中绘制,添加到painterPath的形状并在鼠标事件中进行操作.