[SOLVED] What are properties for?
-
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?
-