强制重绘QGraphicsScene

时间:2016-06-02 22:51:21

标签: qt repaint qgraphicsview qgraphicsscene

我需要强制在视图内重新绘制QGraphicsScene - 整个视图 我在下面解释为什么我不能重新绘制具体项目,以及我尝试过的内容。

我有一个QGraphicsScene子类,用于绘制项目的“实际画布矩形” - 但是项目可以放在这个矩形之外,或者更大。
“实际画布矩形”可以调整大小,我也会在调整大小时调整它,因此(0,0)始终是(0,0)QGraphicsScene坐标的点。
我使调整大小足够重新绘制旧画布和新画布之间的最大矩形 我没有考虑在整个QGraphicsScene或画布外的任何项目上进行重绘,因为它是巨大的 - 并且项目可能遍布整个地方 - 并且因为初始应用程序也在视图中重新定位画布

此类是从QWidget旁边创建的QScrollArea引用的,该QGraphicsView已提升为包含该场景的 QList<QGraphicsView*> views = m_canvas->views(); if(views.size() > 0) { m_canvas->update(views.at(0)->rect()); // or QWidget* viewport = views.at(0)->viewport(); viewport->update(); // or QRectF r = views.at(0)->mapToScene(views.at(0)->rect()).boundingRect(); m_canvas->update(r); } 子类。

如果我在场景上放置一个大文本项目,并且我调整画布大小,我可以在左侧或右侧留下剩余的文本(取决于项目是否大于旧画布或新画布)。由于“移动”,通常增加画布大小会在左侧留下一个神器。

在画布上进行移动或缩放会进行重新绘制 - 但即使在场景中也不会显示。

我需要在重新调整后强制重新显示项,然后从技术上移动它。

我对视口更新感到满意,但我无法理解:尝试了几次:

#ifndef MYVIEW_H
#define MYVIEW_H

#include <QGraphicsView>
#include <QGraphicsScene>

class MyView : public QGraphicsView
{
public:
    MyView(QWidget *parent = 0) : QGraphicsView(parent) {
        setRenderHints(QPainter::Antialiasing |
                       QPainter::SmoothPixmapTransform);
        setCacheMode(CacheNone); // to avoid smear when panning very far
        setAutoFillBackground(true);
        setBackgroundRole(QPalette::Window);
        setViewportUpdateMode(SmartViewportUpdate);
        setTransformationAnchor(AnchorUnderMouse);
        setDragMode(ScrollHandDrag);
    }
};

class MyScene : public QGraphicsScene
{
public:
    explicit MyScene(const qreal sceneW, const qreal sceneH,
            const qreal canvasW, const qreal canvasH,
            QObject *parent = 0) : QGraphicsScene(parent) {
        m_actualCanvasRect = QRectF(0, 0, canvasW, canvasH);
        setSceneRect(0.5*(canvasW - sceneW), 0.5*(canvasH - sceneH), sceneW, sceneH);
    }

    void setCanvasSize(const qreal canvasW, const qreal canvasH) {
        setSceneRect(0.5*(canvasW - sceneRect().width()),
                     0.5*(canvasH - sceneRect().height()),
                     sceneRect().width(), sceneRect().height());
        qreal oldW = m_actualCanvasRect.width(),
              oldH = m_actualCanvasRect.height();
        m_actualCanvasRect = QRectF(0, 0, canvasW, canvasH);
        qreal updateW = qMax(oldW, canvasW);
        qreal updateH = qMax(oldH, canvasH);
        QRectF updateRect(0, 0, updateW, updateH);
        update(updateRect);
    }

protected:
    virtual void drawBackground(QPainter *painter, const QRectF &rect) {
        QGraphicsScene::drawBackground(painter, rect);
        QPen p(Qt::green);
        p.setWidth(5);   // this creates artifacts but lucky in my code i don't use a width
        painter->setPen(p);
        painter->setBrush(Qt::red);
        painter->drawRect(m_actualCanvasRect);
    }

private:
    QRectF m_actualCanvasRect;
};

#endif // MYVIEW_H

这些都不起作用。

由于坐标已经改变,我甚至不知道如何将项目的旧边界矩形映射到场景的新坐标。
这就是为什么我的想法,更新视图更简单 但是我必须做错事,因为剩下的画仍然存在。

我真正想要的是强制在整个视口上重绘场景 我怎么能这样做?

编辑 - 添加一个可以重现问题的程序。

  

myview.h

#ifndef TESTSCENE_H
#define TESTSCENE_H

#include <QWidget>
#include "myview.h"

namespace Ui {
class TestScene;
class MyScene;
class QGraphicsTextItem;
}

class TestScene : public QWidget
{
    Q_OBJECT

public:
    explicit TestScene(QWidget *parent = 0);
    ~TestScene();

private slots:
    void on_btnResize_clicked();

private:
    Ui::TestScene *ui;
    MyScene* s;
    QGraphicsTextItem* yyy;
};

#endif // TESTSCENE_H
  

testscene.h

#include "testscene.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TestScene w;
    w.show();

    return a.exec();
}
  

