PDA

View Full Version : QPainter over Pixmap problem



seany
16th June 2013, 10:18
Hi

My intent is to have the user be able to draw a rounded dot using the Cursor over an Bitmap image displayed in the background. The Rounded dot remains on the screen and forms a line following
the Cursor movement (when Mouse is pressed). Drawing terminates when Mouse is Released.

In the program, I am using a Label to load the Bitmap and have the Label added to a layout and the layout to the Main window. I use setCentralWidget to place the label in the
center area of the MainWindow for esoteric purposes. When user presses Mouse, I activate PaintEvent and the latter will attempt to draw the rounded dot.

The problem is that the QPainter does not draw over the Bitmap. Note that it draws over the status and menu bar area of MainWindow correctly. If I comment out the Pixmap to label code, the QPainter draws across the entire screen. I realize I did not use QPainter to draw Bitmap as well the a rounded dot - instead I attempted to use Label to load the bitmap. The latter seemed a convenient way since I want the PaintEvent to focus on drawing lines/dots etc over the Bitmap without worrying about the Bitmap.

My question is can I actually do it this way successfully ? I have tried many combinations of MainWindow setAttributes and setting Pixmap and Label settings to no avail. Appreciate your help.

Thanks

Sean

------------------------mainwindow.cpp----------------------------------------------------------

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QtWidgets>
#include <QtGui>
#include <QtCore>
#include <QDebug>
#include <QPixmap>
#include <QLayout>
#include <QLabel>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QString bmp_filename;
QPixmap *pm;

ui->setupUi(this);

//Setup Attribute for drawing
this->setAttribute(Qt::WA_OpaquePaintEvent);

// Setup Boolean to indicate User is dragging Cursor and thus OK for PaintEvent to Draw
drawing = false;

/*
* Setup Layout, Label
* Attach Label to Layout
* Setup Layout to WIndow and set it as the central Widget
*/
layout = new QGridLayout(this);
lbl = new QLabel(this);
lbl->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
layout->addWidget(lbl, 0, 0);
this->setLayout(layout);
setCentralWidget(lbl);

/*
* Setup filename for Bitma and create a Pixmap
*/
bmp_filename = "C:/Users/syiu/VideoAd/QT/Test_Paint_Bitmap/images/test.bmp";
pm = new QPixmap(bmp_filename, 0, 0);

/*
* Bring the Pixmap to scale of the Window's dimensions and set this Pixmap to Label
*/
lbl->setPixmap(pm->scaled(this->width(), this->height(), Qt::KeepAspectRatioByExpanding, Qt::FastTransformation));
}

MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::paintEvent(QPaintEvent *event)
{
if (!drawing)
return;
QPainter painter(this);
QPen pen(Qt::green, 4, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen);

painter.drawPoint(current_pos);
}



void MainWindow::mousePressEvent(QMouseEvent *event)
{
drawing = true;

}

void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
qDebug() << "Main Window MouseRelease Event";
drawing = false;
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
current_pos = event->pos();
this->repaint();
}

-------------- main.cpp ------------------------------
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();

return a.exec();
}

-------------------- mainwindow.h -----------------------------------------------------
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtCore>
#include <QtGui>
#include <QPoint>
#include <QLabel>
#include <QLayout>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT
QPoint current_pos;
bool drawing;
QGridLayout *layout;
QLabel *lbl;


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

private:
Ui::MainWindow *ui;

protected:
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
};

#endif // MAINWINDOW_H

Santosh Reddy
16th June 2013, 15:55
You will have to implement QLabel's paintEvent(), and also store the points so that they are persistent

mainwindow.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtCore>
#include <QtGui>
#include <QPoint>
#include <QLabel>
#include <QLayout>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT
QGridLayout *layout;
QLabel *lbl;


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

private:
Ui::MainWindow *ui;
};

class Label : public QLabel
{
QList<QPoint> current_pos; //<<<<<<<<<<<<<<<<
bool drawing;

public:
explicit Label(QWidget * parent);

protected:
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
};

#endif // MAINWINDOW_H


mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QtWidgets>
#include <QtGui>
#include <QtCore>
#include <QDebug>
#include <QPixmap>
#include <QLayout>
#include <QLabel>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QString bmp_filename;
QPixmap *pm;

ui->setupUi(this);

//Setup Attribute for drawing
this->setAttribute(Qt::WA_OpaquePaintEvent);

/*
* Setup Layout, Label
* Attach Label to Layout
* Setup Layout to WIndow and set it as the central Widget
*/
layout = new QGridLayout(this);
lbl = new Label(this); //<<<<<<<<<<<<<<<<<<<<<<
lbl->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
layout->addWidget(lbl, 0, 0);
this->setLayout(layout);
setCentralWidget(lbl);

/*
* Setup filename for Bitma and create a Pixmap
*/
bmp_filename = "C:/Users/syiu/VideoAd/QT/Test_Paint_Bitmap/images/test.bmp";
pm = new QPixmap(bmp_filename, 0, 0);

/*
* Bring the Pixmap to scale of the Window's dimensions and set this Pixmap to Label
*/
lbl->setPixmap(pm->scaled(this->width(), this->height(), Qt::KeepAspectRatioByExpanding, Qt::FastTransformation));
}

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

Label::Label(QWidget * parent)
: QLabel(parent)
{
// Setup Boolean to indicate User is dragging Cursor and thus OK for PaintEvent to Draw
drawing = false;
}

void Label::paintEvent(QPaintEvent *event)
{
QLabel::paintEvent(event); //<<<<<<<<<<<<<<<
if (!drawing)
return;
QPainter painter(this);
QPen pen(Qt::green, 4, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen);

foreach(QPoint point, current_pos) //<<<<<<<<<<<<<<<
painter.drawPoint(point);
}

void Label::mousePressEvent(QMouseEvent *event)
{
drawing = true;
}

void Label::mouseReleaseEvent(QMouseEvent *event)
{
qDebug() << "Main Window MouseRelease Event";
drawing = false;
}

void Label::mouseMoveEvent(QMouseEvent *event)
{
current_pos << event->pos(); //<<<<<<<<<<<<<<<<<
this->repaint();
}

seany
16th June 2013, 18:48
Thanks for your insights. It works for me now

I tried something additional - instead of storing in the Label Qlist and having to replay the whole QList on a Label PaintEvent, I tried to no avail to manipulate the Label's Painter setCompositionMode to QPainter::CompostionMode_xxxx so that it would Paint the rounded dot over the existing Bitmap while leaving the trail of lines behind.
All combinations failed.

Anyone who have insights whether this can be done ?

Thanks

Sean

anda_skoa
16th June 2013, 20:18
What you want is not drawing on the widget, but into a pixmap.

So instead of the repaint() call in the code example of Santosh Reddy, you get the pixmap(), create a painter on it, paint onto it and then set the pixmap on the label again (this will trigger a label update).

Obviously you don't need to overwrite paintEvent() anymore.

Cheers,
_