Skip to content


A QT Project – Fractal generator – Custom Label Widget

In this post I will continue to develop the Arthur fractal generator. In the former post I created the base GUI, which I will develop further. While I was using Designer for making the GUI, this time I will modify the label widget manually to allow some interaction. We used a label widget, to show an image. In a fractal generator it is useful if we can select a rectangular area to zoom in or out. Therefore, we have to draw somehow on the top of the widget. When the mouse is pressed, we start drawing a rectangle. One corner of the rectangle will be the point where the mouse was pressed. The opposite corner will be the current position of the mouse, while it is moving and the mouse button is still pressed. When the mouse button is released, we stop drawing the rectangle.

To achieve this behavior I will make a custom widget. I will derive it from the existing QLabel widget by inheritance:

#ifndef ARTHUR_CANVAS_H
#define ARTHUR_CANVAS_H

#include <QLabel>
#include <QPainter>
#include <QMouseEvent>

class ArthurCanvas : public QLabel
{
// Q_OBJECT

public:
ArthurCanvas(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *event);

void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event );

private:
bool showSelectionRectangle;
int  selectionX;
int  selectionY;
int  selectionW;
int  selectionH;
};

#endif

I call the new widget ArthurCanvas. I wrote the class definition to a separate header file arthur_canvas.h. I implement the constructor where I simply call the QLabel constructor and in addition I give some default values to the attributes. I have five private attributes. One is for keeping the status whether we need to draw the rectangle or not. The other four are the coordinates of the starting corner of the rectangle and its width and height.

Then I also have four event handling functions. These are virtual functions of QLabel. They are called when the event in their name happens: paint, mouse press, mouse release, mouse move.

OK. Lets check the implementation, which I wrote to arthur_canvas.cpp:

#include “arthur_canvas.h”

ArthurCanvas::ArthurCanvas(QWidget *parent)
: QLabel(parent)
{
showSelectionRectangle = false;
selectionX = 0;
selectionY = 0;
selectionW = 0;
selectionH = 0;
}
void ArthurCanvas::paintEvent(QPaintEvent *event)
{

QLabel::paintEvent(event);

if(showSelectionRectangle)
{
QPainter painter(this);
painter.setPen(Qt::black);
painter.drawRect(selectionX, selectionY, selectionW, selectionH);
painter.setPen(Qt::white);
painter.drawRect(selectionX + 1, selectionY + 1, selectionW, selectionH);
}

}

void ArthurCanvas::mousePressEvent(QMouseEvent *event)
{
showSelectionRectangle = true;
selectionX = event->x();
selectionY = event->y();
selectionW = 0;
selectionH = 0;
repaint();
}

void ArthurCanvas::mouseReleaseEvent(QMouseEvent *event)
{
showSelectionRectangle = false;

repaint();
}

void ArthurCanvas::mouseMoveEvent(QMouseEvent *event)
{

if(showSelectionRectangle)
{
selectionW = event->pos().x() – selectionX;
selectionH = event->pos().y() – selectionY;
repaint();
}
}

The paint event is called when some parts of the widget are redrawn. As you can see first I call the QLabel paintEvent to keep the basic behavior of the label widget. In addition to that I draw the rectangle if necessary. The mouse events are controlling whether we need to draw and updating the coordinates and size. The code is very simple. You might noticed that I actually draw two rectangles. One is white the other is black. It makes sure that the rectangle is visible on any background. E.g. a simple black would not be visible on a black background.

Now all what we have to do is to add the new source files to the project file, and modify the ui_main.h to use the ArthurCanvas widget instead of the QLabel. Here is the new project file:

TEMPLATE = app
TARGET = arthur
DEPENDPATH += . include src
INCLUDEPATH += . include
UI_HEADERS_DIR = include

# Input
INCLUDES += include/ui_main.h \
include/arthur_canvas.h

SOURCES += src/main.cpp \
src/arthur_canvas.cpp

FORMS += main.ui

I guess it does not require too much explanation. One interesting thing that I found a new (new for me) variable UI_HEADERS_DIR which controls where uic puts the header file what it generates from the ui file. So we do not have to move it manually. Cool. You can modify the ui_main.h as a homework :) or if you are lazy like me, you can check it from the sources archive. Here is a screenshot of the working proggee:

You can download the sources from here: fractal003

Posted in Arthur Fractal Generator, QT Programming.

Tagged with , , , , , , , .