的main.cpp

#include "testscene.h"
#include "ui_testscene.h"

#include <QGraphicsTextItem>

TestScene::TestScene(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TestScene)
{
    ui->setupUi(this);

    qreal w = 300, h = 200;
    s = new MyScene(1000000, 1000000, w, h);
    ui->myView->setScene(s);

    yyy = new QGraphicsTextItem("Hello Great World");
    QFont fff("Arial", 34);
    yyy->setFont(fff);

    QSizeF sz = yyy->boundingRect().size();
    qreal cx = (w - sz.width())/2;
    qreal cy = (h - sz.height())/2;
    yyy->setPos(cx, cy);

    s->addItem(yyy);
}

TestScene::~TestScene()
{
    delete ui;
}

void TestScene::on_btnResize_clicked()
{
    bool ok;
    qreal w = ui->linWidth->text().toDouble(&ok);
    if(!ok || w <= 0) return;
    qreal h = ui->linHeight->text().toDouble(&ok);
    if(!ok || h <= 0) return;

    s->setCanvasSize(w, h);

    QSizeF sz = yyy->boundingRect().size();
    qreal cx = (w - sz.width())/2;
    qreal cy = (h - sz.height())/2;
    yyy->setPos(cx, cy);
}
  

testscene.cpp

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>TestScene</class>
 <widget class="QWidget" name="TestScene">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>649</width>
    <height>307</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>TestScene</string>
  </property>
  <widget class="QScrollArea" name="scrlArea">
   <property name="geometry">
    <rect>
     <x>60</x>
     <y>40</y>
     <width>471</width>
     <height>231</height>
    </rect>
   </property>
   <property name="lineWidth">
    <number>0</number>
   </property>
   <property name="verticalScrollBarPolicy">
    <enum>Qt::ScrollBarAlwaysOff</enum>
   </property>
   <property name="horizontalScrollBarPolicy">
    <enum>Qt::ScrollBarAlwaysOff</enum>
   </property>
   <property name="widgetResizable">
    <bool>true</bool>
   </property>
   <widget class="QWidget" name="scrollAreaWidgetContents">
    <property name="geometry">
     <rect>
      <x>0</x>
      <y>0</y>
      <width>469</width>
      <height>229</height>
     </rect>
    </property>
    <widget class="MyView" name="myView">
     <property name="geometry">
      <rect>
       <x>10</x>
       <y>10</y>
       <width>451</width>
       <height>211</height>
      </rect>
     </property>
     <property name="lineWidth">
      <number>0</number>
     </property>
     <property name="verticalScrollBarPolicy">
      <enum>Qt::ScrollBarAlwaysOff</enum>
     </property>
     <property name="horizontalScrollBarPolicy">
      <enum>Qt::ScrollBarAlwaysOff</enum>
     </property>
    </widget>
   </widget>
  </widget>
  <widget class="QPushButton" name="btnResize">
   <property name="geometry">
    <rect>
     <x>550</x>
     <y>50</y>
     <width>75</width>
     <height>23</height>
    </rect>
   </property>
   <property name="text">
    <string>Resize</string>
   </property>
  </widget>
  <widget class="QLineEdit" name="linWidth">
   <property name="geometry">
    <rect>
     <x>540</x>
     <y>90</y>
     <width>113</width>
     <height>20</height>
    </rect>
   </property>
  </widget>
  <widget class="QLineEdit" name="linHeight">
   <property name="geometry">
    <rect>
     <x>540</x>
     <y>130</y>
     <width>113</width>
     <height>20</height>
    </rect>
   </property>
  </widget>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <customwidgets>
  <customwidget>
   <class>MyView</class>
   <extends>QGraphicsView</extends>
   <header location="global">myview.h</header>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>
  

testscene.ui

setPos

要测试 - 启动后,设置大小40,30并查看工件。移动程序后设置更大的尺寸,工件将再次显示。

我已经意识到我可以在重新定位项目之后进行调整大小 - 并且由于某些奇怪的原因而处理工件(即使调整大小中调用的更新不包括整个项目边界矩形)。这与其他一些操作有冲突,但我可以让它发挥作用。

所以 - 我不再急于寻求解决方案,只是理解。为什么/如何在当前情况下强制重绘 - 在调整大小后使用项CREATE p1=(m:Movie {title:'M'})<-[:ACTED_IN {role:'R1'}]-(:Actor {name:'A1'}), p2 = (m)<-[:ACTED_IN {role:'R2'}]-(:Actor {name:'A2'}) WITH [p1,p2] as paths CALL apoc.convert.toTree(paths) YIELD value RETURN value -> {_id=0, _type=Movie, title=M, acted_in=[ {_id=1, _type=Actor, name=A1, acted_in.role=R1}, {_id=2, _type=Actor, name=A2, acted_in.role=R2}]}

0 个答案:

没有答案