Unsolved Q_Properties in a Qt program
-
in 99% of the cases,
Q_PROPERTY
s are needed only when using QtQuick (QML) as interface. They are not used afai see in this code. You can delete them. -
@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*
orQWidget*
, without knowing for sure if it isIconEditor
or not. You still can get/set its properties withQObject::property
/QObject::setProperty
, and if object is of different type but provides same property it will work just as fine asIconEditor
[*] - 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
-
You can also find code that uses QProperties for serialization of objects
-
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.
-
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? -
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.
-
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.
-
@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. -
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.
-
@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
-
@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? -
@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
-
Thank you.
-
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?
-
- correct
- 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
- 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);
- 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
-
@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)
-
- Take this situation:
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 outsideevent->region()
and we don't repaint it
Repainting is handled internally by Qt, it will take care of callingpaintEvent
every time it needs re-painting - http://doc.qt.io/qt-5/qimage.html#pixelColor-1 : "This function was introduced in Qt 5.6."
- Take this situation:
-
OK, thank you.
What is the role ofintersected(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.
-
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). Ifrect
(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 -
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?