【问题标题】:How can I change QGraphicsView background using check box如何使用复选框更改 QGraphicsView 背景
【发布时间】:2017-12-09 11:48:25
【问题描述】:

在这段代码中,它改变了QGraphicsView背景。现在我需要在检查真checkBox时更改背景。当我设置为checkBox以检查true时,我需要像这样设置背景代码。当我设置checkBox 来检查false。我需要将QGraphicsView 设置为正常的默认方式。我该怎么做。

这是我的代码:

ma​​inwindow.cpp

#include "mainwindow.h"
#include <QGraphicsTextItem>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    scene = new Scene(this);
    scene->setSceneRect(10,10,260,200);
    view = new QGraphicsView(scene);
    setCentralWidget(view);
}

ma​​inwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsView>
#include "scene.h"
#include "customrectitem.h"

class MainWindow : public QMainWindow
{
public:
    explicit MainWindow(QWidget *parent = 0);
private:
    QGraphicsView* view;
    QGraphicsScene* scene;
};

#endif // MAINWINDOW_H

Scene.h

#ifndef SCENE_H
#define SCENE_H

#include <QGraphicsScene>
#include <QPainter>
#include <QApplication>

class Scene : public QGraphicsScene
{
    Q_OBJECT
public:
    explicit Scene(QObject *parent = 0);
    int getGridSize() const {return this->gridSize;}

protected:
    void drawBackground (QPainter* painter, const QRectF &rect);
private:
    int gridSize;

};

#endif // SCENE_H

Scene.cpp

#include "scene.h"

Scene::Scene(QObject *parent) : QGraphicsScene(parent), gridSize(20)
{
    Q_ASSERT(gridSize > 0);
}

void Scene::drawBackground(QPainter *painter, const QRectF &rect)
{
        QColor c (10,140,255,155);
        painter->setPen(c);
        qreal left = int(rect.left()) - (int(rect.left()) % gridSize);
        qreal top = int(rect.top()) - (int(rect.top()) % gridSize);
        QVarLengthArray<QLineF,100> lines;
        for (qreal x = left; x < rect.right(); x += gridSize)
            lines.append(QLineF(x,rect.top(),x,rect.bottom()));

        for (qreal y = top; y < rect.bottom(); y += gridSize)
            lines.append(QLineF(rect.left(),y,rect.right(),y));
        painter->drawLines(lines.data(),lines.size());
}

【问题讨论】:

  • @eyllanesc 我尝试了您的解决方案,但我无法为我的项目设置该解决方案。我不明白如何解决它。这是我的项目link 请检查并给我一个解决方案先生。

标签: c++ qt background qt5 qgraphicsview


【解决方案1】:

@Scheff的解决方案虽然不错,但存在以下问题:

  • 第一种解决方案是只覆盖很小的空间,如果你改变QGraphicsView的大小,它不会覆盖所有的空间。

  • 第二种解决方案的问题是您使用的是viewport()坐标,而不是场景,如果您添加一个项目然后放大QGraphicsView而不移动该项目,那么您会看到一个滚动。

首字母:

改变大小后:

纠正这两个错误的解决方案是覆盖 QGraphicsScene 的drawBackground 方法:

#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H

#include <QGraphicsScene>
#include <QPainter>


class GraphicsScene: public QGraphicsScene{

    int mGridSize;
    QColor mGridColor;
    bool mGridVisible;

    Q_OBJECT
public:
    GraphicsScene(QObject *parent = Q_NULLPTR):QGraphicsScene(parent),
        mGridSize(20), mGridColor(0x0a8affu), mGridVisible(true)
    {

    }
    bool gridVisible() const {
        return mGridVisible;
    }
    void setGridVisible(bool gridVisible){
        if(mGridVisible != gridVisible){
            mGridVisible = gridVisible;
            update();
        }
    }
protected:
    void drawBackground(QPainter *painter, const QRectF &rect){
        if(mGridVisible) {
            QRect r = rect.toRect();
            int xmin  =r.left() - r.left()%mGridSize - mGridSize;
            int ymin = r.top() - r.top()%mGridSize - mGridSize;
            int xmax = r.right() - r.right()%mGridSize + mGridSize;
            int ymax = r.bottom() - r.bottom()%mGridSize + mGridSize;
            for(int x=xmin ; x <= xmax; x += mGridSize ){
                painter->drawLine(x, r.top(), x, r.bottom());
            }

            for(int y=ymin ; y <= ymax; y+= mGridSize ){
                painter->drawLine(r.left(), y, r.right(), y);
            }
        }
    }
};

