如何使用复选框

时间:2017-12-09 11:48:25

标签: c++ qt background qt5 qgraphicsview

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

这是我的代码:

mainwindow.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);
}

mainwindow.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());
}

2 个答案:

答案 0 :(得分:2)

虽然@Scheff的解决方案很好,但它存在以下问题:

  • 第一个解决方案是它只覆盖一个小空间,如果你改变QGraphicsView的大小,它将无法覆盖所有空间。

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

初​​始:

enter image description here

更改尺寸后:

enter image description here

纠正这两个错误的解决方案是覆盖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

这个解决方案的优点是它不会加载任何新对象,除了图形位于场景的坐标中,因此第二个解决方案没有位移。

初​​始:

enter image description here

更改尺寸后:

enter image description here

完整示例可在以下link

中找到

答案 1 :(得分:1)

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

  1. QGraphicsView派生一个类并重载paintEvent()并绘制网格,然后再回到QGraphicsView::paintEvent()

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

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

    这是我的示例代码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位)上进行测试:

    snapshot of testQGraphicsView-BgGrid

    <强>更新

    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应用程序相同的程序:

    snapshot of testQGraphicsView-BgGrid (cygwin, X11)

    又一次更新:

    我承认,在我的第一个版本中,我专注于如何使用复选框更改QGraphicsView背景,重点是复选框忽略{{3 (我不知道)并忽略网格渲染本身的问题(我用它代替)。正如QGraphicsScene::drawBackground()所指出的,两者都表明解决方案提供了一些弱点,至少我应该记录这些弱点。

    1. 左视图(涉及网格到场景中)不一定会填充viewport()。恕我直言,如果网格填充场景使用的相关范围,这是可以接受的。 (这可能是为了可视化场景仅涵盖viewport()的一部分。)但是,const QSize &size的论证makeGrid()对于这个意图是一个不吉利的选择。我通过将其替换为const QRect &rect

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

    4. 更新示例代码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();
      }
      

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

      eyllanesc's answer

      snapshot of testQGraphicsView-BgGrid after start