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
Forum Updated to NodeBB v4.3 + New Features

QPaintEvent in MainWindow

Scheduled Pinned Locked Moved Unsolved General and Desktop
qprinteventqprinterqmainwindow
20 Posts 4 Posters 11.2k 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
    #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