Quantcast
Channel: Wesley's Techblog » Qt
Viewing all articles
Browse latest Browse all 10

Resizable photo frames in Qt

$
0
0

Today someone asked how to copy one image into another image in Qt. I thought it was a nice idea to write an example about how to do that, plus a few extra things. We will create a resizable photo frame from just one simple image of a photo frame! It works like this:

  • Reimplement QWidget::paintEvent() and construct a QPainter(this) in the reimplementation so we can draw on the widget
  • Load the image of the photo frame and define 4 QRect objects to define the position of the frame borders – these borders are not allowed to scale
  • Draw something which will be contained inside of the frame – for example another image using QPainter::drawPixmap() or QPainter::drawImage()
  • Generate and draw the frame bars (the pieces between the borders)
    • Make use of the QImage::mirrored() function and another QPainter to create a new pixmap which contains the frame bar plus the mirrored frame bar.
    • This will make the bar look great when the frame bar is enlarged by tiling. This method is actually a very popular one in basic photo manipulation.
  • Draw the four borders

The result looks like this:

Photo frame in native size – versus – Enlarged photo frame

The code looks like this:

photowidget.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef PHOTOWIDGET_H
#define PHOTOWIDGET_H

#include <QtGui/QWidget>

class PhotoWidget : public QWidget {
    Q_OBJECT

public:
    PhotoWidget(QWidget *parent = 0);

protected:
    void paintEvent(QPaintEvent *event);

private:
    QPixmap createBar(Qt::Orientation orientation, const QPixmap &pixmap, const QRect &rect);
};

#endif // PHOTOWIDGET_H

photowidget.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "photowidget.h"
#include <QPainter>
#include <QPaintEvent>

#define SIZE 108

PhotoWidget::PhotoWidget(QWidget *parent) : QWidget(parent) {
    resize(400, 329);
    setWindowTitle("Photo Frame Example");
}

// This function generates a pixmap that can be used as a tiled bar.
// Note: We use a QPainter and the mirrored() function to make sure that the bar looks good when tiled.
//       This technique is often applied in basic photo manipulation.
QPixmap PhotoWidget::createBar(Qt::Orientation orientation, const QPixmap &pixmap, const QRect &rect) {
    QImage barA = pixmap.copy(rect).toImage();
    QImage barB = barA.mirrored(orientation == Qt::Horizontal ? true : false,
                                orientation == Qt::Vertical ? true : false);

    QSize size;
    size.setWidth(orientation == Qt::Horizontal ? barA.width() << 1 : barA.width());
    size.setHeight(orientation == Qt::Vertical ? barA.height() << 1 : barA.height());

    QPixmap bar(size);
    bar.fill(Qt::transparent);
    QPainter merger(&bar);

    merger.drawImage(0, 0, barA);
    if (orientation == Qt::Horizontal)
        merger.drawImage(barA.width(), 0, barB);
    else
        merger.drawImage(0, barA.height(), barB);

    return bar;
}

void PhotoWidget::paintEvent(QPaintEvent *event) {
    QPainter p(this);

    // Our frame as one full image, and an image to put in the frame
    QPixmap frame(":/img/frame.png");
    QPixmap sky(":/img/palmtree.jpg");

    // These four rectangles define the four borders of the frame
    QRect topLeft(0, 0, SIZE, SIZE);
    QRect topRight(frame.width() - SIZE, 0, SIZE, SIZE);
    QRect bottomLeft(0, frame.height() - SIZE, SIZE, SIZE);
    QRect bottomRight(frame.width() - SIZE, frame.height() - SIZE, SIZE, SIZE);

    // Draw the image first
    p.drawPixmap(QRect(40, 40, event->rect().width() - 80, event->rect().height() - 80), sky);

    // Draw the bars
    p.drawTiledPixmap(QRect(QPoint(SIZE, 0), event->rect().topRight() + QPoint(-SIZE, SIZE - 1)),
                      createBar(Qt::Horizontal, frame, QRect(QPoint(SIZE, 0), frame.rect().topRight() + QPoint(-SIZE, SIZE))));
    p.drawTiledPixmap(QRect(event->rect().bottomLeft() + QPoint(SIZE, -SIZE - 1), event->rect().bottomRight() - QPoint(SIZE, 0)),
                      createBar(Qt::Horizontal, frame, QRect(frame.rect().bottomLeft() + QPoint(SIZE, -SIZE), frame.rect().bottomRight() - QPoint(SIZE, 0))));
    p.drawTiledPixmap(QRect(QPoint(0, SIZE), event->rect().bottomLeft() + QPoint(SIZE, -SIZE)),
                      createBar(Qt::Vertical, frame, QRect(QPoint(0, SIZE), frame.rect().bottomLeft() + QPoint(SIZE, -SIZE))));
    p.drawTiledPixmap(QRect(event->rect().topRight() - QPoint(SIZE + 1, -SIZE), event->rect().bottomRight() - QPoint(0, SIZE)),
                      createBar(Qt::Vertical, frame, QRect(frame.rect().topRight() - QPoint(SIZE, -SIZE), frame.rect().bottomRight() - QPoint(0, SIZE))));

    // Draw the borders
    p.drawPixmap(QPoint(0, 0), frame, topLeft);
    p.drawPixmap(event->rect().topRight() - QPoint(SIZE, 0), frame, topRight);
    p.drawPixmap(event->rect().bottomLeft() - QPoint(0, SIZE), frame, bottomLeft);
    p.drawPixmap(event->rect().bottomRight() - QPoint(SIZE, SIZE), frame, bottomRight);
}

Viewing all articles
Browse latest Browse all 10

Trending Articles