QGraphicsScene项目在两次(x2)位置绘制

时间:2019-07-19 19:08:56

标签: c++ qt qt5 qgraphicsscene

(警告发布在https://forum.qt.io/topic/105158/qgraphicsscene-item-is-drawn-at-twice-x2-position上)

在以下代码中,我将创建一个自定义窗口小部件,该窗口小部件中嵌入了QGraphicsScene的子类。我的目的是单击并在场景中添加一个点。一个点是我的QGraphicsItem(GIPoint)子类。我想移动该点,然后再将其连接到其他点并创建样条路径。

我面临的问题是,该点不是绘制在我单击的位置,而是绘制在通过将鼠标事件的scenePos()坐标加倍而形成的位置。因此,如果我单击(100,100),则点将绘制为(200,200)。我怀疑尽管阅读了文档,但我还是误解了坐标系。

问题How to add item in a QGraphicsScene?似乎相关,但是提出的通过mapToScene(event->pos());转换鼠标事件的坐标的解决方案实际上使位置翻了一番(在打印之前,它绘制在相同的位置,但随后会是x2。现在它也将其打印为x2)。

因此,我还想向我指出一些关于小部件放置方式的简单建议。顺便说一句是QRectF GIPoint::boundingRect() const { return QRectF(pos().x(), pos().y(), 5, 5); 关于矩形的(x,y)坐标是否正确?

我的示例代码如下:

/* use the following pro:
QT += widgets core gui

CONFIG += debug console
SOURCES = example.cpp
TARGET = example
*/
#include <QGraphicsItem>
#include <QPainter>
#include <QWidget>
#include <QRectF>
#include <QPointF>
#include <QGraphicsScene>
#include <QStyleOptionGraphicsItem>
#include <QGraphicsSceneMouseEvent>
#include <QKeyEvent>
#include <QGraphicsView>
#include <QApplication>
#include <QOpenGLWidget>
#include <QMainWindow>
#include <QGridLayout>
#include <QDebug>

class GIPoint : public QGraphicsItem{
public:
    GIPoint(QGraphicsItem * parent, const QPointF &position);
protected:
    QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
    QRectF boundingRect() const override;
    void paint(
        QPainter *painter,
        const QStyleOptionGraphicsItem *option,
        QWidget *widget
    );
};
class GraphicsSceneWidget : public QGraphicsScene {

public:
    explicit GraphicsSceneWidget(QObject *parent);
    ~GraphicsSceneWidget();
    virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
};

class VectorGraphicsWidget : public QWidget {
public:
    VectorGraphicsWidget(QWidget *parent);
    ~VectorGraphicsWidget();
private:
    GraphicsSceneWidget *myGraphicsSceneWidget;
};

// implementation
GIPoint::GIPoint(
    QGraphicsItem *parent,
    const QPointF &position
) : QGraphicsItem(parent) {
    setFlag(QGraphicsItem::ItemIsMovable, true);
    setFlag(QGraphicsItem::ItemIsSelectable, true);
    setPos(position);
    qWarning() << "GIPoint::GIPoint() : init at " << position;
}
QVariant GIPoint::itemChange(
    GraphicsItemChange change,
    const QVariant &value
){
    if (change == QGraphicsItem::ItemPositionChange) {
        qWarning("position changed");
    }
    return value;
}
QRectF GIPoint::boundingRect() const {
    return QRectF(pos().x(), pos().y(), 5, 5);
//  return QRectF(0,0, 5, 5);
}
void GIPoint::paint(
    QPainter *painter,
    const QStyleOptionGraphicsItem *option,
    QWidget *widget
){
    (void )option;
    (void )widget;
    QPointF xx = scenePos();
    QRectF rect = QRectF(xx.x(), xx.y(), 10, 10);
    qWarning() << "painting: scenePos " << scenePos() << ", rect " << rect;
    QBrush brush = QBrush(Qt::black, Qt::SolidPattern);
    //painter->fillRect(rect, brush);
    painter->drawRect(rect);
}

GraphicsSceneWidget::GraphicsSceneWidget(QObject *parent)
    : QGraphicsScene(parent)
{}
GraphicsSceneWidget::~GraphicsSceneWidget(){}
void GraphicsSceneWidget::mousePressEvent(
    QGraphicsSceneMouseEvent *event
){
    GIPoint *gip = new GIPoint(Q_NULLPTR, event->scenePos());
    addItem(gip);
    QGraphicsScene::mousePressEvent(event);
}

VectorGraphicsWidget::VectorGraphicsWidget(QWidget *parent) :
    QWidget(parent)
{
    myGraphicsSceneWidget = new GraphicsSceneWidget(this);
    QGraphicsView *view = new QGraphicsView(myGraphicsSceneWidget);
    myGraphicsSceneWidget->setSceneRect(QRectF(0, 0, 500, 500));
    QGridLayout *centralLayout = new QGridLayout;
    centralLayout->addWidget(view);
    setLayout(centralLayout);
    myGraphicsSceneWidget->addRect(
        QRectF(0, 0, 100, 100),
        QPen(Qt::black),
        QBrush(Qt::green)
    );
    view->show();
}
VectorGraphicsWidget::~VectorGraphicsWidget() {
    delete myGraphicsSceneWidget;
}
int main(int argc, char **argv){
    QApplication app(argc, argv);
    app.setApplicationName("test");
    app.setOrganizationName("myorg");
    app.setOrganizationDomain("myorg.com");

    QMainWindow *w = new QMainWindow();
    w->resize(500, 500);
    w->setCentralWidget(new VectorGraphicsWidget(Q_NULLPTR));
    w->show();

    return app.exec();
}

1 个答案:

答案 0 :(得分:1)

问题在于boundingRect()paint()方法尊重项目的坐标系,而不是场景。因此解决方案不是在两种方法中都使用scenePos(),而是使用0, 0

QRectF GIPoint::boundingRect() const {
    return QRectF(0, 0, 10, 10);
}
void GIPoint::paint(
    QPainter *painter,
    const QStyleOptionGraphicsItem *option,
    QWidget *widget
){
    (void )option;
    (void )widget;
    QRectF rect = QRectF(0, 0, 10, 10);
    qWarning() << "painting: scenePos " << scenePos() << ", rect " << rect;
    QBrush brush = QBrush(Qt::black, Qt::SolidPattern);
    painter->fillRect(rect, brush);
    painter->drawRect(rect);
}

尽管我建议使用QGraphicsRectItem来实现您所做的事情。