how to avoid paintevent() being called when the wi

2019-07-21 14:38发布

i want to draw some rhombuses with random colors in a Qwidget. The widget should be repainted only when the window is resized .The problem is that when the widget was obscured and has now been uncovered , it is repainted. How can i avoid calling paintEvent() in this case? Thanks in advance.

void Dialog::paintEvent(QPaintEvent *e)
{
    QPainter painter(this);
    QRect background(0,0,this->geometry().width(),this->geometry().height());

    painter.setBrush( QBrush( Qt::white ) );
    painter.setPen( Qt::NoPen );
    // QBrush bbrush(Qt::black,Qt::SolidPattern);
    painter.drawRect(background);

    int width = this->geometry().width();
    int height = this->geometry().height();
    int rec_size=64;
    int rows=floor((double)height/(double)rec_size);
    int cols=floor((double)width/(double)rec_size);

    QPointF points[4];

    for (int i=0;i<floor(rows);i++)
    {
        for (int j=0;j<floor(cols);j++)
        {
            painter.setBrush( QBrush( colors[rand() % color_size] ) );

            points[0] = QPointF(rec_size*(j),rec_size*(i+0.5));
            points[1] = QPointF(rec_size*(j+0.5),rec_size*(i));
            points[2] = QPointF(rec_size*(j+1),rec_size*(i+0.5));
            points[3] = QPointF(rec_size*(j+0.5),rec_size*(i+1));

            painter.drawPolygon(points, 4);
        }
    }
}

标签: c++ qt qt4 qt5
1条回答
欢心
2楼-- · 2019-07-21 14:53

You are presupposing a solution, where in fact you should be focusing on the problem instead. Your problem isn't about when paintEvent is called. Qt's semantics are such that the paintEvent can be called at any time in the main thread. You must cope with it.

What you need to do, instead, is store the randomized colors in a container, to re-use them when painting. In the example below, the colors are generated on demand, and are stored in a dynamically growing list indexed by row and column. This way when you resize the widget, the colors of the existing items don't have to change. You can then regenerate the colors at any time by simply clearing the container and forcing an update.

The example below allows you to select whether to preserve the colors during resizing.

The code uses Qt 5 and C++11. Note that the use of rand() % range is discouraged in modern code - it doesn't preserve the uniformity of the distribution.

screenshot

#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QCheckBox>
#include <QGridLayout>
#include <QPainter>
#include <random>

std::default_random_engine rng;

class Dialog : public QWidget {
   Q_OBJECT
   Q_PROPERTY(bool recolorOnResize READ recolorOnResize WRITE setRecolorOnResize)
   QList<QColor> m_palette;
   QList<QList<QColor>> m_chosenColors;
   bool m_recolorOnResize;
   void paintEvent(QPaintEvent *) {
      QPainter p(this);
      p.fillRect(rect(), Qt::white);
      p.setRenderHint(QPainter::Antialiasing);

      int rec_size=64;
      int rows=height()/rec_size;
      int cols=width()/rec_size;
      std::uniform_int_distribution<int> dist(0, m_palette.size()-1);
      while (m_chosenColors.size() < rows) m_chosenColors << QList<QColor>();
      for (QList<QColor> & colors : m_chosenColors)
         while (colors.size() < cols)
            colors << m_palette.at(dist(rng));

      QPointF points[4];
      for (int i=0; i<rows; i++) {
         for (int j=0; j<cols; j++) {
            points[0] = QPointF(rec_size*(j),rec_size*(i+0.5));
            points[1] = QPointF(rec_size*(j+0.5),rec_size*(i));
            points[2] = QPointF(rec_size*(j+1),rec_size*(i+0.5));
            points[3] = QPointF(rec_size*(j+0.5),rec_size*(i+1));
            p.setBrush(m_chosenColors[i][j]);
            p.drawPolygon(points, 4);
         }
      }
   }
   void resizeEvent(QResizeEvent *) {
      if (m_recolorOnResize) m_chosenColors.clear();
   }
public:
   Dialog(QWidget * parent = 0) : QWidget(parent), m_recolorOnResize(false) {
      m_palette << "#E2C42D" << "#E5D796" << "#BEDA2C" << "#D1DD91" << "#E2992D" << "#E5C596";
      setAttribute(Qt::WA_OpaquePaintEvent);
   }
   Q_SLOT void randomize() {
      m_chosenColors.clear();
      update();
   }
   bool recolorOnResize() const { return m_recolorOnResize; }
   void setRecolorOnResize(bool recolor) {
      m_recolorOnResize = recolor;
      setAttribute(Qt::WA_StaticContents, !m_recolorOnResize);
   }
};

int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   QWidget w;
   QGridLayout l(&w);
   Dialog d;
   QCheckBox recolor("Recolor on Resize");
   QPushButton update("Repaint"), randomize("Randomize");
   d.setMinimumSize(256, 128);
   l.addWidget(&d, 0, 0, 1, 2);
   l.addWidget(&recolor, 1, 0, 1, 2);
   l.addWidget(&update, 2, 0);
   l.addWidget(&randomize, 2, 1);
   recolor.setChecked(d.recolorOnResize());
   QObject::connect(&recolor, &QAbstractButton::toggled, [&d](bool checked){
      d.setRecolorOnResize(checked);}
   );
   QObject::connect(&update, &QAbstractButton::clicked, &d, static_cast<void(QWidget::*)()>(&QWidget::update));
   QObject::connect(&randomize, &QAbstractButton::clicked, &d, &Dialog::randomize);
   w.show();
   return a.exec();
}

#include "main.moc"
查看更多
登录 后发表回答