无法从GraphicScene中选择自定义图形项

时间:2018-05-24 14:00:20

标签: c++ qt

在自定义绘图场景上绘制圆和圆弧后,我想选择圆弧。 奇怪的是,当我从侧面QTreeView(显示场景中存在的元素列表)中选择弧时,弧的选择工作正常但是我不能通过在场景上点击它来选择弧...

我无法确定问题的根源,因此任何有关此问题的方向都会受到欢迎:)

以下是一些实现的类的代码:

GraphicArcItem.cpp:

#include "graphicarcitem.h"
#include "state.h"
#include "link.h"
#include <QPainter>
#include <QDebug>
#include <QPen>
#include <QStyle>
#include <QStyleOption>

GraphicArcItem::GraphicArcItem(Link *link){
    setFlags(ItemIsMovable | ItemIsSelectable);
    setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
    m_link = link;
    setStartAngle(0);
    setSpanAngle(270 * 16);
    link->setArcView(this);
}

void GraphicArcItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *){
    QColor myLineColor = Qt::black;
    QPen pen(myLineColor);
        if (option->state & QStyle::State_Selected) {
        pen.setColor(Qt::blue);
        pen.setStyle(Qt::DashLine);
        pen.setWidth(2);
    }
    painter->setPen(pen);

    StateView* sview = m_link->getStart()->getStateView();
    QPointF top_left = mapFromItem(sview,
                        sview->getCenterEllipse());
    double x = top_left.rx() - 60.0 - 15.0;
    double y = top_left.ry() - 60.0 - 15.0;
    QRectF rectangle = QRectF(x,y,50.0,50.0);
    painter->drawArc(rectangle, startAngle(), spanAngle());
    x = top_left.rx() - 60.0 - 15.0 - 5;
    y = top_left.ry() - 60.0 - 15.0 - 5;
    QRectF rectangle2 = QRectF(x,y,60.0,60.0);
    painter->drawRect(rectangle2);
}

/*Return the center point of the arc in the parent coordinates*/
QPointF GraphicArcItem::getCenter(){
    int xCenter = rect().x() + rect().width()/2;
    int yCenter = rect().y() + rect().height()/2;
    QPointF center = QPointF(xCenter,yCenter);
    return center;
}

QRectF GraphicArcItem::boundingRect() const{
    StateView* sview = m_link->getStart()->getStateView();
    QPointF top_left = mapFromItem(sview,
                        sview->getCenterEllipse());
    double x = top_left.rx() - 60.0 - 15.0 - 5;
    double y = top_left.ry() - 60.0 - 15.0 - 5;
    QRectF rectangle = QRectF(x,y,60.0,60.0);
    qreal extra = (pen().width() + 50) / 2.0;
    return rectangle
         .normalized()
         .adjusted(-extra, -extra, extra, extra);
}

StateView.cpp:

#include "stateview.h"
#include "state.h"

#include <QGraphicsScene>
#include <QPen>
#include <QStyle>
#include <QStyleOption>

StateView::StateView(State *state, QRectF rect) : QGraphicsEllipseItem(rect){
    setFlags(ItemIsMovable | ItemIsSelectable);
    setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
    m_state = state;
    m_rectangle = rect;
    state->setStateView(this);
}
QPointF StateView::getCenterEllipse(){
    int xCenter = rect().x() + rect().width()/2;
    int yCenter = rect().y() + rect().height()/2;
    return QPointF(xCenter,yCenter);
}

QRectF StateView::boundingRect() const{
    qreal extra = (pen().width() + 50) / 2.0;
    return m_rectangle
         .normalized()
         .adjusted(-extra, -extra, extra, extra);
}

void StateView::paint(QPainter *painter,
              const QStyleOptionGraphicsItem *option,
              QWidget */*widget*/){
    QColor myOutlineColor = Qt::black;
    QColor myBackgroundColor = Qt::white;
    QPen pen(myOutlineColor);
    if (option->state & QStyle::State_Selected) {
        pen.setColor(Qt::blue);
        pen.setStyle(Qt::DashLine);
        pen.setWidth(2);
    }
    painter->setPen(pen);
    painter->setBrush(myBackgroundColor);
    painter->drawEllipse(m_rectangle.center(), 60,60);
    QString name = getState()->getName();
    painter->drawText(this->rect(), Qt::AlignCenter, name);
}

DrawingScene.cpp:

#include "drawingscene.h"