#endif // GRAPHICSSCENE_H

这种方案的优点是不加载任何新的物体,而且图形在场景的坐标中,所以第二种方案没有位移。

首字母:

改变大小后:

完整的例子可以在下面的link找到

【讨论】:

  • 先生,我正在尝试将您的代码设置到我的项目中。但是有一些困难要做。所以在这里我附上我的项目链接。 link 请告诉我如何为我的项目执行此操作(您的答案)。
  • @Learner 我没有看到你已经实现了我的代码,试试吧,如果你失败了,那么在那一刻分享你尝试过的代码。
  • @Learner 必须实现mGridVisible is Scene,然后像我在main.cpp中那样连接到QCheckBox的stateChanged信号
  • 我更新了 github,当我尝试我的程序时,出现了这个错误消息。 The program has unexpectedly finished. 所以请检查我在这里做错了什么。我在使用复选框之前运行我的项目。
  • 我不知道你在做什么,我建议你阅读编程基础知识,这将是你最后一次工作,工作代码在以下链接中:ufile.io/u86ou
【解决方案2】:

我有两个机会画一个网格:

  1. QGraphicsView 派生一个类并重载paintEvent() 并在回退到QGraphicsView::paintEvent() 之前绘制网格

  2. QGraphicsItemGroup 下添加网格线作为场景项,以控制可见性。

第一种方法的优点是它可以无缝地适应任何视口的大小调整。

这是我的示例代码testQGraphicsView-BgGrid.cc

#include <QtWidgets>

class Canvas: public QGraphicsView {
  private:
    int _gridSize;
    QColor _gridColor;
    bool _gridVisible;

  public:
    explicit Canvas(QWidget *pQParent = nullptr):
      QGraphicsView(pQParent),
      _gridSize(20), _gridColor(0x0a8affu), _gridVisible(true)
    { }

    bool gridVisible() const { return _gridVisible; }
    void setGridVisible(bool gridVisible)
    {
      _gridVisible = gridVisible;
      viewport()->update();
    }

  protected:
    virtual void paintEvent(QPaintEvent *pQEvent) override
    {
      QPainter qPainter(viewport());
      if (_gridVisible) {
        const int wView = viewport()->width(), hView = viewport()->height();
        qPainter.setPen(_gridColor);
        for (int x = _gridSize / 2; x < wView; x += _gridSize) {
          qPainter.drawLine(x, 0, x, hView - 1);
        }
        for (int y = _gridSize / 2; y < hView; y += _gridSize) {
          qPainter.drawLine(0, y, wView - 1, y);
        }
      }
      QGraphicsView::paintEvent(pQEvent);
    }
};

void makeGrid(
  QGraphicsItemGroup &qItemGrp, const QSize &size,
  int gridSize = 20, const QColor &gridColor = 0x0a8affu)
{
  const int wView = size.width(), hView = size.height();
  for (int x = gridSize / 2; x < wView; x += gridSize) {
    QGraphicsLineItem *pQItem = new QGraphicsLineItem(x, 0, x, hView - 1);
    pQItem->setPen(gridColor);
    qItemGrp.addToGroup(pQItem);
  }
  for (int y = gridSize / 2; y < hView; y += gridSize) {
    QGraphicsLineItem *pQItem = new QGraphicsLineItem(0, y, wView - 1, y);
    pQItem->setPen(gridColor);
    qItemGrp.addToGroup(pQItem);
  }
}

