PDA

View Full Version : select QPixmap area with mouse



tommy
16th November 2007, 00:36
Hi. I have a code (please see below) that displays a user-provided bitmap image (image_ori.bmp) when a pushbutton is clicked. I want the user to be able to select two coordinates on the image using mouse (one left click and one right click) and by doing it, crop the picture. Then I want the cropped picture to be displayed instead of the original picture. When the pushbutton is clicked, the original picture (uncropped) is displayed again.
I can get this to sort of work. But the coordinates are off and selection is offset. I think this is because I use global coordinates but I need local to that QLabel widget. How do you get local coordinates with mouse? Do you need to subclass mouse event for that (in the same subclass with the QLabel that displays the picture?)?
Also, what's the best way of avoiding having to save an load files every time you crop the picture like I rather unprofessionally do it?
I know you say that the QLabel approach is not the best for cropping and displaying but I kind of need to stick to this weird appraoch because a program that I write this code for requires this approach. Thanks a lot guys!


////////////////////////main.cpp//////////////////////////////
#include <QApplication>
#include <QtGui>
#include "tom.h"

int right_x, right_y, left_x, left_y;

MyWidget::MyWidget(QWidget* parent): QWidget(parent)
{
m_pixmapLabel = new QLabel;
m_drawButton = new QPushButton("&Load Original Image");
connect(m_drawButton, SIGNAL(clicked()), this, SLOT(refresh()));
QVBoxLayout* mainLayout = new QVBoxLayout;
mainLayout->addWidget(m_pixmapLabel);
mainLayout->addWidget(m_drawButton);
setLayout(mainLayout);
}

void MyWidget::refresh()
{
QPixmap pm3;
pm3.load("image_ori.bmp");
pm3.save("image.bmp", 0, -1);
testDraw();
}

void MyWidget::testDraw()
{
right_x=-1;
right_y=-1;
left_x=9999;
left_y=9999;
QPixmap pm;
pm.load("image.bmp");
m_pixmapLabel->setPixmap(pm);
}

void MyWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::RightButton)
{
right_x=event->x();
right_y=event->y();
}
if
(event->button() == Qt::LeftButton)
{
left_x=event->x();
left_y=event->y();
}

if ( (right_x - left_x) >=0 && (right_y - left_y >=0) && (left_x !=9999) && (right_x !=-1))
{
QPixmap pm2;
pm2.load("image.bmp");
pm2 = pm2.copy(left_x,left_y,right_x,right_y);
pm2.save("image.bmp", 0, -1);
m_pixmapLabel->setPixmap(pm2);
}

else QWidget::mousePressEvent(event);
}


int main(int argc, char *argv[])
{
QApplication application(argc, argv);
MyWidget window;
window.show();
return application.exec();
}


////////////////////////////////////tom.h///////////////////////////////////////
#ifndef TOM_H
#define TOM_H

#include <QtGui>
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget (QWidget* parent = 0);
protected:
void mousePressEvent(QMouseEvent *event);

public slots:
void testDraw();
void refresh();
private:
QLabel* m_pixmapLabel;
QPushButton* m_drawButton;
};

#endif

marcel
16th November 2007, 05:28
You have to subclass QLabel and reimplement mousePressEvent, mouseMoveEvent and paintEvent.

In mousePressEvent: store the crop coordinates in a QRect or two QPoint's. The local coordinates are stored in the event.
When you receive the right click(you should implement some kind of click counting - a boolean flag, etc) you have the two local coordinates. Now you can crop the pixmap and set it in the label.

In mouseMoveEvent: after you have the coordinate for the left mouse click you can update the second coordinate with the current mouse position stored in the event.

In paintEvent: draw the crop rectangle specified by the left click position and right click position or current mouse position(if you didn't have a right click yet). Note that you first have to call QLabel::paintEvent and then draw your crop rectangle, because you want the label to be able to draw its initial contents.


As for storing the pixmaps, you can do that with a 1 QPixmap member, for the original image.

tommy
16th November 2007, 18:15
Thanks for your useful answer, I now know where to kind of start. My only problem is that I'm not at that level yet. I don't fully understand all the aspects of the general outline you provided.
May I ask you to be a bit more specific. My general questions are:
1. OK, I subclass QLabel. I guess I do it exacly like I subclassed MyWidget in the above example. So I guess the QLabel subclass is going to hold (under protected:) mousePressEvent(), mouseMoveEvent() and paintEvent(). Is it also going to create the m_pixmapLabel instance? If I put this in the QLabel subclass it needs to be in the appropriate constructor, meaning that I cannot add it to my mainLayout (which is subclassed in MyWidget).
2. Am I still going to have the MyWidget subclass for the pushbutton and everything else that is not the QLabel where the picture is going to appear?
3. How do I make the objects of the two different subclasses to interact? I mean how do I ensure that the mouse is going to work on the right object?
4. I guess my questions mostly all boil down to the fact that I am not getting how the mouse events work. Mouse seems to behave very differently from the usual signal/slot.
5. Maybe the easiest thing for me would be to look at some example code where people have done a similar thing. Do you know of any such postings.
Thanks a lot!