2016-11-17 683 views
0

我有一个自定义QGraphicsViewQGraphicsSceneQGraphicsScene我已经覆盖void drawBackground(QPainter *painter, const QRectF &rect)并基于布尔标志我想打开和关闭网格。我尝试拨打clear()或在我的功能中拨打paintereraseRect(sceneRect()),但它不起作用。所以在做了一些阅读之后,我想它不应该起作用,因为在改变场景之后,你需要刷新视图。这就是为什么我发了一个名为signalUpdateViewport()如何刷新QGraphicsView以显示QGraphicsScene背景中的更改

void Scene::drawBackground(QPainter *painter, const QRectF &rect) { 
    if(this->gridEnabled) { 
     // Draw grid 
    } 
    else { 
     // Erase using the painter 
     painter->eraseRect(sceneRect()); 
     // or by calling 
     //clear(); 
    } 

    // Trigger refresh of view 
    emit signalUpdateViewport(); 
    QGraphicsScene::drawBackground(painter, rect); 
} 

信号,然后通过我的观点捕获:

void View::slotUpdateViewport() { 
    this->viewport()->update(); 
} 

不用说,这没有奏效。与不起作用我的意思是,只有当更改窗口小部件,例如触发resize事件时,结果(从场景内部或视图内部刷新)才可见。

如何正确刷新视图以显示我在场景背景中所做的更改?

代码:

scene.h

#ifndef SCENE_HPP 
#define SCENE_HPP 

#include <QGraphicsScene> 

class View; 

class Scene : public QGraphicsScene 
{ 
    Q_OBJECT 
    Q_ENUMS(Mode) 
    Q_ENUMS(ItemType) 
    public: 
    enum Mode { Default, Insert, Select }; 
    enum ItemType { None, ConnectionCurve, ConnectionLine, Node }; 

    Scene(QObject* parent = Q_NULLPTR); 
    ~Scene(); 

    void setMode(Mode mode, ItemType itemType); 
    signals: 
    void signalCursorCoords(int x, int y); 

    void signalSceneModeChanged(Scene::Mode sceneMode); 
    void signalSceneItemTypeChanged(Scene::ItemType sceneItemType); 
    void signalGridDisplayChanged(bool gridEnabled); 

    void signalUpdateViewport(); 
    public slots: 
    void slotSetSceneMode(Scene::Mode sceneMode); 
    void slotSetSceneItemType(Scene::ItemType sceneItemType); 

    void slotSetGridStep(int gridStep); 
    void slotToggleGrid(bool flag); 
    private: 
    Mode sceneMode; 
    ItemType sceneItemType; 

    bool gridEnabled; 
    int gridStep; 

    void makeItemsControllable(bool areControllable); 
    double round(double val); 
    protected: 
    void mousePressEvent(QGraphicsSceneMouseEvent *event); 
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event); 
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); 
    void keyPressEvent(QKeyEvent *event); 

    void drawBackground(QPainter *painter, const QRectF &rect); 
}; 

Q_DECLARE_METATYPE(Scene::Mode) 
Q_DECLARE_METATYPE(Scene::ItemType) 

#endif // SCENE_HPP 

scene.cpp

#include <QGraphicsItem> 
#include <QGraphicsView> 
#include <QGraphicsSceneMouseEvent> 
#include <QPainter> 
#include <QRectF> 
#include <QKeyEvent> 

#include <QtDebug> 

#include "scene.h" 

Scene::Scene(QObject* parent) 
    : QGraphicsScene (parent), 
     sceneMode(Default), 
     sceneItemType(None), 
     gridEnabled(true), 
     gridStep(30) 
{ 

} 

Scene::~Scene() 
{ 
} 

void Scene::setMode(Mode mode, ItemType itemType) 
{ 
    this->sceneMode = mode; 
    this->sceneItemType = itemType; 

    QGraphicsView::DragMode vMode = QGraphicsView::NoDrag; 

    switch(mode) { 
    case Insert: 
    { 
     makeItemsControllable(false); 
     vMode = QGraphicsView::NoDrag; 
     break; 
    } 
    case Select: 
    { 
     makeItemsControllable(true); 
     vMode = QGraphicsView::RubberBandDrag; 
     break; 
    } 
    case Default: 
    { 
     makeItemsControllable(false); 
     vMode = QGraphicsView::NoDrag; 
     break; 
    } 
    } 

    QGraphicsView* mView = views().at(0); 
    if(mView) { 
    mView->setDragMode(vMode); 
    } 
} 

void Scene::slotSetSceneMode(Scene::Mode sceneMode) 
{ 
    this->sceneMode = sceneMode; 
    qDebug() << "SM" << (int)this->sceneMode; 
    emit signalSceneModeChanged(this->sceneMode); 
} 

void Scene::slotSetSceneItemType(Scene::ItemType sceneItemType) 
{ 
    this->sceneItemType = sceneItemType; 
    qDebug() << "SIT:" << (int)this->sceneItemType; 
    emit signalSceneItemTypeChanged(this->sceneItemType); 
} 

void Scene::slotSetGridStep(int gridStep) 
{ 
    this->gridStep = gridStep; 
} 

void Scene::slotToggleGrid(bool flag) 
{ 
    this->gridEnabled = flag; 
    invalidate(sceneRect(), BackgroundLayer); 
    qDebug() << "Grid " << (this->gridEnabled ? "enabled" : "disabled"); 
    update(sceneRect()); 
    emit signalGridDisplayChanged(this->gridEnabled); 
} 