int main(int argc, char **argv)
{
  QApplication app(argc, argv);
  // setup GUI
  QWidget qWnd;
  QGridLayout qGrid;
  QLabel qLblL(QString::fromUtf8("Grid as part of scene"));
  qGrid.addWidget(&qLblL, 0, 0);
  QCheckBox qTglGridL(QString::fromUtf8("Show Grid"));
  qGrid.addWidget(&qTglGridL, 0, 1);
  QGraphicsView qGraphView;
  qGrid.addWidget(&qGraphView, 1, 0, 1, 2);
  QLabel qLblR(QString::fromUtf8("Grid painted as background"));
  qGrid.addWidget(&qLblR, 0, 2);
  QCheckBox qTglGridR(QString::fromUtf8("Show Grid"));
  qGrid.addWidget(&qTglGridR, 0, 3);
  Canvas canvas;
  qGrid.addWidget(&canvas, 1, 2, 1, 2);
  qWnd.setLayout(&qGrid);
  qWnd.show();
  // init GUI
  QGraphicsScene qGraphSceneL;
  QGraphicsItemGroup qItemGrid;
  makeGrid(qItemGrid, qGraphView.viewport()->size());
  qGraphSceneL.addItem(&qItemGrid);
  qGraphView.setScene(&qGraphSceneL);
  qTglGridL.setCheckState(
    qItemGrid.isVisible() ? Qt::Checked : Qt::Unchecked);
  qTglGridR.setCheckState(
    canvas.gridVisible() ? Qt::Checked : Qt::Unchecked);
  // install signal handlers
  QObject::connect(&qTglGridL, &QCheckBox::stateChanged,
    [&qItemGrid](int state)
    {
      qItemGrid.setVisible(state != Qt::Unchecked);
    });
  QObject::connect(&qTglGridR, &QCheckBox::stateChanged,
    [&canvas](int state)
    {
      canvas.setGridVisible(state != Qt::Unchecked);
    });
  // runtime loop
  return app.exec();
}

使用 VS2013 和 Qt 5.9.2 编译,在 Window 10(64 位)上测试:


更新:

QMake 脚本testQGraphicsView-BgGrid.pro:

SOURCES = testQGraphicsView-BgGrid.cc

QT += widgets

在 cygwin 上的 bash 中构建和测试:

$ qmake-qt5 testQGraphicsView-BgGrid.pro

$ make
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQGraphicsView-BgGrid.o testQGraphicsView-BgGrid.cc
g++  -o testQGraphicsView-BgGrid.exe testQGraphicsView-BgGrid.o   -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread 

$ ./testQGraphicsView-BgGrid 

与 X11 应用程序相同的程序:


又一次更新:

我必须承认,在我的第一个版本中,我专注于 如何使用复选框更改 QGraphicsView 背景,重点是 复选框 忽略 QGraphicsScene::drawBackground() (我不知道)并忽略了网格渲染本身的问题(我使用了它)。正如eyllanesc's answer 中所指出的,这两种解决方案都存在一些(至少)我应该记录下来的弱点。

  1. 左视图(涉及到场景中的网格)不一定会填充viewport()。恕我直言,如果网格填充了场景使用的相关范围,这是可以接受的。 (这可能是为了形象化场景仅覆盖viewport() 的一部分。)但是,makeGrid() 的论点const QSize &amp;size 是关于此意图的不幸选择。我通过将其替换为 const QRect &amp;rect 来解决此设计问题。

  2. 右视图(重载paintEvent())没有考虑可能的场景滚动。我通过将左上角映射到场景坐标 (const QPointF offs = mapToScene(0, 0);) 来解决此问题,并将偏移量视为循环中的起始值。

更新示例代码testQGrapicsView-BgGrid.cc:

#include <QtWidgets>

class Canvas: public QGraphicsView {
  private:
    int _gridSize;
    QColor _gridColor;
    bool _gridVisible;

  public:
    explicit Canvas(QWidget *pQParent = nullptr):
      QGraphicsView(pQParent),
      _gridSize(20), _gridColor(0x0a8affu), _gridVisible(true)
    { }

    bool gridVisible() const { return _gridVisible; }
    void setGridVisible(bool gridVisible)
    {
      _gridVisible = gridVisible;
      viewport()->update();
    }

