how to avoid paintevent() being called when the widget was obscured and uncovered

社会主义新天地 提交于 2019-12-11 02:26:28

问题


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

回答1:


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.

#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"


来源:https://stackoverflow.com/questions/24995572/how-to-avoid-paintevent-being-called-when-the-widget-was-obscured-and-uncovere

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!