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. Q_Properties in a Qt program
Forum Updated to NodeBB v4.3 + New Features

Q_Properties in a Qt program

Scheduled Pinned Locked Moved Unsolved General and Desktop
30 Posts 7 Posters 8.2k Views 4 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.
  • tomyT Offline
    tomyT Offline
    tomy
    wrote on last edited by
    #1

    Hello,

    I still have some issues on this example:

    main.cpp:

    #include <QApplication>
    #include "iconeditor.h"
    
    int main(int argc, char* argv[])
    {
        QApplication app(argc, argv);
    
        IconEditor iconEditor;
        iconEditor.setWindowTitle(QObject::tr("Icon Editor"));
        iconEditor.setIconImage(QImage(":/images/mouse.png"));
        iconEditor.show();
    
        return app.exec();
    }
    

    iconeditor.h:

    #ifndef ICONEDITOR_H
    #define ICONEDITOR_H
    
    #include <QColor>
    #include <QImage>
    #include <QWidget>
    
    class IconEditor : public QWidget
    {
        Q_OBJECT
        Q_PROPERTY(QColor penColor READ penColor WRITE setPenColor)
        Q_PROPERTY(QImage iconImage READ iconImage WRITE setIconImage)
        Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor)
    
    public:
        IconEditor(QWidget *parent = 0);
    
        QColor penColor() const { return curColor; }
        QImage iconImage() const { return image; }
        int zoomFactor() const { return zoom; }
        void setPenColor(const QColor &newColor);
        void setIconImage(const QImage &newImage);
        void setZoomFactor(int newZoom);
    
        QSize sizeHint() const;
    
        ~IconEditor();
    
    protected:
        void mousePressEvent(QMouseEvent *event);
        void mouseMoveEvent(QMouseEvent *event);
        void paintEvent(QPaintEvent *event);
    
    private:
        void setImagePixel(const QPoint &pos, bool opaque);
        QRect pixelRect(int i, int j) const;
    
        QColor curColor;
        QImage image;
        int zoom;
    };
    
    #endif // ICONEDITOR_H
    

    iconeditor.cpp:

    #include <QtWidgets>
    #include "iconeditor.h"
    
    IconEditor::IconEditor(QWidget *parent)
        : QWidget(parent)
    {
        setAttribute(Qt::WA_StaticContents);
        setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    
        curColor = Qt::blue;
        zoom = 8;
    
        image = QImage(16, 16, QImage::Format_ARGB32);
        image.fill(qRgba(0, 0, 0, 0));
    }
    
    //*******************************************************
    
    void IconEditor::setPenColor(const QColor& newColor)
    {
        curColor = newColor;
    }
    
    //**************************************************
    
    void IconEditor::setZoomFactor(int newZoom)
    {
        if (newZoom < 1)
            newZoom = 1;
    
        if (newZoom != zoom) {
            zoom = newZoom;
            update();
            updateGeometry();
        }
    }
    
    //***********************************************************
    
    void IconEditor::setIconImage(const QImage &newImage)
    {
        if (newImage != image) {
            image = newImage.convertToFormat(QImage::Format_ARGB32);
            update();
            updateGeometry();
        }
    }
    
    //********************************************
    
    QSize IconEditor::sizeHint() const
    {
        QSize size = zoom * image.size();
        if (zoom >= 3)
            size += QSize(1, 1);
        return size;
    }
    
    //*******************************************
    
    void IconEditor::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);
        qDebug() << image.height() << ' ' << image.width() <<endl;
        if(zoom >= 3)
          {
            painter.setPen(palette().foreground().color());
            for(int i = 0; i< image.width(); ++i)
                painter.drawLine(zoom * i, 0, zoom *i, zoom * image.height());
    
            for(int j = 0; j<image.height(); ++j)
                painter.drawLine(0, zoom * j, zoom * image.width(), zoom * j);
          }
    
        for(int i = 0; i<image.width(); ++i)
            for(int j = 0; j < image.height(); ++j)
            {
                QRect rect = pixelRect(i, j);
                  if(!event->region().intersected(rect).isEmpty())
                  {
                     QColor color = QColor::fromRgba(image.pixel(i, j));
                      if(color.alpha() < 255)
                         painter.fillRect(rect, Qt::white);
                      painter.fillRect(rect, color);
                  }
            }
    }
    
    //************************************************
    
    QRect IconEditor::pixelRect(int i, int j) const
    {
        if( zoom >= 3)
            return QRect(zoom * i + 1, zoom * j + 1, zoom-1, zoom-1);
        else
            return QRect(zoom * i, zoom * j, zoom , zoom);
    }
    
    //**************************************************
    
    void IconEditor::mousePressEvent(QMouseEvent *event)
    {
        if(event->button() == Qt::LeftButton)
            setImagePixel(event->pos(), true);
        else if(event->button() == Qt::RightButton)
            setImagePixel(event->pos(), false);
    }
    
    //************************************************
    
    void IconEditor::mouseMoveEvent(QMouseEvent *event)
    {
        if(event->buttons() & Qt::LeftButton)
            setImagePixel(event->pos(), true);
        else if(event->buttons() & Qt::RightButton)
            setImagePixel(event->pos(), false);
    }
    
    //*********************************************************
    
    void IconEditor::setImagePixel(const QPoint &pos, bool opaque)
    {
        int i = pos.x() / zoom;
        int j = pos.y() / zoom;
    
        if(image.rect().contains(i, j)) {
            if(opaque)
                image.setPixel(i, j, penColor().rgba());
            else
                image.setPixel(i, j, qRgba(0 , 0, 0, 0));
        update(pixelRect(i, j));
        }
    }
    
    //***************************************************
    
    IconEditor::~IconEditor() { }
    
    

    The functions below are called only by those three properties:

     QColor penColor() const { return curColor; }
     int zoomFactor() const { return zoom; }
     void setPenColor(const QColor &newColor);
     void setIconImage(const QImage &newImage);
     void setZoomFactor(int newZoom);
    

    But what if we don't use the properties? I meant, whether I use the properties or make them comments, the program works well in both cases. So the question is how or by what instructions/statements are those functions called when we make the properties comments (/* */), please?

    m.sueM K VRoninV 3 Replies Last reply
    0
    • tomyT tomy

      Hello,

      I still have some issues on this example:

      main.cpp:

      #include <QApplication>
      #include "iconeditor.h"
      
      int main(int argc, char* argv[])
      {
          QApplication app(argc, argv);
      
          IconEditor iconEditor;
          iconEditor.setWindowTitle(QObject::tr("Icon Editor"));
          iconEditor.setIconImage(QImage(":/images/mouse.png"));
          iconEditor.show();
      
          return app.exec();
      }
      

      iconeditor.h:

      #ifndef ICONEDITOR_H
      #define ICONEDITOR_H
      
      #include <QColor>
      #include <QImage>
      #include <QWidget>
      
      class IconEditor : public QWidget
      {
          Q_OBJECT
          Q_PROPERTY(QColor penColor READ penColor WRITE setPenColor)
          Q_PROPERTY(QImage iconImage READ iconImage WRITE setIconImage)
          Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor)
      
      public:
          IconEditor(QWidget *parent = 0);
      
          QColor penColor() const { return curColor; }
          QImage iconImage() const { return image; }
          int zoomFactor() const { return zoom; }
          void setPenColor(const QColor &newColor);
          void setIconImage(const QImage &newImage);
          void setZoomFactor(int newZoom);
      
          QSize sizeHint() const;
      
          ~IconEditor();
      
      protected:
          void mousePressEvent(QMouseEvent *event);
          void mouseMoveEvent(QMouseEvent *event);
          void paintEvent(QPaintEvent *event);
      
      private:
          void setImagePixel(const QPoint &pos, bool opaque);
          QRect pixelRect(int i, int j) const;
      
          QColor curColor;
          QImage image;
          int zoom;
      };
      
      #endif // ICONEDITOR_H
      

      iconeditor.cpp:

      #include <QtWidgets>
      #include "iconeditor.h"
      
      IconEditor::IconEditor(QWidget *parent)
          : QWidget(parent)
      {
          setAttribute(Qt::WA_StaticContents);
          setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
      
          curColor = Qt::blue;
          zoom = 8;
      
          image = QImage(16, 16, QImage::Format_ARGB32);
          image.fill(qRgba(0, 0, 0, 0));
      }
      
      //*******************************************************
      
      void IconEditor::setPenColor(const QColor& newColor)
      {
          curColor = newColor;
      }
      
      //**************************************************
      
      void IconEditor::setZoomFactor(int newZoom)
      {
          if (newZoom < 1)
              newZoom = 1;
      
          if (newZoom != zoom) {
              zoom = newZoom;
              update();
              updateGeometry();
          }
      }
      
      //***********************************************************
      
      void IconEditor::setIconImage(const QImage &newImage)
      {
          if (newImage != image) {
              image = newImage.convertToFormat(QImage::Format_ARGB32);
              update();
              updateGeometry();
          }
      }
      
      //********************************************
      
      QSize IconEditor::sizeHint() const
      {
          QSize size = zoom * image.size();
          if (zoom >= 3)
              size += QSize(1, 1);
          return size;
      }
      
      //*******************************************
      
      void IconEditor::paintEvent(QPaintEvent *event)
      {
          QPainter painter(this);
          qDebug() << image.height() << ' ' << image.width() <<endl;
          if(zoom >= 3)
            {
              painter.setPen(palette().foreground().color());
              for(int i = 0; i< image.width(); ++i)
                  painter.drawLine(zoom * i, 0, zoom *i, zoom * image.height());
      
              for(int j = 0; j<image.height(); ++j)
                  painter.drawLine(0, zoom * j, zoom * image.width(), zoom * j);
            }
      
          for(int i = 0; i<image.width(); ++i)
              for(int j = 0; j < image.height(); ++j)
              {
                  QRect rect = pixelRect(i, j);
                    if(!event->region().intersected(rect).isEmpty())
                    {
                       QColor color = QColor::fromRgba(image.pixel(i, j));
                        if(color.alpha() < 255)
                           painter.fillRect(rect, Qt::white);
                        painter.fillRect(rect, color);
                    }
              }
      }
      
      //************************************************
      
      QRect IconEditor::pixelRect(int i, int j) const
      {
          if( zoom >= 3)
              return QRect(zoom * i + 1, zoom * j + 1, zoom-1, zoom-1);
          else
              return QRect(zoom * i, zoom * j, zoom , zoom);
      }
      
      //**************************************************
      
      void IconEditor::mousePressEvent(QMouseEvent *event)
      {
          if(event->button() == Qt::LeftButton)
              setImagePixel(event->pos(), true);
          else if(event->button() == Qt::RightButton)
              setImagePixel(event->pos(), false);
      }
      
      //************************************************
      
      void IconEditor::mouseMoveEvent(QMouseEvent *event)
      {
          if(event->buttons() & Qt::LeftButton)
              setImagePixel(event->pos(), true);
          else if(event->buttons() & Qt::RightButton)
              setImagePixel(event->pos(), false);
      }
      
      //*********************************************************
      
      void IconEditor::setImagePixel(const QPoint &pos, bool opaque)
      {
          int i = pos.x() / zoom;
          int j = pos.y() / zoom;
      
          if(image.rect().contains(i, j)) {
              if(opaque)
                  image.setPixel(i, j, penColor().rgba());
              else
                  image.setPixel(i, j, qRgba(0 , 0, 0, 0));
          update(pixelRect(i, j));
          }
      }
      
      //***************************************************
      
      IconEditor::~IconEditor() { }
      
      

      The functions below are called only by those three properties:

       QColor penColor() const { return curColor; }
       int zoomFactor() const { return zoom; }
       void setPenColor(const QColor &newColor);
       void setIconImage(const QImage &newImage);
       void setZoomFactor(int newZoom);
      

      But what if we don't use the properties? I meant, whether I use the properties or make them comments, the program works well in both cases. So the question is how or by what instructions/statements are those functions called when we make the properties comments (/* */), please?

      m.sueM Offline
      m.sueM Offline
      m.sue
      wrote on last edited by m.sue
      #2

      Hi @tomy

      the Q_PROPERTY macro does some signal slot registration behind the scenes (http://doc.qt.io/qt-5/properties.html) using the real functions and variable definition that you provide yourself: like QColor penColor, QColor penColor(), and void setPenColor(const QColor &color). Without the macro your function definitions still exist, so you can still use them.

      -Michael.

      1 Reply Last reply
      0
      • VRoninV Offline
        VRoninV Offline
        VRonin
        wrote on last edited by
        #3

        in 99% of the cases, Q_PROPERTYs are needed only when using QtQuick (QML) as interface. They are not used afai see in this code. You can delete them.

        "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
        ~Napoleon Bonaparte

        On a crusade to banish setIndexWidget() from the holy land of Qt

        1 Reply Last reply
        1
        • tomyT tomy

          Hello,

          I still have some issues on this example:

          main.cpp:

          #include <QApplication>
          #include "iconeditor.h"
          
          int main(int argc, char* argv[])
          {
              QApplication app(argc, argv);
          
              IconEditor iconEditor;
              iconEditor.setWindowTitle(QObject::tr("Icon Editor"));
              iconEditor.setIconImage(QImage(":/images/mouse.png"));
              iconEditor.show();
          
              return app.exec();
          }
          

          iconeditor.h:

          #ifndef ICONEDITOR_H
          #define ICONEDITOR_H
          
          #include <QColor>
          #include <QImage>
          #include <QWidget>
          
          class IconEditor : public QWidget
          {
              Q_OBJECT
              Q_PROPERTY(QColor penColor READ penColor WRITE setPenColor)
              Q_PROPERTY(QImage iconImage READ iconImage WRITE setIconImage)
              Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor)
          
          public:
              IconEditor(QWidget *parent = 0);
          
              QColor penColor() const { return curColor; }
              QImage iconImage() const { return image; }
              int zoomFactor() const { return zoom; }
              void setPenColor(const QColor &newColor);
              void setIconImage(const QImage &newImage);
              void setZoomFactor(int newZoom);
          
              QSize sizeHint() const;
          
              ~IconEditor();
          
          protected:
              void mousePressEvent(QMouseEvent *event);
              void mouseMoveEvent(QMouseEvent *event);
              void paintEvent(QPaintEvent *event);
          
          private:
              void setImagePixel(const QPoint &pos, bool opaque);
              QRect pixelRect(int i, int j) const;
          
              QColor curColor;
              QImage image;
              int zoom;
          };
          
          #endif // ICONEDITOR_H
          

          iconeditor.cpp:

          #include <QtWidgets>
          #include "iconeditor.h"
          
          IconEditor::IconEditor(QWidget *parent)
              : QWidget(parent)
          {
              setAttribute(Qt::WA_StaticContents);
              setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
          
              curColor = Qt::blue;
              zoom = 8;
          
              image = QImage(16, 16, QImage::Format_ARGB32);
              image.fill(qRgba(0, 0, 0, 0));
          }
          
          //*******************************************************
          
          void IconEditor::setPenColor(const QColor& newColor)
          {
              curColor = newColor;
          }
          
          //**************************************************
          
          void IconEditor::setZoomFactor(int newZoom)
          {
              if (newZoom < 1)
                  newZoom = 1;
          
              if (newZoom != zoom) {
                  zoom = newZoom;
                  update();
                  updateGeometry();
              }
          }
          
          //***********************************************************
          
          void IconEditor::setIconImage(const QImage &newImage)
          {
              if (newImage != image) {
                  image = newImage.convertToFormat(QImage::Format_ARGB32);
                  update();
                  updateGeometry();
              }
          }
          
          //********************************************
          
          QSize IconEditor::sizeHint() const
          {
              QSize size = zoom * image.size();
              if (zoom >= 3)
                  size += QSize(1, 1);
              return size;
          }
          
          //*******************************************
          
          void IconEditor::paintEvent(QPaintEvent *event)
          {
              QPainter painter(this);
              qDebug() << image.height() << ' ' << image.width() <<endl;
              if(zoom >= 3)
                {
                  painter.setPen(palette().foreground().color());
                  for(int i = 0; i< image.width(); ++i)
                      painter.drawLine(zoom * i, 0, zoom *i, zoom * image.height());
          
                  for(int j = 0; j<image.height(); ++j)
                      painter.drawLine(0, zoom * j, zoom * image.width(), zoom * j);
                }
          
              for(int i = 0; i<image.width(); ++i)
                  for(int j = 0; j < image.height(); ++j)
                  {
                      QRect rect = pixelRect(i, j);
                        if(!event->region().intersected(rect).isEmpty())
                        {
                           QColor color = QColor::fromRgba(image.pixel(i, j));
                            if(color.alpha() < 255)
                               painter.fillRect(rect, Qt::white);
                            painter.fillRect(rect, color);
                        }
                  }
          }
          
          //************************************************
          
          QRect IconEditor::pixelRect(int i, int j) const
          {
              if( zoom >= 3)
                  return QRect(zoom * i + 1, zoom * j + 1, zoom-1, zoom-1);
              else
                  return QRect(zoom * i, zoom * j, zoom , zoom);
          }
          
          //**************************************************
          
          void IconEditor::mousePressEvent(QMouseEvent *event)
          {
              if(event->button() == Qt::LeftButton)
                  setImagePixel(event->pos(), true);
              else if(event->button() == Qt::RightButton)
                  setImagePixel(event->pos(), false);
          }
          
          //************************************************
          
          void IconEditor::mouseMoveEvent(QMouseEvent *event)
          {
              if(event->buttons() & Qt::LeftButton)
                  setImagePixel(event->pos(), true);
              else if(event->buttons() & Qt::RightButton)
                  setImagePixel(event->pos(), false);
          }
          
          //*********************************************************
          
          void IconEditor::setImagePixel(const QPoint &pos, bool opaque)
          {
              int i = pos.x() / zoom;
              int j = pos.y() / zoom;
          
              if(image.rect().contains(i, j)) {
                  if(opaque)
                      image.setPixel(i, j, penColor().rgba());
                  else
                      image.setPixel(i, j, qRgba(0 , 0, 0, 0));
              update(pixelRect(i, j));
              }
          }
          
          //***************************************************
          
          IconEditor::~IconEditor() { }
          
          

          The functions below are called only by those three properties:

           QColor penColor() const { return curColor; }
           int zoomFactor() const { return zoom; }
           void setPenColor(const QColor &newColor);
           void setIconImage(const QImage &newImage);
           void setZoomFactor(int newZoom);
          

          But what if we don't use the properties? I meant, whether I use the properties or make them comments, the program works well in both cases. So the question is how or by what instructions/statements are those functions called when we make the properties comments (/* */), please?

          K Offline
          K Offline
          Konstantin Tokarev
          wrote on last edited by
          #4

          @tomy Q_PROPERTY allows to access properties by their name (which may be unknown at compile time) instead of calling concrete class methods.

          Examples of cases when this may be needed:

          • As @VRonin mentioned, objects exposed to QML
          • Similarly, old application using QtScript, and also 3rd party language bindings may use this
          • In Qt Designer (or version of it embedded into Qt Creator) you can modify values of widget properties via GUI
          • In C++ code there may be a situation when you have access to some object as QObject* or QWidget*, without knowing for sure if it is IconEditor or not. You still can get/set its properties with QObject::property/QObject::setProperty, and if object is of different type but provides same property it will work just as fine as IconEditor [*]
          • Variation of previous item, you can have generic code that traverses object/widget hierarchies from parent to children and accessing their properties. For example, I've once implemented custom style system based on QProperties, for set of custom widgets which did not use QStyle internally

          [*] Though it's better to use abstract interface instead, if possible

          K 1 Reply Last reply
          3
          • K Konstantin Tokarev

            @tomy Q_PROPERTY allows to access properties by their name (which may be unknown at compile time) instead of calling concrete class methods.

            Examples of cases when this may be needed:

            • As @VRonin mentioned, objects exposed to QML
            • Similarly, old application using QtScript, and also 3rd party language bindings may use this
            • In Qt Designer (or version of it embedded into Qt Creator) you can modify values of widget properties via GUI
            • In C++ code there may be a situation when you have access to some object as QObject* or QWidget*, without knowing for sure if it is IconEditor or not. You still can get/set its properties with QObject::property/QObject::setProperty, and if object is of different type but provides same property it will work just as fine as IconEditor [*]
            • Variation of previous item, you can have generic code that traverses object/widget hierarchies from parent to children and accessing their properties. For example, I've once implemented custom style system based on QProperties, for set of custom widgets which did not use QStyle internally

            [*] Though it's better to use abstract interface instead, if possible

            K Offline
            K Offline
            Konstantin Tokarev
            wrote on last edited by
            #5

            You can also find code that uses QProperties for serialization of objects

            1 Reply Last reply
            0
            • tomyT Offline
              tomyT Offline
              tomy
              wrote on last edited by
              #6

              Thanks for the answers.
              I used the header file this way and removed all redundant parts:

              #ifndef ICONEDITOR_H
              #define ICONEDITOR_H
              
              #include <QColor>
              #include <QImage>
              #include <QWidget>
              
              class IconEditor : public QWidget
              {
                  Q_OBJECT
              
              public:
                  IconEditor(QWidget *parent = 0);
              
                  QColor penColor() const { return curColor; }
                  void setPenColor(const QColor &newColor);
                  void setIconImage(const QImage &newImage);
                  void setZoomFactor(int newZoom);
              
                  QSize sizeHint() const;
                  ~IconEditor();
              
              protected:
                  void mousePressEvent(QMouseEvent *event);
                  void mouseMoveEvent(QMouseEvent *event);
                  void paintEvent(QPaintEvent *event);
              
              private:
                  void setImagePixel(const QPoint &pos, bool opaque);
                  QRect pixelRect(int i, int j) const;
              
                  QColor curColor;
                  QImage image;
                  int zoom;
              };
              
              #endif // ICONEDITOR_H
              

              The code is much more reasonable and works well too.

              1 Reply Last reply
              0
              • tomyT Offline
                tomyT Offline
                tomy
                wrote on last edited by tomy
                #7

                Something strange!

                I even shortened the code more, to this state:

                #ifndef ICONEDITOR_H
                #define ICONEDITOR_H
                
                #include <QColor>
                #include <QImage>
                #include <QWidget>
                
                class IconEditor : public QWidget
                {
                    Q_OBJECT
                
                public:
                    IconEditor(QWidget *parent = 0);
                
                    QColor penColor() const { return curColor; }
                    void setIconImage(const QImage &newImage);
                
                    QSize sizeHint() const;
                    ~IconEditor();
                
                protected:
                    void mousePressEvent(QMouseEvent *event);
                    void mouseMoveEvent(QMouseEvent *event);
                    void paintEvent(QPaintEvent *event);
                
                private:
                    void setImagePixel(const QPoint &pos, bool opaque);
                    QRect pixelRect(int i, int j) const;
                
                    QColor curColor;
                    QImage image;
                    int zoom;
                };
                
                #endif // ICONEDITOR_H
                

                These are all the code needs to run. But the odd thing here is that why the author expanded the code to the one written in the first post of this thread! (from 35 lines of code to 43 only in the header!)
                I don't understand, do you?

                K 1 Reply Last reply
                0
                • tomyT tomy

                  Something strange!

                  I even shortened the code more, to this state:

                  #ifndef ICONEDITOR_H
                  #define ICONEDITOR_H
                  
                  #include <QColor>
                  #include <QImage>
                  #include <QWidget>
                  
                  class IconEditor : public QWidget
                  {
                      Q_OBJECT
                  
                  public:
                      IconEditor(QWidget *parent = 0);
                  
                      QColor penColor() const { return curColor; }
                      void setIconImage(const QImage &newImage);
                  
                      QSize sizeHint() const;
                      ~IconEditor();
                  
                  protected:
                      void mousePressEvent(QMouseEvent *event);
                      void mouseMoveEvent(QMouseEvent *event);
                      void paintEvent(QPaintEvent *event);
                  
                  private:
                      void setImagePixel(const QPoint &pos, bool opaque);
                      QRect pixelRect(int i, int j) const;
                  
                      QColor curColor;
                      QImage image;
                      int zoom;
                  };
                  
                  #endif // ICONEDITOR_H
                  

                  These are all the code needs to run. But the odd thing here is that why the author expanded the code to the one written in the first post of this thread! (from 35 lines of code to 43 only in the header!)
                  I don't understand, do you?

                  K Offline
                  K Offline
                  Konstantin Tokarev
                  wrote on last edited by
                  #8

                  Presumably because author intended this class to be more reusable, e.g. like widgets that are part of Qt. Built-in widgets have getters and setters for all their properties, as well as Q_PROPERTY declarations, to not limit you in different usage scenarios. If you are developing widget to be used in specific place of specific project, you can cut off a lot of unneeded stuff and make it simpler.

                  1 Reply Last reply
                  1
                  • tomyT Offline
                    tomyT Offline
                    tomy
                    wrote on last edited by
                    #9

                    Thank you. I even made it shorter. Not a good policy to me if the author has intended it for a reader who is "learning" new things to be overwhelmed by useless methods wasting time while they don't have any real usage at the given example. If he wanted he could use them all in a more appropriate example.

                    mrjjM 1 Reply Last reply
                    0
                    • tomyT tomy

                      Thank you. I even made it shorter. Not a good policy to me if the author has intended it for a reader who is "learning" new things to be overwhelmed by useless methods wasting time while they don't have any real usage at the given example. If he wanted he could use them all in a more appropriate example.

                      mrjjM Offline
                      mrjjM Offline
                      mrjj
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      @tomy
                      Actually, in the very next chapter he uses those properties to integrate as plugin into Designer
                      http://www.informit.com/articles/article.aspx?p=1405227&seqNum=3
                      So he had a plan with it.

                      1 Reply Last reply
                      2
                      • tomyT Offline
                        tomyT Offline
                        tomy
                        wrote on last edited by
                        #11

                        Hi,
                        So I will deal with those properties on that chapter with the experience I gained from here. Thanks.

                        One other question. In prior apps we would use setLayout for showing the output. Here I don't see that tool. What part of the code does this duty please? That is, it brings the window up for the rest of the program.

                        VRoninV 1 Reply Last reply
                        0
                        • tomyT tomy

                          Hi,
                          So I will deal with those properties on that chapter with the experience I gained from here. Thanks.

                          One other question. In prior apps we would use setLayout for showing the output. Here I don't see that tool. What part of the code does this duty please? That is, it brings the window up for the rest of the program.

                          VRoninV Offline
                          VRoninV Offline
                          VRonin
                          wrote on last edited by
                          #12

                          @tomy said in Q_Properties in a Qt program:

                          In prior apps we would use setLayout for showing the output

                          Nope, setLayout is used to, unsurprisingly, lay out multiple widgets. This example is a single widget that takes care of painting itself so no need for layouts

                          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                          ~Napoleon Bonaparte

                          On a crusade to banish setIndexWidget() from the holy land of Qt

                          tomyT 1 Reply Last reply
                          2
                          • VRoninV VRonin

                            @tomy said in Q_Properties in a Qt program:

                            In prior apps we would use setLayout for showing the output

                            Nope, setLayout is used to, unsurprisingly, lay out multiple widgets. This example is a single widget that takes care of painting itself so no need for layouts

                            tomyT Offline
                            tomyT Offline
                            tomy
                            wrote on last edited by
                            #13

                            @VRonin
                            We have a window that in main.cpp using the instruction below we set its title to "Icon Editor":
                            iconEditor.setWindowTitle(QObject::tr("Icon Editor"));
                            Then that window will be used for painting using the paintEvent function.
                            I mean, how will that window be up/shown? Using what function/instructions?

                            1 Reply Last reply
                            0
                            • tomyT tomy

                              Hello,

                              I still have some issues on this example:

                              main.cpp:

                              #include <QApplication>
                              #include "iconeditor.h"
                              
                              int main(int argc, char* argv[])
                              {
                                  QApplication app(argc, argv);
                              
                                  IconEditor iconEditor;
                                  iconEditor.setWindowTitle(QObject::tr("Icon Editor"));
                                  iconEditor.setIconImage(QImage(":/images/mouse.png"));
                                  iconEditor.show();
                              
                                  return app.exec();
                              }
                              

                              iconeditor.h:

                              #ifndef ICONEDITOR_H
                              #define ICONEDITOR_H
                              
                              #include <QColor>
                              #include <QImage>
                              #include <QWidget>
                              
                              class IconEditor : public QWidget
                              {
                                  Q_OBJECT
                                  Q_PROPERTY(QColor penColor READ penColor WRITE setPenColor)
                                  Q_PROPERTY(QImage iconImage READ iconImage WRITE setIconImage)
                                  Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor)
                              
                              public:
                                  IconEditor(QWidget *parent = 0);
                              
                                  QColor penColor() const { return curColor; }
                                  QImage iconImage() const { return image; }
                                  int zoomFactor() const { return zoom; }
                                  void setPenColor(const QColor &newColor);
                                  void setIconImage(const QImage &newImage);
                                  void setZoomFactor(int newZoom);
                              
                                  QSize sizeHint() const;
                              
                                  ~IconEditor();
                              
                              protected:
                                  void mousePressEvent(QMouseEvent *event);
                                  void mouseMoveEvent(QMouseEvent *event);
                                  void paintEvent(QPaintEvent *event);
                              
                              private:
                                  void setImagePixel(const QPoint &pos, bool opaque);
                                  QRect pixelRect(int i, int j) const;
                              
                                  QColor curColor;
                                  QImage image;
                                  int zoom;
                              };
                              
                              #endif // ICONEDITOR_H
                              

                              iconeditor.cpp:

                              #include <QtWidgets>
                              #include "iconeditor.h"
                              
                              IconEditor::IconEditor(QWidget *parent)
                                  : QWidget(parent)
                              {
                                  setAttribute(Qt::WA_StaticContents);
                                  setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
                              
                                  curColor = Qt::blue;
                                  zoom = 8;
                              
                                  image = QImage(16, 16, QImage::Format_ARGB32);
                                  image.fill(qRgba(0, 0, 0, 0));
                              }
                              
                              //*******************************************************
                              
                              void IconEditor::setPenColor(const QColor& newColor)
                              {
                                  curColor = newColor;
                              }
                              
                              //**************************************************
                              
                              void IconEditor::setZoomFactor(int newZoom)
                              {
                                  if (newZoom < 1)
                                      newZoom = 1;
                              
                                  if (newZoom != zoom) {
                                      zoom = newZoom;
                                      update();
                                      updateGeometry();
                                  }
                              }
                              
                              //***********************************************************
                              
                              void IconEditor::setIconImage(const QImage &newImage)
                              {
                                  if (newImage != image) {
                                      image = newImage.convertToFormat(QImage::Format_ARGB32);
                                      update();
                                      updateGeometry();
                                  }
                              }
                              
                              //********************************************
                              
                              QSize IconEditor::sizeHint() const
                              {
                                  QSize size = zoom * image.size();
                                  if (zoom >= 3)
                                      size += QSize(1, 1);
                                  return size;
                              }
                              
                              //*******************************************
                              
                              void IconEditor::paintEvent(QPaintEvent *event)
                              {
                                  QPainter painter(this);
                                  qDebug() << image.height() << ' ' << image.width() <<endl;
                                  if(zoom >= 3)
                                    {
                                      painter.setPen(palette().foreground().color());
                                      for(int i = 0; i< image.width(); ++i)
                                          painter.drawLine(zoom * i, 0, zoom *i, zoom * image.height());
                              
                                      for(int j = 0; j<image.height(); ++j)
                                          painter.drawLine(0, zoom * j, zoom * image.width(), zoom * j);
                                    }
                              
                                  for(int i = 0; i<image.width(); ++i)
                                      for(int j = 0; j < image.height(); ++j)
                                      {
                                          QRect rect = pixelRect(i, j);
                                            if(!event->region().intersected(rect).isEmpty())
                                            {
                                               QColor color = QColor::fromRgba(image.pixel(i, j));
                                                if(color.alpha() < 255)
                                                   painter.fillRect(rect, Qt::white);
                                                painter.fillRect(rect, color);
                                            }
                                      }
                              }
                              
                              //************************************************
                              
                              QRect IconEditor::pixelRect(int i, int j) const
                              {
                                  if( zoom >= 3)
                                      return QRect(zoom * i + 1, zoom * j + 1, zoom-1, zoom-1);
                                  else
                                      return QRect(zoom * i, zoom * j, zoom , zoom);
                              }
                              
                              //**************************************************
                              
                              void IconEditor::mousePressEvent(QMouseEvent *event)
                              {
                                  if(event->button() == Qt::LeftButton)
                                      setImagePixel(event->pos(), true);
                                  else if(event->button() == Qt::RightButton)
                                      setImagePixel(event->pos(), false);
                              }
                              
                              //************************************************
                              
                              void IconEditor::mouseMoveEvent(QMouseEvent *event)
                              {
                                  if(event->buttons() & Qt::LeftButton)
                                      setImagePixel(event->pos(), true);
                                  else if(event->buttons() & Qt::RightButton)
                                      setImagePixel(event->pos(), false);
                              }
                              
                              //*********************************************************
                              
                              void IconEditor::setImagePixel(const QPoint &pos, bool opaque)
                              {
                                  int i = pos.x() / zoom;
                                  int j = pos.y() / zoom;
                              
                                  if(image.rect().contains(i, j)) {
                                      if(opaque)
                                          image.setPixel(i, j, penColor().rgba());
                                      else
                                          image.setPixel(i, j, qRgba(0 , 0, 0, 0));
                                  update(pixelRect(i, j));
                                  }
                              }
                              
                              //***************************************************
                              
                              IconEditor::~IconEditor() { }
                              
                              

                              The functions below are called only by those three properties:

                               QColor penColor() const { return curColor; }
                               int zoomFactor() const { return zoom; }
                               void setPenColor(const QColor &newColor);
                               void setIconImage(const QImage &newImage);
                               void setZoomFactor(int newZoom);
                              

                              But what if we don't use the properties? I meant, whether I use the properties or make them comments, the program works well in both cases. So the question is how or by what instructions/statements are those functions called when we make the properties comments (/* */), please?

                              VRoninV Offline
                              VRoninV Offline
                              VRonin
                              wrote on last edited by VRonin
                              #14

                              @tomy said in Q_Properties in a Qt program:

                              how will that window be up/shown?

                              @tomy said in Q_Properties in a Qt program:

                              iconEditor.show();

                              Qt is more intuitive than you'd think

                              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                              ~Napoleon Bonaparte

                              On a crusade to banish setIndexWidget() from the holy land of Qt

                              1 Reply Last reply
                              3
                              • tomyT Offline
                                tomyT Offline
                                tomy
                                wrote on last edited by
                                #15

                                Thank you.

                                1 Reply Last reply
                                0
                                • tomyT Offline
                                  tomyT Offline
                                  tomy
                                  wrote on last edited by
                                  #16

                                  On the method void IconEditor::paintEvent(QPaintEvent *event), I think:

                                  1- QPainter painter(this): Here this is a pointer to a QPaintDevice which is here the widget we are working on.

                                  2- if(!event->region().intersected(rect).isEmpty()): I toyed with Documentations and read about each type: event, region, intersect, and isEmpty. I know that it compares "two" rectangles for an area to be intersected and looks if such an area exists or not (it's empty). The first rectangle is our rect, what's the other one? Would you please explain this line of code a little more?

                                  3- QColor color = QColor::fromRgba(image.pixel(i, j)): Here we first take the color of a pixel on our original icon, addressed by coordinates i and j, out, and then convert it to an Rgba format and set it to the variable color.

                                  4- if(color.alpha() < 255) painter.fillRect(rect, Qt::white);
                                  painter.fillRect(rect, color);

                                  If the color obtained that way (above), "isn't" completely dark, we first set a white background, and if it "is", we won't do anything. Then we paint the rect using that color.

                                  Are all 4 correct please?

                                  VRoninV 1 Reply Last reply
                                  0
                                  • tomyT tomy

                                    On the method void IconEditor::paintEvent(QPaintEvent *event), I think:

                                    1- QPainter painter(this): Here this is a pointer to a QPaintDevice which is here the widget we are working on.

                                    2- if(!event->region().intersected(rect).isEmpty()): I toyed with Documentations and read about each type: event, region, intersect, and isEmpty. I know that it compares "two" rectangles for an area to be intersected and looks if such an area exists or not (it's empty). The first rectangle is our rect, what's the other one? Would you please explain this line of code a little more?

                                    3- QColor color = QColor::fromRgba(image.pixel(i, j)): Here we first take the color of a pixel on our original icon, addressed by coordinates i and j, out, and then convert it to an Rgba format and set it to the variable color.

                                    4- if(color.alpha() < 255) painter.fillRect(rect, Qt::white);
                                    painter.fillRect(rect, color);

                                    If the color obtained that way (above), "isn't" completely dark, we first set a white background, and if it "is", we won't do anything. Then we paint the rect using that color.

                                    Are all 4 correct please?

                                    VRoninV Offline
                                    VRoninV Offline
                                    VRonin
                                    wrote on last edited by VRonin
                                    #17
                                    1. correct
                                    2. from http://doc.qt.io/qt-5/qpaintevent.html#region "Returns the region that needs to be updated." basically if the pixel (image pixel, not display pixel) you are painting is outside the area that needs to be repainted you don't bother painting it
                                    3. no, pixel already returns an rgb encoded color, you just create a QColor with it. You can actually replace it with QColor color = image.pixelColor(i, j);
                                    4. correct. The idea is that if it's completely dark it will overwrite the background anyway so might as well not bother painting the background

                                    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                    ~Napoleon Bonaparte

                                    On a crusade to banish setIndexWidget() from the holy land of Qt

                                    tomyT 1 Reply Last reply
                                    3
                                    • VRoninV VRonin
                                      1. correct
                                      2. from http://doc.qt.io/qt-5/qpaintevent.html#region "Returns the region that needs to be updated." basically if the pixel (image pixel, not display pixel) you are painting is outside the area that needs to be repainted you don't bother painting it
                                      3. no, pixel already returns an rgb encoded color, you just create a QColor with it. You can actually replace it with QColor color = image.pixelColor(i, j);
                                      4. correct. The idea is that if it's completely dark it will overwrite the background anyway so might as well not bother painting the background
                                      tomyT Offline
                                      tomyT Offline
                                      tomy
                                      wrote on last edited by
                                      #18

                                      @VRonin
                                      Thank you.

                                      from http://doc.qt.io/qt-5/qpaintevent.html#region "Returns the region that needs to be updated." basically if the pixel (image pixel, not display pixel) you are painting is outside the area that needs to be repainted you don't bother painting it

                                      1- I still haven't got it!
                                      Where have we any region for updating? I don't think we have any updating on the whole program.
                                      And, how an image pixel can be outside an area? We used the icon and created a grid according to its size.
                                      As well as, Where do we have repainting in this application please? Everything seems to be in a rather static mode.

                                      2- Is QColor color = image.pixelColor(i, j); another style of code only or related to new version of Qt? (Because the book is somewhat outdated)

                                      1 Reply Last reply
                                      0
                                      • VRoninV Offline
                                        VRoninV Offline
                                        VRonin
                                        wrote on last edited by
                                        #19
                                        1. Take this situation:
                                          Two windows partially overlapping
                                          if you now close the notepad, the calculator does not need to repaint everything but just the region that was previously hidden so a pixel that is on the top left section is outside event->region() and we don't repaint it
                                          Repainting is handled internally by Qt, it will take care of calling paintEvent every time it needs re-painting
                                        2. http://doc.qt.io/qt-5/qimage.html#pixelColor-1 : "This function was introduced in Qt 5.6."

                                        "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                        ~Napoleon Bonaparte

                                        On a crusade to banish setIndexWidget() from the holy land of Qt

                                        1 Reply Last reply
                                        1
                                        • tomyT Offline
                                          tomyT Offline
                                          tomy
                                          wrote on last edited by tomy
                                          #20

                                          OK, thank you.
                                          What is the role of intersected(rect).isEmpty() in that instruction, please?
                                          That part seems to check if there even is any widget (area) for painting! It also seemingly compares some two rectangles!

                                          All the painting happens based on that line in the code.

                                          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