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 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
                • VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by VRonin
                  #21

                  That's exactly what I'm explaining. event->region() is the area that need to be repainted (the one under the notepad in my previous example). If rect (which is 1 image pixel zoomed) is inside that region then repaint it, otherwise just skip it. You can actually remove that if altogether, it's there just to make the paint faster to avoid repainting regions that did not need repainting

                  "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
                  2
                  • tomyT Offline
                    tomyT Offline
                    tomy
                    wrote on last edited by
                    #22

                    Thanks.

                    That if-condition is for "the whole" painting I think. I removed the condition and it made the parameter event be left uselessly! I can't accept that condition is useful.

                    About another if-condition: if(event->buttons() & Qt::LeftButton) in the mouseMoveEvent. Here it has used a bit-wise and (&) while the operator == will work too.

                    Both sides are of the sate type (left, right or middle button). Why a bit-wise operator? (&)

                    And how could we convince ourselves that, that operator works correctly for that condition, please?

                    VRoninV 1 Reply Last reply
                    0
                    • mrjjM Offline
                      mrjjM Offline
                      mrjj
                      Lifetime Qt Champion
                      wrote on last edited by
                      #23

                      Hi
                      The bitwise & is used as the information is created that way. (using OR)
                      If multiple buttons were pressed, using == would fail even the Qt::LeftButton was actually also pressed.
                      So when a valued is created by using OR. the only correct way is to use & to check if that bit/bits is set.

                      1 Reply Last reply
                      2
                      • tomyT tomy

                        Thanks.

                        That if-condition is for "the whole" painting I think. I removed the condition and it made the parameter event be left uselessly! I can't accept that condition is useful.

                        About another if-condition: if(event->buttons() & Qt::LeftButton) in the mouseMoveEvent. Here it has used a bit-wise and (&) while the operator == will work too.

                        Both sides are of the sate type (left, right or middle button). Why a bit-wise operator? (&)

                        And how could we convince ourselves that, that operator works correctly for that condition, please?

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

                        @tomy said in Q_Properties in a Qt program:

                        I removed the condition and it made the parameter event be left uselessly!

                        It's not uncommon to have useless arguments. There is even a macro Q_UNUSED to suppress warnings regarding useless parameters

                        And how could we convince ourselves that, that operator works correctly for that condition, please?

                        think of if as "it executes the next block if the argument is not 0. event->buttons() & Qt::LeftButton will return 0 only if the Qt::LeftButton bit is not set

                        "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
                        2
                        • tomyT Offline
                          tomyT Offline
                          tomy
                          wrote on last edited by
                          #25

                          Thank you. But I still haven't got it.
                          The bitwise operators as their names express work on bits (0 and 1).
                          Do you mean that the states event->buttons() and Qt::LeftButton return are actually bits? event->buttons() returns a bit (0 or 1) and Qt::LeftButton also returns a bit (1 or 0). Then that bitwise operator &, operates on the two states and returns the result according to the && rule?

                          jsulmJ 1 Reply Last reply
                          0
                          • tomyT tomy

                            Thank you. But I still haven't got it.
                            The bitwise operators as their names express work on bits (0 and 1).
                            Do you mean that the states event->buttons() and Qt::LeftButton return are actually bits? event->buttons() returns a bit (0 or 1) and Qt::LeftButton also returns a bit (1 or 0). Then that bitwise operator &, operates on the two states and returns the result according to the && rule?

                            jsulmJ Offline
                            jsulmJ Offline
                            jsulm
                            Lifetime Qt Champion
                            wrote on last edited by jsulm
                            #26

                            @tomy Please check the definition of http://doc.qt.io/qt-5/qt.html#MouseButton-enum, LeftButton has a value of 0x00000001
                            It is not a bit it is an integer.
                            If you do a bitwise & with for example 0x00000011 you will get 0x00000001 which is not 0 and as such true:

                            0x00000011 & 0x00000001 = 0x00000001 // true
                            0x00000010 & 0x00000001 = 0x00000000 // false
                            

                            This has nothing to do with Qt - C/C++ basics.

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

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

                              @jsulm

                              0x00000011 & 0x00000001 = 0x00000001 // true
                              0x00000010 & 0x00000001 = 0x00000000 // false
                              

                              Thanks.

                              What's the criteria to consider it true/false? By the least-valuable bit?
                              I implemented the instructions for all three buttons.

                              Qt::LeftButton 0x00000001
                              Qt::RightButton 0x00000002
                              Qt::MidButton 0x00000004

                              Yes, they are integers and we will have one of those values if its corresponding button is pressed.
                              If we press "any" key (of the mouse) we will have a true value on the left side (event->buttons()). For instance, we press the midbutton. So on the left side we have a value true and on the right we have a value 4:

                              true & 4 = 0x00000100 // true or false
                              

                              Now is it interpreted true or false?

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

                                Nope, it's not converted to bool. Let's say you pressed both left and right mouse buttons. event->buttons() will return Qt::LeftButton | Qt::RightButton which is 3 as an integer (suppose 32 bits) 00000000000000000000000000000011 in binary. Now you "and" bit by bit with Qt::LeftButton which is 1 as an integer (suppose 32 bits) 00000000000000000000000000000001. The result is 00000000000000000000000000000001 as an integer. now

                                @VRonin said in Q_Properties in a Qt program:

                                think of if as "it executes the next block if the argument is not 0

                                since it's not 0 if executes the block

                                If it's still not clear: https://en.wikipedia.org/wiki/Bitwise_operation

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

                                  I studied the bit-wise AND of that link.

                                  Nope, it's not converted to bool.

                                  Help says: event->buttons(): Returns the button state when the event was generated. The button state is a combination of Qt::LeftButton, Qt::RightButton, Qt::MidButton using the OR operator.
                                  So by 'OR', it means 'plus' (+), not boolean OR!

                                  Thanks.

                                  JKSHJ 1 Reply Last reply
                                  0
                                  • tomyT tomy

                                    I studied the bit-wise AND of that link.

                                    Nope, it's not converted to bool.

                                    Help says: event->buttons(): Returns the button state when the event was generated. The button state is a combination of Qt::LeftButton, Qt::RightButton, Qt::MidButton using the OR operator.
                                    So by 'OR', it means 'plus' (+), not boolean OR!

                                    Thanks.

                                    JKSHJ Offline
                                    JKSHJ Offline
                                    JKSH
                                    Moderators
                                    wrote on last edited by JKSH
                                    #30

                                    @tomy said in Q_Properties in a Qt program:

                                    So by 'OR', it means 'plus' (+), not boolean OR!

                                    It is a bitwise-OR. If you press left and right mouse buttons at the same time, buttons() will return
                                    Qt::LeftButton | Qt::RightButton == 0x00000001 | 0x00000002 == 0x00000003.

                                    It is not 'plus' (+). Qt::LeftButton | Qt::LeftButton == 0x00000001 | 0x00000001 == 0x00000001

                                    @tomy said in Q_Properties in a Qt program:

                                    About another if-condition: if(event->buttons() & Qt::LeftButton) in the mouseMoveEvent. Here it has used a bit-wise and (&) while the operator == will work too.

                                    Both sides are of the sate type (left, right or middle button). Why a bit-wise operator? (&)

                                    No, == can fail if you press two buttons at the same time. As above, if you press the left and right buttons simultaneously, buttons() will return 0x00000003.

                                    • 0x00000003 == Qt::LeftButton evaluates to false
                                    • 0x00000003 & Qt::LeftButton evaluates to true

                                    Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                                    1 Reply Last reply
                                    4

                                    • Login

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