void Scene::makeItemsControllable(bool areControllable) 
{ 
    foreach(QGraphicsItem* item, items()) { 
    if(/*item->type() == QCVN_Node_Top::Type 
     ||*/ item->type() == QGraphicsLineItem::Type 
     || item->type() == QGraphicsPathItem::Type) { 
     item->setFlag(QGraphicsItem::ItemIsMovable, areControllable); 
     item->setFlag(QGraphicsItem::ItemIsSelectable, areControllable); 
    } 
    } 
} 

double Scene::round(double val) 
{ 
    int tmp = int(val) + this->gridStep/2; 
    tmp -= tmp % this->gridStep; 
    return double(tmp); 
} 

void Scene::mousePressEvent(QGraphicsSceneMouseEvent *event) 
{ 
    QGraphicsScene::mousePressEvent(event); 
} 

void Scene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) 
{ 
    emit signalCursorCoords(int(event->scenePos().x()), int(event->scenePos().y())); 
    QGraphicsScene::mouseMoveEvent(event); 
} 

void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) 
{ 
    QGraphicsScene::mouseReleaseEvent(event); 
} 

void Scene::keyPressEvent(QKeyEvent* event) 
{ 
    if(event->key() == Qt::Key_M) { 
    slotSetSceneMode(static_cast<Mode>((int(this->sceneMode) + 1) % 3)); 
    } 
    else if(event->key() == Qt::Key_G) { 
    slotToggleGrid(!this->gridEnabled); 
    } 

    QGraphicsScene::keyPressEvent(event); 
} 

void Scene::drawBackground(QPainter *painter, const QRectF &rect) 
{ 
    // FIXME Clearing and drawing the grid happens only when scene size or something else changes 
    if(this->gridEnabled) { 
    painter->setPen(QPen(QColor(200, 200, 255, 125))); 
    // draw horizontal grid 
    double start = round(rect.top()); 
    if (start > rect.top()) { 
     start -= this->gridStep; 
    } 
    for (double y = start - this->gridStep; y < rect.bottom();) { 
     y += this->gridStep; 
     painter->drawLine(int(rect.left()), int(y), int(rect.right()), int(y)); 
    } 
    // now draw vertical grid 
    start = round(rect.left()); 
    if (start > rect.left()) { 
     start -= this->gridStep; 
    } 
    for (double x = start - this->gridStep; x < rect.right(); x += this->gridStep) { 
     painter->drawLine(int(x), int(rect.top()), int(x), int(rect.bottom())); 
    } 
    } 
    else { 
    // Erase whole scene's background 
    painter->eraseRect(sceneRect()); 
    } 

    slotToggleGrid(this->gridEnabled); 

    QGraphicsScene::drawBackground(painter, rect); 
} 

View目前没有任何内容 - 所有的默认值。我SceneView实例我QMainWindow内部的设置如下:

void App::initViewer() 
{ 
    this->scene = new Scene(this); 
    this->view = new View(this->scene, this); 
    this->viewport = new QGLWidget(QGLFormat(QGL::SampleBuffers), this->view); 
    this->view->setRenderHints(QPainter::Antialiasing); 
    this->view->setViewport(this->viewport); 
    this->view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); 
    this->view->setCacheMode(QGraphicsView::CacheBackground); 

    setCentralWidget(this->view); 
} 

编辑:我试着打电话给前update()clear()或任何我试图触发刷新(sceneRect()BackgroundLayer)无效。

我也尝试了QGraphicsScene::update()从场景中,但它没有工作传递两个没有参数的函数调用,然后传递sceneRect()没有导致任何不同,然后我已经在上面描述。

回答

0

发现问题 - 我忘了现场设置的矩形的大小:

this->scene->setSceneRect(QRectF(QPointF(-1000, 1000), QSizeF(2000, 2000))); 

我实际上是决定打印由sceneRect()调用返回的QRectF的大小发现问题,当我看着输出我看到0, 0所以基本上我确实触发了更新,但在面积为0的场景中(显然)不会导致任何结果。

另一件我测试过的工作是删除我的视图的背景缓存。

0

当你改变你的网格设置,无论是打开还是关闭(或颜色等),你需要调用QGraphicsScene :: update。这也是一个插槽,所以如果你愿意,你可以连接一个信号。您也可以指定曝光区域;如果你不这样做,那么它使用默认的一切。对于一个网格,这可能是你想要的。

您不需要清除网格。更新调用可确保更新的区域被清除,然后如果需要网格,则可以在其上绘制,或者如果网格不应该在网格上,则不要在其上绘制。

+0

我其实也尝试从场景中更新,但它没有工作(抱歉,我忘记在问题中提到它)。我尝试传递两个没有参数的函数调用,然后传递'sceneRect()',但都没有表现出与我在post中描述的问题不同的行为。顺便说一句,我使用OpenGL来渲染场景。这会对场景清除的方式产生任何影响吗? – rbaleksandar

+0

另外我尝试在update(),clear()或任何我试图触发刷新之前调用'invalidate(sceneRect(),BackgroundLayer)'。 – rbaleksandar

+0

我已经更新了一些代码,如果有帮助。 – rbaleksandar