首页 > 解决方案 > 拖动时QGraphicsPolygonItem不更新QPolygonF坐标

问题描述

我有一个自定义版本的 QGraphicsPolygonItem,它在这里定义:

#ifndef CUSTOMGPOLYGON_H
#define CUSTOMGPOLYGON_H

#include <QObject>
#include <QGraphicsPolygonItem>
#include <string>
#include <QGraphicsSceneMouseEvent>
#include <QMenu>
#include <QGraphicsTextItem>

class CustomGPolygon : public QObject, public QGraphicsPolygonItem
{
    Q_OBJECT
public:
    CustomGPolygon(QPolygonF poly, QObject *parent);
    ~CustomGPolygon();
    using QGraphicsPolygonItem::boundingRect;
    using QGraphicsPolygonItem::paint;

    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);

    QGraphicsTextItem *className;

private slots:
    void deletePolygon();
    void copyPolygon();


signals:
    void duplicatePoly(QPolygonF);

private:
    QMenu menu;

};

#endif // CUSTOMGPOLYGON_H

这是我的 CustomGPolygon 的 .cpp:

#include "customgpolygon.h"
#include <iostream>
CustomGPolygon::CustomGPolygon(QPolygonF poly, QObject *parent):QGraphicsPolygonItem(poly)
{
    menu.addAction("Copy", this, SLOT(copyPolygon()));
    menu.addAction("Delete", this, SLOT(deletePolygon()));

    connect(this, SIGNAL(duplicatePoly(QPolygonF)), parent, SLOT(drawPolygon(QPolygonF)));
}

CustomGPolygon::~CustomGPolygon()
{}

    void CustomGPolygon::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if(event->buttons() & Qt::LeftButton)
        {
        QGraphicsItem::mouseMoveEvent(event);

        QPolygonF poly = this->polygon();
        QPointF edgePoint(0,0);
        for(int i = 0; i<poly.size(); i++){
            if(poly.at(i).x() > edgePoint.x() && poly.at(i).y() > edgePoint.y())
            {
                edgePoint.setX(poly.at(i).x());
                edgePoint.setY(poly.at(i).y());
            }

        }
        this->className->setPos(edgePoint);
        }

}

void CustomGPolygon::deletePolygon()
{

    delete this;
}

void CustomGPolygon::copyPolygon()
{
    QPolygonF poly = this->polygon();
    emit duplicatePoly(poly);
}

要将这些多边形之一绘制到我的 QGraphicsScene 上,我在 mainwindow.cpp 中使用以下函数:

void MainWindow::drawPolygon(const QPolygonF &poly)
{
    CustomGPolygon *objectPt = new CustomGPolygon(poly, this);
    objectPt->setPen(pen);
    objectPt->setFlag(QGraphicsItem::ItemIsMovable);
    scene->addItem(objectPt);
    objectPt->className = textItem;
    map->drawing = false;
}

当我拖动这个绘制的多边形时,我需要更新 boundingRect 中向量的坐标——目前,他们没有这样做。

我尝试添加这些标志来解决问题:

objectPt->setFlag(QGraphicsItem::ItemSendsGeometryChanges);
objectPt->setFlag(QGraphicsItem::ItemSendsScenePositionChanges);

然而问题依然存在

标签: c++qt

解决方案


在item中设置的QPolygonF不是关于场景的坐标而是关于item的坐标,所以移动item不会改变QPolygonF。这类似于我们脸部的位置:如果道路相对于世界移动,但相对于我们自己不移动。因此,如果您想获得与场景相关的多边形,则必须使用 mapToScene() 方法进行转换。另一方面,如果要跟踪项目的位置,则不应使用 mouseMoveEvent() 而是 itemChange()。

另一方面,您对点的计算不正确,您应该比较的是基于某些度量的距离,例如欧几里得距离,因为例如,如果多边形位于负坐标位置,那么 edgePoint 将始终为 (0,0)。

考虑到上述情况,解决方案是:

#include <QtWidgets>

class CustomGPolygon: public QObject, public QGraphicsPolygonItem{
    Q_OBJECT
public:
    CustomGPolygon(QPolygonF poly, QObject *parent=nullptr):
        QObject(parent), QGraphicsPolygonItem(poly), className(nullptr){
        setFlag(QGraphicsItem::ItemIsMovable);
        setFlag(QGraphicsItem::ItemSendsGeometryChanges);
        menu.addAction("Copy", this, &CustomGPolygon::copyPolygon);
        menu.addAction("Delete", this,  &CustomGPolygon::deletePolygon);
        // if(parent)
        // connect(this, &CustomGPolygon:: SIGNAL(duplicatePoly(QPolygonF)), parent, SLOT(drawPolygon(QPolygonF)));
    }
    ~CustomGPolygon(){}
    QGraphicsTextItem *getClassName() const{return className;}
    void setClassName(QGraphicsTextItem *value){className = value;}
protected:
    QVariant itemChange(GraphicsItemChange change, const QVariant &value){
        if(change == GraphicsItemChange::ItemPositionChange && !polygon().isEmpty()){
            QPolygonF p = mapToScene(polygon());
            QPointF edgePoint = *std::max_element(p.begin(), p.end(),
                                                  [](const QPointF & x, const QPointF & y) -> bool
            {
                return QVector2D(x).length() > QVector2D(y).length();
            });
            if(className)
                className->setPos(edgePoint);
        }
        return QGraphicsPolygonItem::itemChange(change, value);
    }
private Q_SLOTS:
    void deletePolygon(){delete this;}
    void copyPolygon(){
        QPolygonF poly = mapToScene(polygon());
        Q_EMIT duplicatePoly(poly);
    }
Q_SIGNALS:
    void duplicatePoly(QPolygonF);
private:
    QGraphicsTextItem *className;
    QMenu menu;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsScene scene;
    QGraphicsView view(&scene);
    QPolygonF poly;
    poly << QPointF(0, 0) << QPointF(100, 0) << QPointF(100, 100);
    CustomGPolygon *item = new CustomGPolygon(poly);
    QGraphicsTextItem *textItem = new QGraphicsTextItem("Stack Overflow");
    scene.addItem(textItem);
    scene.addItem(item);
    item->setClassName(textItem);
    view.show();
    view.resize(640, 480);
    return a.exec();
}

#include "main.moc"

推荐阅读