简体   繁体   English

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

[英]QGraphicsScene item is drawn at twice(x2) position

(warning crossposted on: https://forum.qt.io/topic/105158/qgraphicsscene-item-is-drawn-at-twice-x2-position ) (警告交叉发布: https ://forum.qt.io/topic/105158/qgraphicsscene-item-is-drawn-at-twice-x2-position)

In the following code I am creating a custom widget which has a subclass of QGraphicsScene embeded in it.在下面的代码中,我创建了一个自定义小部件,其中嵌入了 QGraphicsScene 的子类。 My aim is to click and add a point to the scene.我的目标是单击并向场景添加一个点。 A point is my subclass of QGraphicsItem (GIPoint).一个点是我的 QGraphicsItem (GIPoint) 的子类。 I want to move that point around and later connect it to other points and make a spline path.我想移动那个点,然后将它连接到其他点并制作样条路径。

The problem I am facing is that the point is not drawn at where I click but at a place which is formed by doubling the mouse-event's scenePos() coordinates.我面临的问题是该点不是在我单击的地方绘制的,而是在通过将鼠标事件的 scenePos() 坐标加倍而形成的地方绘制的。 So if I click at (100,100) the point is drawn at (200,200).因此,如果我在 (100,100) 处单击,该点将绘制在 (200,200) 处。 I suspect that I have misunderstood the coordinate system despite reading the documentation.尽管阅读了文档,我怀疑我误解了坐标系。

The question How to add item in a QGraphicsScene?问题如何在 QGraphicsScene 中添加项目? seems relevant but the proposed solution to transform the mouse-event's coordinates via mapToScene(event->pos());似乎相关,但建议的解决方案是通过mapToScene(event->pos());转换鼠标事件的坐标mapToScene(event->pos()); actually doubles up the position (before it will print that it draws on same position but it would then be x2. Now it also prints it as x2).实际上将位置加倍(在它打印之前它在相同的位置绘制,但它会是x2。现在它也将它打印为x2)。

So I am asking additionally to point me to some simple-to-digest advice on how the widgets placement works.所以我另外要求指出一些关于小部件放置如何工作的简单易懂的建议。 btw.顺便提一句。 is QRectF GIPoint::boundingRect() const { return QRectF(pos().x(), pos().y(), 5, 5);QRectF GIPoint::boundingRect() const { return QRectF(pos().x(), pos().y(), 5, 5); correct regarding the (x,y) coordinates of the rectangle?关于矩形的 (x,y) 坐标是否正确?

My example code follows:我的示例代码如下:

/* 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();
}

The problem is that the boundingRect() and the paint() methods is respect the coordinate system of the item, not the scene.问题是boundingRect()paint()方法尊重项目的坐标系,而不是场景。 So the solution is not to use scenePos() in both methods but 0, 0 :所以解决方案不是在这两种方法中都使用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);
}

Although I would recommend using QGraphicsRectItem as it implements what you have done.尽管我建议使用 QGraphicsRectItem 因为它实现了你所做的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM