[SOLVED] What are properties for?
-
Sorry if that seems like a dumb question, but none of the explanations I've read make it clear to me. I've looked at various code snippets that use them, but I'm not understanding when they're necessary.
-
Could you please provide us one of that snippets.
-
I asked the question in such a general way because I was hoping for a general answer. But as an example, here's the icon editor from Blanchette/Summerfield 2nd ed. (p. 108):
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);void setPenColor(const QColor &newColor); QColor penColor() const { return curColor; } void setZoomFactor(int newZoom); int zoomFactor() const { return zoom; } void setIconImage(const QImage &newImage); QImage iconImage() const { return image; } QSize sizeHint() const;
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.cpp
@#include <QtGui>#include "iconeditor.h"
IconEditor::IconEditor(QWidget *parent)
: QWidget(parent)
{
setAttribute(Qt::WA_StaticContents);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);curColor = Qt::black; 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::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::paintEvent(QPaintEvent *event)
{
QPainter painter(this);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().intersect(rect).isEmpty()) { QColor color = QColor::fromRgba(image.pixel(i, j)); if (color.alpha() < 255) painter.fillRect(rect, Qt::white); painter.fillRect(rect, color); } } }
}
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)); }
}
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);
}
}
@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();
}
@ -
A property, at least in Qt terms, is first and foremost a bundling of a series of methods on an object into a single semantic unit. Often, a getter, a setter and a signal are bundled under the flag of a single property. In your example, there are no signals attached to the properties, but there often are. So, instead of having separate methods to read and to write a value, a property bundles these conceptually.
In Qt, properties also enable introspection. That is: you can query an object at runtime for what properties it supports, its name, its type, and you can read and often minipulate its value through a generic interface. That enables techniques like property editors: you can minipulate the values in an object at runtime, while at design time you did not know anyting about what kind of object you'd be manipulating. [[doc:QObject]] has the property() and setProperty() methods, that allow you to read and write any property in the object, or even to create new ones dynamically. If you want to see what properties an object has, [[doc:QMetaObject]] provides you with the means to query an object on what it offers in terms of properties, but also in terms of signals, slots and some other bits and pieces.
-
Thanks, Andre, that explanation is very helpful. But when I look at the above example, I don't see many of these features in use: Only one of penColor's methods is called, on line 104 of iconeditor.cpp; iconImage has its bundled write method called directly on line 10 of main.cpp (apparently bypassing the property); zoomFactor isn't ever used! Am I missing something?
-
You're missing that it is only an example. API of classes is often designed in such a way that it would support more uses than just the example you're looking at. There is a pretty good chance the code for a sample was ripped out of something a bit bigger.
-
Ok, so it sounds like this code doesn't need properties to function. It seems needlessly complicated for a textbook example, but oh well.