Qt - QGraphicsScene 和 QGraphicsView 不更新更改?

Posted

技术标签:

【中文标题】Qt - QGraphicsScene 和 QGraphicsView 不更新更改?【英文标题】:Qt - QGraphicsScene and QGraphicsView not updating changes? 【发布时间】:2017-03-28 08:35:29 【问题描述】:

我正在尝试一些看起来很容易的东西,但我有点挣扎。我希望能够在 GUI 中绘制矩形。我现在做的是:

我使用 Qt Designer 创建了一个 GUI,其中包含一个 QGraphicsView。

在我的主窗口中,我创建了一个 myGraphicsScene(派生自 QGraphicsScene 的类,但覆盖了鼠标按下、移动和释放事件)并将场景设置为在 UI 中创建的 QGraphicsView。

李>

问题是我在切换场景时无法正确控制视图的刷新和更新。

以下是代码的相关部分:

MainGUIWindow 构造函数和初始化:

MainGUIWindow::MainGUIWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainGUIWindow)


    ui->setupUi(this);
    _init();


void MainGUIWindow::_init()


    scene = new myGraphicsScene(ui->frame_drawing);
    scene->setSceneRect(QRectF(QPointF(-100, 100), QSizeF(200, 200)));

    ui->graphicsView->setScene(scene);
    QRect rect(10, 20, 80, 60);
    scene->addText("Hello world!");
    scene->addRect(rect, QPen(Qt::black), QBrush(Qt::blue));

我可以完美地看到 HelloWorld 文本和这个矩形。但是,当我从单击事件开始时,我无法再正确获取更新。

myGraphicsScene 类头:

#ifndef MYGRAPHICSSCENE_H
#define MYGRAPHICSSCENE_H

#include <QGraphicsScene>

class QGraphicsSceneMouseEvent;
class QPointF;
class QColor;

class myGraphicsScene : public QGraphicsScene

    Q_OBJECT

public:
    explicit myGraphicsScene(QObject *parent = 0);

public slots:

signals:

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
    void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) override;

private:
    QPen* pen;
    QBrush* brush;
    QRect* rect;
    QPoint* p1;
    QPoint* p2;

    bool firstClick;

    // bool startedRect;
;

#endif

myGraphicsScene 类实现:

#include "myGraphicsScene.h"

#include <QGraphicsSceneMouseEvent>
#include <QRect>

myGraphicsScene::myGraphicsScene(QObject *parent)
    : QGraphicsScene(parent)

    pen = new QPen(Qt::black);
    brush = new QBrush(Qt::blue);
    rect = 0;
    // startedRect = false;
    firstClick = true;



void myGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)

    if (mouseEvent->button() != Qt::LeftButton)
        return;


    // rect = new QRect((mouseEvent->scenePos()).toPoint(), (mouseEvent->scenePos()).toPoint());
    // addRect(*rect, *pen, *brush);
    // startedRect = true;

    if(firstClick)
    
        p1 = new QPoint((mouseEvent->scenePos()).toPoint());
        QRect tmp_rect(*p1, *p1);
        addRect(tmp_rect, *pen, *brush);
    
    else
    
        p2 = new QPoint((mouseEvent->scenePos()).toPoint());
        QRect tmp_rect(*p2, *p2);
        addRect(tmp_rect, *pen, *brush);
    
    QGraphicsScene::mousePressEvent(mouseEvent);


void myGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)

    // if(startedRect)
    // 
    //     rect->moveBottomRight((mouseEvent->scenePos()).toPoint());
    //     qDebug("Mouse Position: %d, %d", (mouseEvent->scenePos()).toPoint().x(), (mouseEvent->scenePos()).toPoint().y());
    //     qDebug("Rectangle BottomRight Position: %d, %d", rect->bottomRight().x(), rect->bottomRight().y());
    // 
    QGraphicsScene::mouseMoveEvent(mouseEvent);


void myGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)


    if (mouseEvent->button() != Qt::LeftButton)
        return;
    // rect = 0;
    // startedRect = false;
    if(firstClick)
    
        firstClick = false;
    
    else
    
        rect = new QRect(*p1, *p2);
        addRect(*rect, *pen, *brush);
        p1 = 0;
        p2 = 0;
        rect = 0;
        firstClick = true;
    
    QGraphicsScene::mouseReleaseEvent(mouseEvent);

我最初的想法是以拖放方式绘制矩形,但最终尝试了两次单击的方法,这种方法效果更好,但仍不能完全更新视图。

我是 Qt 的新手,所以我不太熟悉应该如何做。任何帮助将不胜感激,因为我在这里已经有一段时间了。

谢谢!

【问题讨论】:

