Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QPaintEvent in MainWindow

QPaintEvent in MainWindow

Scheduled Pinned Locked Moved Unsolved General and Desktop
qprinteventqprinterqmainwindow
20 Posts 4 Posters 12.9k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • DonnD Offline
    DonnD Offline
    Donn
    wrote on last edited by
    #9

    I'm still confused... Sorry for my stupid questions but I want to make it clear. I assume MyLabelWithOverlay inherits most of the methods provided by QLabel and I don't get why it cannot directly display text with label->setText() ?

    kshegunovK 1 Reply Last reply
    0
    • DonnD Donn

      I'm still confused... Sorry for my stupid questions but I want to make it clear. I assume MyLabelWithOverlay inherits most of the methods provided by QLabel and I don't get why it cannot directly display text with label->setText() ?

      kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by kshegunov
      #10

      @Donn
      It inherits all of the methods provided by QLabel, but it overrides the QLabel::paintEvent method, so no painting is done from QLabel::paintEvent and consequently you don't get the text painted (which is what QLabel::paintEvent actually does).

      Read and abide by the Qt Code of Conduct

      1 Reply Last reply
      0
      • DonnD Offline
        DonnD Offline
        Donn
        wrote on last edited by
        #11

        So QLabel::paintEvent is actually responsible for painting a simple text and if I override it doesn't provide the functionality for displaying text anymore and I need to do it myself in the body of overridden function, right? Can you provide some code how it could be in the body because I don't have any idea.

        kshegunovK 1 Reply Last reply
        0
        • DonnD Donn

          So QLabel::paintEvent is actually responsible for painting a simple text and if I override it doesn't provide the functionality for displaying text anymore and I need to do it myself in the body of overridden function, right? Can you provide some code how it could be in the body because I don't have any idea.

          kshegunovK Offline
          kshegunovK Offline
          kshegunov
          Moderators
          wrote on last edited by
          #12

          @Donn said:

          So QLabel::paintEvent is actually responsible for painting a simple text and if I override it doesn't provide the functionality for displaying text anymore and I need to do it myself in the body of overridden function, right?

          Correct.

          Can you provide some code how it could be in the body because I don't have any idea.

          void MyLabelWithOverlay::paintEvent(QPaintEvent * event)
          {
              // This code draws the pixmap that was given with setPixmap(), and hopefully it does that correctly 
              QPixmap pix = pixmap();
              qreal ratio = qMin(static_cast<qreal>(width()) / pix.width(), static_cast<qreal>(height()) / pix.height());
          
              QTransform transform;
              transform.scale(ratio, ratio);
          
              QRect sourceRect = transform.mapRect(event->rect());
          
              QPainter painter(this);
              painter.drawPixmap(event->rect(), pix, sourceRect); //< Pixmap was drawn
          
              if (overlayEnabled)  {
                  //< Here you can draw on top of that pixmap the lines (that's why it was left unfilled)
              }
          
              // Here you can draw the text (on top of the pixmap and the lines
              QRect widgetRect = rect(); //< This is the widget's rectangle
              QString labelText = text(); //< This is the text that was set
              // This following line draws the text centered horizontally and bound by the provided rectangle
              painter.drawText(widgetRect, labelText, Qt::AlignHCenter); 
          }
          

          Read and abide by the Qt Code of Conduct

          jsulmJ 1 Reply Last reply
          0
          • DonnD Offline
            DonnD Offline
            Donn
            wrote on last edited by Donn
            #13
            void MyLabelWithOverlay::paintEvent(QPaintEvent * event)
            {
                const QPixmap pix = *pixmap();
                qreal ratio = qMin(static_cast<qreal>(width()) / pix.width(), static_cast<qreal>(height()) / pix.height());
            
                QTransform transform;
                  transform.scale(ratio, ratio);
            
                QRect sourceRect = transform.mapRect(event->rect());
            
                QPainter painter(this);
                painter.drawPixmap(event->rect(), pix, sourceRect);
            
                if (overlayEnabled)  {
                    // Draw your lines here
                }
                // Here you can draw the text (on top of the pixmap and the lines
                QRectF widgetRect = rect(); //< This is the widget's rectangle
                QString labelText = text(); //< This is the text that was set
                // This following line draws the text centered horizontally and bound by the provided rectangle
                //painter.drawText(widgetRect, labelText, Qt::AlignHCenter);
            }
            
            

            My app crashes after this saying that

            QWidget::repaint: Recursive repaint detected
            

            If I uncomment the last line I get the following:

            C2664: 'void QPainter::drawText(const QRectF &,const QString &,const QTextOption &)': cannot convert argument 1 from 'QRectF' to 'int'
            
            1 Reply Last reply
            0
            • kshegunovK Offline
              kshegunovK Offline
              kshegunov
              Moderators
              wrote on last edited by kshegunov
              #14
              const QPixmap pix = *pixmap();
              

              Since you're not checking if the pointer returned is NULL, have you set a pixmap for the label with QLabel::setPixmap?
              If you haven't this would cause a segfault, because dereferencing a NULL pointer isn't allowed.

              Recursive repaint detected

              This shouldn't be normally happening. Are you calling repaint() manually, or is there an explicit call to paintEvent() somewhere?

              If I uncomment the last line I get the following: ... cannot convert argument 1 from 'QRectF' to 'int'

              Have you included the header for QRectF?

              Read and abide by the Qt Code of Conduct

              DonnD 1 Reply Last reply
              0
              • kshegunovK kshegunov

                @Donn said:

                So QLabel::paintEvent is actually responsible for painting a simple text and if I override it doesn't provide the functionality for displaying text anymore and I need to do it myself in the body of overridden function, right?

                Correct.

                Can you provide some code how it could be in the body because I don't have any idea.

                void MyLabelWithOverlay::paintEvent(QPaintEvent * event)
                {
                    // This code draws the pixmap that was given with setPixmap(), and hopefully it does that correctly 
                    QPixmap pix = pixmap();
                    qreal ratio = qMin(static_cast<qreal>(width()) / pix.width(), static_cast<qreal>(height()) / pix.height());
                
                    QTransform transform;
                    transform.scale(ratio, ratio);
                
                    QRect sourceRect = transform.mapRect(event->rect());
                
                    QPainter painter(this);
                    painter.drawPixmap(event->rect(), pix, sourceRect); //< Pixmap was drawn
                
                    if (overlayEnabled)  {
                        //< Here you can draw on top of that pixmap the lines (that's why it was left unfilled)
                    }
                
                    // Here you can draw the text (on top of the pixmap and the lines
                    QRect widgetRect = rect(); //< This is the widget's rectangle
                    QString labelText = text(); //< This is the text that was set
                    // This following line draws the text centered horizontally and bound by the provided rectangle
                    painter.drawText(widgetRect, labelText, Qt::AlignHCenter); 
                }
                
                jsulmJ Offline
                jsulmJ Offline
                jsulm
                Lifetime Qt Champion
                wrote on last edited by
                #15

                @kshegunov Wouldn't it be easier to first call QLabel::paintEvent(...) to get back the inherited functionality and then draw custom stuff?

                https://forum.qt.io/topic/113070/qt-code-of-conduct

                kshegunovK 1 Reply Last reply
                0
                • kshegunovK kshegunov
                  const QPixmap pix = *pixmap();
                  

                  Since you're not checking if the pointer returned is NULL, have you set a pixmap for the label with QLabel::setPixmap?
                  If you haven't this would cause a segfault, because dereferencing a NULL pointer isn't allowed.

                  Recursive repaint detected

                  This shouldn't be normally happening. Are you calling repaint() manually, or is there an explicit call to paintEvent() somewhere?

                  If I uncomment the last line I get the following: ... cannot convert argument 1 from 'QRectF' to 'int'

                  Have you included the header for QRectF?

                  DonnD Offline
                  DonnD Offline
                  Donn
                  wrote on last edited by
                  #16

                  @kshegunov said:

                  Since you're not checking if the pointer returned is NULL, have you set a pixmap for the label with QLabel::setPixmap?
                  If you haven't this would cause a segfault, because dereferencing a NULL pointer isn't allowed.

                  Could you please provide a solution for this because I really don't get it how it is done since it is a big mess for me and trying to get it step by step. I really appreatiate your help!

                  This shouldn't be normally happening. Are you calling repaint() manually, or is there an explicit call to paintEvent() somewhere?

                  I do not call any repaint() or paintEvent() explicitly I think. I just simply created a header file and a source file as mentioned above and have included header file to other header file and have promoted one QLabel widget to MyLabelWithOverlay.

                  Have you included the header for QRectF?

                  I have included the header but it is still the same problem.

                  1 Reply Last reply
                  0
                  • jsulmJ jsulm

                    @kshegunov Wouldn't it be easier to first call QLabel::paintEvent(...) to get back the inherited functionality and then draw custom stuff?

                    kshegunovK Offline
                    kshegunovK Offline
                    kshegunov
                    Moderators
                    wrote on last edited by
                    #17

                    @jsulm
                    Absolutely! Although, I was half way down writing the code when I realized I had a QLabel instead of QWidget (which would be usually the case) and was reluctant to rewrite it. :)

                    @Donn

                    Could you please provide a solution for this because I really don't get it how it is done since it is a big mess for me and trying to get it step by step.

                    Solution for what you mean? How to check whether a pointer is null? Simply check with if:

                    QPixmap * pixmapPointer = pixmap();
                    if (!pixmapPointer)
                        return;
                    
                    QPixmap & pix = *pixmapPointer; //< You have to make sure pixmapPointer points to a valid object before using the deref operator (the *)
                    

                    Also something I noticed in your code is that you're passing const QPixmap * to QPainter::drawPixmap, which accepts const QPixmap &, you should fix that (look the snippet how conversion between the two is done).

                    I have included the header but it is still the same problem.

                    Usually this happens when the header is not present. Try passing the object directly:

                    painter.drawText(QRectF(rect()), labelText, Qt::AlignHCenter);
                    

                    Read and abide by the Qt Code of Conduct

                    DonnD 1 Reply Last reply
                    0
                    • kshegunovK kshegunov

                      @jsulm
                      Absolutely! Although, I was half way down writing the code when I realized I had a QLabel instead of QWidget (which would be usually the case) and was reluctant to rewrite it. :)

                      @Donn

                      Could you please provide a solution for this because I really don't get it how it is done since it is a big mess for me and trying to get it step by step.

                      Solution for what you mean? How to check whether a pointer is null? Simply check with if:

                      QPixmap * pixmapPointer = pixmap();
                      if (!pixmapPointer)
                          return;
                      
                      QPixmap & pix = *pixmapPointer; //< You have to make sure pixmapPointer points to a valid object before using the deref operator (the *)
                      

                      Also something I noticed in your code is that you're passing const QPixmap * to QPainter::drawPixmap, which accepts const QPixmap &, you should fix that (look the snippet how conversion between the two is done).

                      I have included the header but it is still the same problem.

                      Usually this happens when the header is not present. Try passing the object directly:

                      painter.drawText(QRectF(rect()), labelText, Qt::AlignHCenter);
                      
                      DonnD Offline
                      DonnD Offline
                      Donn
                      wrote on last edited by Donn
                      #18

                      @kshegunov

                      Everything mentioned above compiles except the last problem:

                      Usually this happens when the header is not present. Try passing the object directly:

                      painter.drawText(QRectF(rect()), labelText, Qt::AlignHCenter);
                      

                      I still get the same error message. Instead I tried

                      painter.drawText(20, 20, labelText);
                      

                      which compiles but I don't get any text displayed in the promoted MyLabelWithOverlay label.

                      EDIT:

                      Maybe I'm doing something wrong in other place. If you can, please check it because I have no idea what could be wrong. Perhaps somewhere I don't completely get how things work...

                      mainwindow.h:

                      #ifndef MAINWINDOW_H
                      #define MAINWINDOW_H
                      
                      #include <QMainWindow>
                      
                      namespace Ui {
                      class MainWindow;
                      }
                      
                      class MainWindow : public QMainWindow
                      {
                          Q_OBJECT
                      
                      public:
                          explicit MainWindow(QWidget *parent = 0);
                          ~MainWindow();
                      
                      private:
                          Ui::MainWindow *ui;
                      };
                      
                      #endif // MAINWINDOW_H
                      
                      

                      MainWindow.cpp:

                      #include "mainwindow.h"
                      #include "ui_mainwindow.h"
                      #include "mylabelwithoverlay.h"
                      
                      MainWindow::MainWindow(QWidget *parent) :
                          QMainWindow(parent),
                          ui(new Ui::MainWindow)
                      {
                          ui->setupUi(this);
                          ui->label_5->setText("hello world"); // label_5 is promoted to MyLabelWithOverlay
                      }
                      
                      MainWindow::~MainWindow()
                      {
                          delete ui;
                      }
                      

                      mylabelwithoverlay.h:

                      #ifndef MYLABELWITHOVERLAY_H
                      #define MYLABELWITHOVERLAY_H
                      
                      #include "QtGui"
                      #include "QtCore"
                      #include "QLabel"
                      
                      
                      class MyLabelWithOverlay : public QLabel
                      {
                          Q_OBJECT
                      
                      public:
                           MyLabelWithOverlay (QWidget * parent = NULL);
                      
                      public slots:
                           void enableOverlay(bool enabled);
                      
                      protected:
                           virtual void paintEvent(QPaintEvent * event);
                      
                      private:
                           bool overlayEnabled;
                      };
                      
                      
                      #endif // MYLABELWITHOVERLAY_H
                      
                      

                      MyLabelWithOverlay.cpp:

                      #include "mylabelwithoverlay.h"
                      #include <QRect>
                      #include <QRectF>
                      
                      
                      MyLabelWithOverlay::MyLabelWithOverlay (QWidget * parent): QLabel(parent), overlayEnabled(false)
                      {
                      }
                      
                      void MyLabelWithOverlay::enableOverlay(bool enabled)
                      {
                          overlayEnabled = enabled;
                      }
                      
                      
                      void MyLabelWithOverlay::paintEvent(QPaintEvent * event)
                      {
                          const QPixmap * pixmapPointer = pixmap();
                          if (!pixmapPointer)
                              return;
                      
                          const QPixmap & pix = *pixmapPointer;
                      
                          qreal ratio = qMin(static_cast<qreal>(width()) / pix.width(), static_cast<qreal>(height()) / pix.height());
                      
                          QTransform transform;
                            transform.scale(ratio, ratio);
                      
                          QRect sourceRect = transform.mapRect(event->rect());
                      
                          QPainter painter(this);
                          painter.drawPixmap(event->rect(), pix, sourceRect);
                      
                          if (overlayEnabled)  {
                              // Draw your lines here
                          }
                          // Here you can draw the text (on top of the pixmap and the lines
                          QRect widgetRect = rect(); //< This is the widget's rectangle
                          QString labelText = text(); //< This is the text that was set
                          // This following line draws the text centered horizontally and bound by the provided rectangle
                          //painter.drawText(QRectF(rect()), labelText, Qt::AlignHCenter);
                          painter.drawText(20, 20, labelText);
                      
                      }
                      
                      1 Reply Last reply
                      0
                      • kshegunovK Offline
                        kshegunovK Offline
                        kshegunov
                        Moderators
                        wrote on last edited by
                        #19

                        @Donn
                        You're not setting a pixmap for the label, so when the paint events gets executed pixmapPointer will be NULL and the function will return. If you wish to support both/either text and pixmap you have to enclose each in its own if block.

                        void MyLabelWithOverlay::paintEvent(QPaintEvent * event)
                        {
                            QPainter painter(this);
                        
                            const QPixmap * pixmapPointer = pixmap();
                            if (pixmapPointer)  {
                                const QPixmap & pix = *pixmapPointer;
                                qreal ratio = qMin(static_cast<qreal>(width()) / pix.width(), static_cast<qreal>(height()) / pix.height());
                        
                                QTransform transform;
                                transform.scale(ratio, ratio);
                        
                                QRect sourceRect = transform.mapRect(event->rect());
                                painter.drawPixmap(event->rect(), pix, sourceRect);
                            }
                        
                            if (overlayEnabled)  {
                                // Draw your lines here
                            }
                        
                            QString labelText = text();
                            if (!labelText.empty())  {
                                painter.drawText(0, 0, labelText);
                            }
                        }
                        

                        Read and abide by the Qt Code of Conduct

                        DonnD 1 Reply Last reply
                        0
                        • kshegunovK kshegunov

                          @Donn
                          You're not setting a pixmap for the label, so when the paint events gets executed pixmapPointer will be NULL and the function will return. If you wish to support both/either text and pixmap you have to enclose each in its own if block.

                          void MyLabelWithOverlay::paintEvent(QPaintEvent * event)
                          {
                              QPainter painter(this);
                          
                              const QPixmap * pixmapPointer = pixmap();
                              if (pixmapPointer)  {
                                  const QPixmap & pix = *pixmapPointer;
                                  qreal ratio = qMin(static_cast<qreal>(width()) / pix.width(), static_cast<qreal>(height()) / pix.height());
                          
                                  QTransform transform;
                                  transform.scale(ratio, ratio);
                          
                                  QRect sourceRect = transform.mapRect(event->rect());
                                  painter.drawPixmap(event->rect(), pix, sourceRect);
                              }
                          
                              if (overlayEnabled)  {
                                  // Draw your lines here
                              }
                          
                              QString labelText = text();
                              if (!labelText.empty())  {
                                  painter.drawText(0, 0, labelText);
                              }
                          }
                          
                          DonnD Offline
                          DonnD Offline
                          Donn
                          wrote on last edited by Donn
                          #20

                          @kshegunov

                          I think I got it! I have included to the painterEvent the following:

                          QPixmap pm(200, 200);
                          pm.fill(Qt::white);
                          setPixmap(pm);
                          

                          Now I can set the text from other class like:

                          ui->label->setText("lala");
                          

                          However, I think I shouldn't set Pixmap inside paintEvent - better to do it in the other class so this type of label could be also used for other labels, right?

                          EDIT:

                          I liked the idea of @jsulm. Could you give me some hints how to achieve it? How to get the painting functionality from a standard QLabel and then add some additional my own painting?

                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved