2 Mayıs 2014 Cuma

Basic Qt Applications: QPainter Application

The QPainter class performs low-level painting on widgets and other devices. Today, I will show you how to paint on a child widget of the mainwindow by using QPainter. Painting on a child widget will lead us to paint on a defined area in our mainwindow. Otherwise, once the program is initialized the paint event will paint on the mainwindow widget which is not desired in our applications.

In order to paint on a child widget, first we have to create a widget class. Please, follow the below mentioned steps to add a new widget class to your project.

1. Right click to your project folder and choose the "Add New".


2. In the opening window choose the "Qt" from Files and Classes section and choose the "Qt Designer Form Class"
3. Click the "Choose" button.



4. In the opening window, choose the "Widget" from templates\form section and then click the next button.

 
5. Name your widget class.



We named our new widget class as "painthere". Thus, the Qt Creator will add painthere.cpp, painthere.h and painthere.ui files to our project.

Our paintings will be done on this newly created widget class by implementing the paint event function in this newly created class. Then an object of this class will be created as a child widget in the mainwindow.cpp file.

Here, as an example we will first create a sine in the "gen_sine()" function of the class painthere. Then, the generated sine will be painted in the "paintEvent" function of the painthere class. The "painthere.h" and "painthere.cpp" files are given below.

painthere.h

#ifndef PAINTHERE_H
#define PAINTHERE_H

#include <QWidget>
#include <QPainter>
#include <QPaintEvent>
#include <QtMath>
#include <QList>
#include <QDebug>
#include <QPalette>

namespace Ui {
class painthere;
}

class painthere : public QWidget
{
    Q_OBJECT

public:
    explicit painthere(QWidget *parent = 0);
    ~painthere();

protected:
    void paintEvent(QPaintEvent *event);

public slots:
    void gen_sine();

private:
    Ui::painthere *ui;
    QList <float> sine_signal; // the list including the sine function values
};



#endif // PAINTHERE_H
 
 




painthere.cpp

#include "painthere.h"
#include "ui_painthere.h"

painthere::painthere(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::painthere)
{
    ui->setupUi(this);

}

painthere::~painthere()
{
    delete ui;
}

void painthere::paintEvent(QPaintEvent *event){

    int i,j;
    float y, ynext, ymax = 1.0, ymin = -1.0;
    QPainter painter(this);
    qDebug() <<"Paint Event"; // debugging

    painter.eraseRect(0,0,this->width(),this->height()); // first the window is erased
    painter.setPen(Qt::blue);


    // screen coordinates must be converted into real coordinates
    for (i = 0;i < sine_signal.length()-1;i++)
    {
        y = 250*(ymax - sine_signal.at(i)) / (ymax - ymin);
        ynext = 250*(ymax - sine_signal.at(i+1)) / (ymax - ymin);
        painter.drawLine(i, y, i, ynext);
    }

    // grid screen
    painter.setPen(Qt::black);
    for (i = 0;i < this->width(); i += (this->width()) / 25)
        for (j = 0;j < this->width(); j += (this->width()) / 25)
        painter.drawPoint(j,i);

}

void painthere::gen_sine(){

    int i;

    sine_signal.clear();

    for (i = 0;i < 500;i++){
        float s = 0.8*sin(2*3.14*i/25) + 0.003 * (qrand() % 20); // a small noise is added to create a flowing signal
                                                                 // effect in the window
        sine_signal.append(s);
    }

}



Once the painthere class is implemented, an object of this class is generated in the mainwindow.cpp file. Since the painthere class is a widget class, this newly generated object will create a new plotting area where our implemented sine function will be plotted. The mainwindow.h and mainwindow.cpp files are given below.

mainwindow.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <painthere.h>
#include <QTimer>


namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();



private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

private:
    Ui::MainWindow *ui;
    painthere *pp; // a painthere pointer 
    QTimer *timer;

};

#endif // MAINWINDOW_H


mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    pp = new painthere(this);
    pp->setGeometry(200,100,500,250);
    pp->setAutoFillBackground(true);
    pp->setBackgroundRole(QPalette::Light);
    pp->show();

    timer = new QTimer(this);
    connect(timer,SIGNAL(timeout()), this, SLOT(on_pushButton_clicked()));
}

MainWindow::~MainWindow()
{
    delete ui;
}



void MainWindow::on_pushButton_clicked()
{

    pp->gen_sine();
    pp->update();

    timer->start(1000);

}

void MainWindow::on_pushButton_2_clicked()
{
    timer->stop();
}


An output of the resulting application is also given below.