首先按值存储QPenQBrush等。这将使代码更易于阅读和维护。其次,不要存储rectp1p2:你不需要它们。这些项目知道它们在哪里,您可以随时参考这些项目本身。您还需要按价值保留项目 - 只需在需要它们可见之前隐藏它们。 【参考方案1】:

在每个mouse*Event() 重载中,调用QGraphicsScene::update() 方法。它将在视图上安排重绘。

http://doc.qt.io/qt-5/qgraphicsscene.html#update

【讨论】:

我刚刚尝试过,它确实使我的两次单击方法明显更好,但拖放式绘图仍然不起作用。问题是我正在调试,正如您在注释代码中看到的那样,矩形确实改变了大小...... 这只适用于其他地方的基本问题。 QGraphicsScene::update() 几乎总是错误代码的统称。如果您需要使用它,那么在 99% 以上的情况下您都做错了。当你在场景中修改一个item时,item会通知场景变化,场景会通知任何view,view会重绘场景。不应该为此做任何额外的事情。如果你对一个项目做了一些事情并且它不是立即可见的,那么你没有做你认为你正在做的事情:这个项目不在场景中,或者被隐藏,或者你没有修改项目。【参考方案2】:

我刚刚找到了解决方案:我必须实际更改添加到场景中的项目,而不是矩形。所以,现在,我的代码看起来像:

#include "myGraphicsScene.h"

#include <QGraphicsSceneMouseEvent>
#include <QRect>
#include <QGraphicsRectItem>

myGraphicsScene::myGraphicsScene(QObject *parent)
    : QGraphicsScene(parent)

    pen = new QPen(Qt::black);
    brush = new QBrush(Qt::blue);

    tmp_rect = 0;
    startedRect = false;
    // firstClick = true;



void myGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)

    if (mouseEvent->button() != Qt::LeftButton)
        return;


    // Drag and drop approach

    startedRect = true;
    p1 = new QPointF(mouseEvent->scenePos());
    tmp_rect = new QRectF(*p1, *p1);
    // addRect(*tmp_rect, *pen, *brush);
    tmp_rect_item = new QGraphicsRectItem(*tmp_rect);
    rectangles.push_back(tmp_rect_item);
    addItem(rectangles.back());

    // Two-clicks approach
    // if(firstClick)
    // 
    //     p1 = new QPointF(mouseEvent->scenePos());
    //     tmp_rect_item = addRect(QRect(p1->toPoint(), p1->toPoint()), *pen, *brush); //save it to remove it after
    // 
    // else
    // 
    //     p2 = new QPointF(mouseEvent->scenePos());
    //     // QRect tmp_rect(*p2, *p2);
    //     // addRect(tmp_rect, *pen, *brush);
    // 


    update();
    QGraphicsScene::mousePressEvent(mouseEvent);


void myGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)

    if(startedRect)
    
        tmp_rect_item->setRect(QRectF(*p1, mouseEvent->scenePos()));
        qDebug("Mouse Position: %d, %d", (mouseEvent->scenePos()).toPoint().x(), (mouseEvent->scenePos()).toPoint().y());
        qDebug("Rectangle BottomRight Position: %d, %d", tmp_rect->bottomRight().x(), tmp_rect->bottomRight().y());
        update();
    
    QGraphicsScene::mouseMoveEvent(mouseEvent);


void myGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)


    if (mouseEvent->button() != Qt::LeftButton)
        return;

    // Drag and drop approach:

    tmp_rect = 0;
    startedRect = false;


    // Two-clicks approach

    // if(firstClick)
    // 
    //     firstClick = false;
    // 
    // else
    // 
    //     removeItem(tmp_rect_item);
    //     tmp_rect_item = new QGraphicsRectItem(QRectF(*p1, *p2));
    //     //            *tmp_rect, *pen, *brush);
    //     rectangles.push_back(tmp_rect_item);

    //     addItem(rectangles.back());
    //     p1 = 0;
    //     p2 = 0;
    //     tmp_rect = 0;
    //     firstClick = true;
    // 

    update();
    QGraphicsScene::mouseReleaseEvent(mouseEvent);

【讨论】:

【参考方案3】:

我发现的另一个有用的提示是,当我扩展视图时,我将鼠标事件处理程序置于“公共”而不是“受保护”之下。我进行了更改,调用始终如一。

【讨论】:

以上是关于Qt - QGraphicsScene 和 QGraphicsView 不更新更改?的主要内容,如果未能解决你的问题,请参考以下文章

Qt等待用户在QGraphicsScene中选择项目

QT:QGraphicsView QGraphicsScene QGraphicsItem理解

qt - 在 QGraphicsScene 中如何捕捉特定项目

简化 Qt 程序,我无法使用 QGraphicsScene 在 Qt 中显示图像

Qt - 如何将 QGraphicsScene 缩放到 QGraphicsView

Qt:QGraphicsScene 在我期望的时候没有更新