DrawingScene::DrawingScene(QObject *parent)
: QGraphicsScene(parent){
    m_mode = MoveItem;
    m_line = 0;
    m_number_states = 0;
}

/*
 * Creates the stateView element corresponding to the
 * state and adds it to the scene
*/
void DrawingScene::on_drawState(State *state){
    QRectF rectangle(80+ (150 * (m_number_states % 3)),
                 80 + (50 * ((m_number_states / 3) % 7)),
                 120.0, 120.0);
    StateView *sview = new StateView(state, rectangle);
    addItem(sview);
    ++m_number_states;
}
/*
 * Creates the linkView element corresponding to the
 * link and adds it to the scene
*/
void DrawingScene::on_drawLink(Link *link){
    if(link->getStart() == link->getEnd()){
        GraphicArcItem *lview = new GraphicArcItem(link);
        addItem(lview);
    }else{
        LinkView *lview = new LinkView(link);
        addItem(lview);
    }
}

void DrawingScene::mousePressEvent(QGraphicsSceneMouseEvent *event){
    if (m_mode == InsertLine){
        m_line = new QGraphicsLineItem(QLineF(event->scenePos(),
                                        event->scenePos()));
        m_line->setPen(QPen(QColor(Qt::black),2));
        addItem(m_line);
    }
    QGraphicsScene::mousePressEvent(event);
}

void DrawingScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
    if (m_mode == InsertLine && m_line != 0){
        QLineF newLine(m_line->line().p1(), event->scenePos());
        m_line->setLine(newLine);
    }else{
        QGraphicsScene::mouseMoveEvent(event);
    }
}

void DrawingScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
    if(m_line != 0 && m_mode == InsertLine){
        QList<QGraphicsItem *> startItems = items(m_line->line().p1());
        if (startItems.count() && startItems.first() == m_line){
            startItems.removeFirst();
        }
        QList<QGraphicsItem *> endItems = items(m_line->line().p2());
        if (endItems.count() && endItems.first() == m_line){
            endItems.removeFirst();
        }
        removeItem(m_line);
        delete m_line;

        if (startItems.count() > 0 && endItems.count() > 0){
            StateView *first = dynamic_cast<StateView *>(startItems.first());
            StateView *last = dynamic_cast<StateView *>(endItems.first());
            if(first && last){
                if(first != last){
                    emit createLink(first->getState(), last->getState());
                }else{
                    emit createLink(first->getState());
                }
            }
        }
    }
    m_line = 0;
    QGraphicsScene::mouseReleaseEvent(event);
}

以下是结果的一些图片:

提前感谢您的帮助或指导:) enter image description here enter image description here enter image description here

1 个答案:

答案 0 :(得分:0)

图形项不应该像在代码中一样依赖于彼此。它们应该是独立的,特别是关于边界框和绘图(可能是形状)。

相对位置是通过亲子关系实现的。

所以我建议你将你的弧项重新设计为独立于状态视图,并在需要时将其添加为状态视图的子项,并使用适当的偏移量。

边界矩形是项目位置周围的矩形,其中所有绘图都将发生(并且是命中测试的基础)。你如何抵消边界矩形并不重要,但惯例是,项目的位置是边界矩形的中心(例外:QGraphicsPixampItem),例如

void GraphicArcItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *){
    /* setup painter */

    QRectF rectangle = QRectF(-25.0,-25.0,50.0,50.0);
    painter->drawArc(rectangle, startAngle(), spanAngle());
    QRectF rectangle2 = QRectF(-30.0,-30.0,60.0,60.0);
    painter->drawRect(rectangle2);
}

QRectF GraphicArcItem::boundingRect() const{
    QRectF rectangle = QRectF(-30.0,-30.0,60.0,60.0);
    qreal extra = (pen().width() + 50) / 2.0;
    return rectangle
         .normalized()
         .adjusted(-extra, -extra, extra, extra);
}

添加弧时,将其创建为子项并根据需要进行偏移:

void DrawingScene::on_drawLink(Link *link){
    if(link->getStart() == link->getEnd()){
        GraphicArcItem *lview = new GraphicArcItem(link);
        lview->setParentItem(link->getStart()->getStateView());
        lview->setPos(-37.5,-37.5)
        addItem(lview);
    }else{
        /* ... */
    }
}

或者,您可以扩展arc的构造函数以获取父项并将其转发到基类(它将成为父类)。

请注意,我没有对此进行测试,并且该坐标可能已关闭