  protected:
    virtual void paintEvent(QPaintEvent *pQEvent) override
    {
      QPainter qPainter(viewport());
      if (_gridVisible) {
        const int wView = viewport()->width(), hView = viewport()->height();
        const QPointF offs = mapToScene(0, 0);
        qPainter.setPen(_gridColor);
        for (int x = (int)offs.x() % _gridSize; x < wView; x += _gridSize) {
          qPainter.drawLine(x, 0, x, hView - 1);
        }
        for (int y = (int)offs.y() % _gridSize; y < hView; y += _gridSize) {
          qPainter.drawLine(0, y, wView - 1, y);
        }
      }
      QGraphicsView::paintEvent(pQEvent);
    }
};

void makeGrid(
  QGraphicsItemGroup &qItemGrp, const QRect &rect,
  int gridSize = 20, const QColor &gridColor = 0x0a8affu)
{
  for (int x = rect.x(), xE = x + rect.width(); x < xE; x += gridSize) {
    QGraphicsLineItem *pQItem
      = new QGraphicsLineItem(x, rect.y(), x, rect.height() - 1);
    pQItem->setPen(gridColor);
    qItemGrp.addToGroup(pQItem);
  }
  for (int y = rect.y(), yE = y + rect.height(); y < yE; y += gridSize) {
    QGraphicsLineItem *pQItem
      = new QGraphicsLineItem(rect.x(), y, rect.width() - 1, y);
    pQItem->setPen(gridColor);
    qItemGrp.addToGroup(pQItem);
  }
}

int main(int argc, char **argv)
{
  QApplication app(argc, argv);
  // setup GUI
  QWidget qWnd;
  QGridLayout qGrid;
  QLabel qLblL(QString::fromUtf8("Grid as part of scene"));
  qGrid.addWidget(&qLblL, 0, 0);
  QCheckBox qTglGridL(QString::fromUtf8("Show Grid"));
  qGrid.addWidget(&qTglGridL, 0, 1);
  QGraphicsView qGraphView;
  qGrid.addWidget(&qGraphView, 1, 0, 1, 2);
  QLabel qLblR(QString::fromUtf8("Grid painted as background"));
  qGrid.addWidget(&qLblR, 0, 2);
  QCheckBox qTglGridR(QString::fromUtf8("Show Grid"));
  qGrid.addWidget(&qTglGridR, 0, 3);
  Canvas canvas;
  qGrid.addWidget(&canvas, 1, 2, 1, 2);
  qWnd.setLayout(&qGrid);
  qWnd.show();
  // init GUI
  QGraphicsScene qGraphSceneL;
  QGraphicsItemGroup qItemGrid;
  makeGrid(qItemGrid, QRect(0, 0, 320, 240));
  qGraphSceneL.addItem(&qItemGrid);
  qGraphView.setScene(&qGraphSceneL);
  qTglGridL.setCheckState(
    qItemGrid.isVisible() ? Qt::Checked : Qt::Unchecked);
  qTglGridR.setCheckState(
    canvas.gridVisible() ? Qt::Checked : Qt::Unchecked);
  // install signal handlers
  QObject::connect(&qTglGridL, &QCheckBox::stateChanged,
    [&qItemGrid](int state)
    {
      qItemGrid.setVisible(state != Qt::Unchecked);
    });
  QObject::connect(&qTglGridR, &QCheckBox::stateChanged,
    [&canvas](int state)
    {
      canvas.setGridVisible(state != Qt::Unchecked);
    });
  // runtime loop
  return app.exec();
}

以下快照显示了启动后和调整大小后的应用程序:

【讨论】:

  • 先生你能和我分享这个源代码吗?因为理解我有一些困难。你能与github分享源代码还是给我发邮件:slstore94@gmail.com
  • 格雷码框包含完整的C++源代码。唯一缺少的部分是 QMake 文件,因为我使用了 CMake 脚本。复制/粘贴它,你可以在你身边使用它。如果我没记错的话:在 SO 上发布的内容是公共领域。因此,请随意使用或更改它。
  • 在 cygwin 中安装 qmake 后,我能够测试一个 qmake 脚本并相应地更新了答案。
  • @eyllanesc 我更新了代码并记录了两种替代方案的优缺点。顺便提一句。我想使用QGraphicsScene::drawBackround() 似乎是“预期的方式”——我以前没有注意到。
猜你喜欢
  • 2011-09-24
  • 2020-05-19
  • 2017-06-15
  • 1970-01-01
  • 1970-01-01
  • 2021-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多