2016-11-17 687 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