如何避免在窗口小部件被遮挡和发现时调用paintevent()

时间:2014-07-28 12:46:42

标签: c++ qt qt4 qt5

我想在Qwidget中绘制一些颜色随机的菱形。只有在调整窗口大小时才应重新绘制窗口小部件。问题是,当窗口小部件被遮挡并且现在已被发现时,它将被重新绘制。在这种情况下,如何避免调用paintEvent()?提前谢谢。

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 个答案:

答案 0 :(得分:5)

您预先假定了一个解决方案,实际上您应该专注于该问题。您的问题不在于何时调用paintEvent。 Qt的语义是这样的,paintEvent可以在主线程中的任何时间调用。你必须应付它。

相反,您需要做的是将随机颜色存储在容器中,以便在绘制时重复使用它们。在下面的示例中,颜色是按需生成的,并存储在由行和列索引的动态增长列表中。这样,当您调整窗口小部件的大小时,现有项目的颜色不必更改。然后,您可以通过简单地清除容器并强制更新来随时重新生成颜色。

以下示例允许您选择是否在调整大小时保留颜色。

代码使用Qt 5和C ++ 11。请注意,现代代码中不鼓励使用rand() % range - 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"