drawing a point over an image on QLabel - image

I displayed a picture on QLabel and wanted to take coordinates and paint a point on image on mouse click event. I am able to get coordinates but painter is painting point below my image on label, i want it above my image.
My code is :
main.cpp
#include "imageviewer.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
imageviewer w;
w.showMaximized();
return a.exec();
}
imageviewer.h
#include <QPushButton>
class imageviewer : public QLabel
{
Q_OBJECT
public:
explicit imageviewer(QWidget *parent = 0);
private slots:
void mousePressEvent(QMouseEvent * e);
void paintEvent(QPaintEvent * e);
private:
QLabel *label1 ;
int mFirstX;
int mFirstY;
bool mFirstClick;
bool mpaintflag;
};
#endif
imageviewer.cpp
#include <QtGui>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include "imageviewer.h"
#include <QDebug>
imageviewer::imageviewer(QWidget *parent)
: QLabel(parent)
{
label1 = new QLabel;
label1->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
QPixmap pm1("/home/nishu/Pictures/img_0002.jpg");
label1->setPixmap(pm1);
label1->adjustSize();
label1->setScaledContents(true);
QHBoxLayout *hlayout1 = new QHBoxLayout;
hlayout1->addWidget(label1);
setLayout(hlayout1);
}
void imageviewer :: mousePressEvent(QMouseEvent *e)
{
mFirstX=0;
mFirstY=0;
mFirstClick=true;
mpaintflag=false;
if(e->button() == Qt::LeftButton)
{
//store 1st point
if(mFirstClick)
{
mFirstX = e->x();
mFirstY = e->y();
mFirstClick = false;
mpaintflag = true;
qDebug() << "First image's coordinates" << mFirstX << "," << mFirstY ;
update();
}
}
}
void imageviewer :: paintEvent(QPaintEvent * e)
{
QLabel::paintEvent(e);
if(mpaintflag)
{
QPainter painter(this);
QPen paintpen(Qt::red);
paintpen.setWidth(10);
QPoint p1;
p1.setX(mFirstX);
p1.setY(mFirstY);
painter.setPen(paintpen);
painter.drawPoint(p1);
}
}
Help me to sort out what exactly problem is?

with line QPainter painter(this); you set QPainter to draw on your main widget instead of QLabel's pixmap. Change block to this and it will work:
if(mpaintflag)
{
QImage tmp(label1->pixmap()->toImage());
QPainter painter(&tmp);
QPen paintpen(Qt::red);
paintpen.setWidth(10);
QPoint p1;
p1.setX(mFirstX);
p1.setY(mFirstY);
painter.setPen(paintpen);
painter.drawPoint(p1);
label1->setPixmap(QPixmap::fromImage(tmp));
}
EDIT:
Just noticed, that you derived from QLabel, not from QWidget, as i assumed automatically, looking at layout. Indeed, you don't need label1 and layout inside of our imageviewer class. That whole point of subclassing is that you implement behavior and filter events the way you want it and then you add them to main widget if that is needed
EDIT2:
Imageviewer class should be derived from QLabel, remove label1 and layout, and paint not on image, but on imageviewer itself, i.e. this. Then you need to add new class to your program, which is derived from QMainwindow or QWidget for example, where you should include your imageviewer class, create layout and add your class to it like this:
#include "imageviewer.h"
//.... somewhere in constructor ....
imageviewer *viewer1=new imageviewer(this); // creating new object of imageviewer
viewer1->setPixmap(...);
hlayout1->addWidget(viewer1);

You derived your class from QLabel, so you should not create another QLabel *label1 and put it inside label's layout. That doesn't make any sense. Why would anyone put a label into a label? You need to remove label1 and use the imageviewer object as a label instead. Your constructor should contain only the following code:
setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
QPixmap pm1(...);
setPixmap(pm1);
adjustSize();
setScaledContents(true);
I've checked that it fixes your problem.

Related

Convert an uploaded from desktop image to black and white in Qt

My program consists of two functions: first a user clicks a button (btn_image) to upload an image from desktop and it displays on the label (lbl_image). Secondly, I push another button (cnv_image) in order to change the colors of that uploaded image to black and white.
I have managed to implement the first function: the image chosen by a user successfully displays. However, I am confused how to convert that image to b&w. I wrote a function that is triggered after clicking the cnv_image button, but the problem is to refer to that uploaded image. So, when I click cnv_image buttom the uploaded image simply disappears.
I tried to use image.load (ui->lbl_image) to refer to the label which contains the image but it shows a mistake.
How can I implement my second function?
void MainWindow::on_btn_image_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose"), "", tr("Images (*.png *.jpg *jpeg)"));
if (QString::compare(fileName, QString()) != 0) {
QImage image;
bool valid = image.load(fileName);
if (valid) {
ui->lbl_image->setPixmap(QPixmap::fromImage(image));
}
}
}
void MainWindow::on_cnv_image_clicked()
{
QImage image;
image.load(ui->lbl_image);
QSize sizeImage = image.size();
int width = sizeImage.width(), height = sizeImage.height();
QRgb color;
for (int f1=0; f1<width; f1++) {
for (int f2=0; f2<height; f2++) {
int gray = qGray(color);
image.setPixel(f1, f2, qRgb(gray, gray, gray));
}
}
ui->lbl_image->setPixmap(QPixmap::fromImage(image));
}
I update your code, I add QImage image; as private member of MainWindow class so In mainwindow.h :
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui
{
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow: public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_btn_image_clicked();
void on_cnv_image_clicked();
private:
Ui::MainWindow *ui;
QImage image;
};
#endif // MAINWINDOW_H
and in on_cnv_image_clicked function
void MainWindow::on_cnv_image_clicked()
{
QSize sizeImage = image.size();
int width = sizeImage.width(), height = sizeImage.height();
QRgb color;
int value;
for (int f1 = 0; f1 < width; f1++)
{
for (int f2 = 0; f2 < height; f2++)
{
color = image.pixel(f1, f2);
int gray = (qRed(color) + qGreen(color) + qBlue(color)) / 3;
image.setPixel(f1, f2, qRgb(gray, gray, gray));
}
}
ui->lbl_image->setPixmap(QPixmap::fromImage(image));
ui->lbl_image->setScaledContents(true);
}
Result :
Welcome to Stackoverflow!
First of all, it's a good idea to keep a copy of the QImage in your class when you load it. It helps to avoid extra conversions from QPixmap to QImage in next steps. I'll skip it because it's out of the scope of your question.
You can use QImage::convertTo to convert the format of a QImage in place. It means that, it does not create a new QImage. As per documentation it may detach the QImage. You can read more about Implicit Sharing if you are interested.
So, the implementation should be something like:
void MainWindow::on_cnv_image_clicked()
{
QImage image = ui->lbl_image->pixmap().toImage();
image.convertTo(QImage::Format_Grayscale8);
ui->lbl_image->setPixmap(QPixmap::fromImage(image));
}
Take a look at the list of QImage::Formats to evaluate other grayscale/mono options.

Show grey level value of pixel in Qt when the mouse is over it

Currently I am working on the display of gray level image with zoom feature. I am able to get the position of the pixel and the zoom feature is working well. However I encountered two problems:
1.) How can I get the grey level value of the pixel that is pointed by the mouse? I only managed to obtain the rgb value through “QRgb rgbValue = pix.toImage().pixel(x,y)”. How can I convert it into grey level value? Or is there any direct way to get the grey level value of the pixel.
2.) I have implemented “mouseMoveEvent(QMouseEvent *event)” and “setMouseTracking(true)”. However the function of “mouseMoveEvent(QMouseEvent *event)” is not functioning when I move the mouse. What is wrong with my code?
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsItem>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
protected:
void mouseMoveEvent(QMouseEvent * event);
private:
Ui::MainWindow *ui;
QGraphicsScene* scene;
QGraphicsItem* item;
QPixmap pix;
};
#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);
QImage image("E:/image_00002.bmp");
pix = QPixmap::fromImage(image);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
scene->addPixmap(pix);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
ui->graphicsView->setMouseTracking(true);
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
QPoint local_pt = ui->graphicsView->mapFromGlobal(event->globalPos());
QPointF img_coord_pt = ui->graphicsView->mapToScene(local_pt);
double x = img_coord_pt.x();
double y = img_coord_pt.y();
/* How can I get a gray level image here */
QRgb rgbValue = pix.toImage().pixel(x,y);
ui->label_X->setText(QString::number(x));
ui->label_Y->setText(QString::number(y));
ui->label_Value->setText(QString::number(rgbValue));
}
To elaborate a bit on what hank said. In order for your QMainWindow to receive the events from the QGraphicsScene you need to install an event filter (see http://qt-project.org/doc/qt-4.8/qobject.html#installEventFilter ). Quoting from the DOCs:
An event filter is an object that receives all events that are sent to this object.
The filter can either stop the event or forward it to this object.
In order to process the events you need to define an eventFilter method in your main window class. Below are the on_pushButton_clicked() and eventFilter() methods that should do what you want:
void MainWindow::on_pushButton_clicked()
{
ui->graphicsView->setMouseTracking(true);
scene->installEventFilter(this);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::GraphicsSceneMouseMove ) {
QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
QPointF img_coord_pt = mouseEvent->scenePos();
double x = img_coord_pt.x();
double y = img_coord_pt.y();
QColor color = QColor(pix.toImage().pixel(x,y));
int average = (color.red()+color.green()+color.blue())/3;
ui->label_X->setText(QString::number(x));
ui->label_Y->setText(QString::number(y));
ui->label_Value->setText(QString::number(average));
return true;
} else {
return QObject::eventFilter(obj, event);
}
}
Does this help?

Image on Qt QMdiArea background

Qt developers!
Is there are way to add image on the background of my midArea like on picture below?
I know I can use something like this
QImage img("logo.jpg");
mdiArea->setBackground(img);
But I don't need any repeat of my image on the background.
Thank you!
As I said in my comment above, you can sub-class the QMdiArea, override its paintEvent() function and draw your logo image yourself (in the bottom right corner). Here is the sample code that implements the mentioned idea:
class MdiArea : public QMdiArea
{
public:
MdiArea(QWidget *parent = 0)
:
QMdiArea(parent),
m_pixmap("logo.jpg")
{}
protected:
void paintEvent(QPaintEvent *event)
{
QMdiArea::paintEvent(event);
QPainter painter(viewport());
// Calculate the logo position - the bottom right corner of the mdi area.
int x = width() - m_pixmap.width();
int y = height() - m_pixmap.height();
painter.drawPixmap(x, y, m_pixmap);
}
private:
// Store the logo image.
QPixmap m_pixmap;
};
And finally use the custom mdi area in the main window:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow mainWindow;
QMdiArea *mdiArea = new MdiArea(&mainWindow);
mainWindow.setCentralWidget(mdiArea);
mainWindow.show();
return app.exec();
}

zoom the Image Element in QML. without using QImage::scaled(), QPixmap::scaled().

I am trying to implement zoom in / out of a image using Image Element in QML.
I want the Pixel scale to be modified if i double click / pinch zoom.
How can i implement this without using QImage::scaled(), QPixmap::scaled().
Basically i dont want to involve Qt logic into my application.
I want Similar effect to hat is happening in the following tutorial
http://harmattan-dev.nokia.com/docs/library/html/qt4/widgets-imageviewer.html
But without Qt Logic in the app.
i know it's not the best answer but i cannot write a comment (i got less then 50 reps...) but zooming in/out qml is easy using PinchArea if you add a MouseArea you can also use onClicked or onDoubleClicked.... there is a useful example for pinch to zoom here(qt.git).
The ImageViewer example you posted got features like print save and so on, and you don't want to use "qt Logic", so i think you will need to use "qt Logic". I would wirte one class for each feature and implement it where i need it.
first of all i think this could help you(Extending QML Functionalities using C++).
Here a (not tested) example for saveing and reading a file:
fileio.h
#ifndef FILEIO_H
#define FILEIO_H
#include <QObject>
#include <QVariant>
class FileIO : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(QString source
READ source
WRITE setSource
NOTIFY sourceChanged)
explicit FileIO(QObject *parent = 0);
Q_INVOKABLE QString source();
Q_INVOKABLE QVariant read();
Q_INVOKABLE bool write(const QVariant& data);
public slots:
void setSource(const QString& source) ;
signals:
void sourceChanged(const QString& source);
void error(const QString& msg);
private:
QString mSource;
};
#endif // FILEIO_H
and fileio.cpp
#include "fileio.h"
#include <QFile>
#include <QDataStream>
#include <QString>
#include <QDebug>
FileIO::FileIO(QObject *parent) :
QObject(parent){
}
QString FileIO::source(){
return mSource;
}
QVariant FileIO::read()
{
if (mSource.isEmpty()){
emit error("source is empty");
return QVariant();
}
QFile file(mSource);
QVariant fileContent; // i dont know if you can use QImage but i think you cann't
if ( file.open(QIODevice::ReadOnly) ) {
QDataStream t( &file );
fileContent << t //you may have to reimplement "<<" operator
file.close();
} else {
emit error("Unable to open the file");
return QVariant();
}
return fileContent;
}.....
and register that in main.cpp like
qmlRegisterType<FileIO, 1>("FileIO", 1, 0, "FileIO");
so you can import it in your qml like
import FileIO 1.0
Rectangle{
id: someId
...
FileIO{
id: yourAccessToYourFileIOclass
}
}
i've not tested that code yet, i hope it helps.
for better answers post what you want to do exacly save, print , any filters....
p.s. I also would create a model in qt and bring it to qml...
greez Matthias

Qt- how to move a picture in screen according to mouse move

I am trying to do a chess game. So I want to move the chess coin picture when the user clicks and drags the coin.
Which class I have to use
update
At last I am just editing the puzzle code which is given in drag and drop examples. Thereby I am trying to know the functions. But Still I am not getting certain things. I am executing the code below but the picture is not moving. And when I am closing I am getting a question from the OS(Windows XP), that there is an unhandled win32 exception in my program, so whether you want to debug or not. Here the code
#include<QApplication>
#include<QMainWindow>
#include<QWidget>
#include<QMenu>
#include<QMenuBar>
#include<QPainter>
#include<QFrame>
#include<QHBoxLayout>
#include<QScrollBar>
#include<QLabel>
#include<QScrollArea>
#include<QListWidgetItem>
#include<QByteArray>
#include<QDataStream>
#include<QMimeData>
#include<QDrag>
#include<QMouseEvent>
#include<iostream>
using namespace std;
class MyWindow:public QMainWindow
{
public:
MyWindow();
};
class MyWidget:public QWidget
{
QPixmap picture;
QPixmap temp;
public:
MyWidget();
void paintEvent(QPaintEvent * event);
void mousePressEvent(QMouseEvent * mouse);
void dragEnterEvent(QDragEnterEvent * dragEnterEvent);
void dragLeaveEvent(QDragLeaveEvent * event);
void dragMoveEvent(QDragMoveEvent * event);
void dropEvent(QDropEvent * event);
};
int main(int argc,char *argv[])
{
Q_INIT_RESOURCE(puzzle);
QApplication app(argc,argv);
MyWindow mainWindow;
mainWindow.show();
return app.exec();
}
MyWindow::MyWindow():QMainWindow()
{
setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
QMenu * fileMenu=menuBar()->addMenu(QObject::tr("Options"));
QAction * restartAction = fileMenu->addAction(tr("NewGame"));
QAction * exitAction = fileMenu->addAction(tr("Exit"));
exitAction->setShortcuts(QKeySequence::Quit);
QWidget * tempWidget=new MyWidget();
QFrame * newFrame=new QFrame();
QHBoxLayout * horizontal= new QHBoxLayout(newFrame);
horizontal->addWidget(tempWidget);
setCentralWidget(newFrame);
}
MyWidget::MyWidget():QWidget()
{
setMinimumSize(10,10);
setMaximumSize(1000,1000);
}
void MyWidget::dragEnterEvent(QDragEnterEvent * dragEnterEvent)
{
if(dragEnterEvent->mimeData()->hasFormat("chess"))
dragEnterEvent->accept();
else
dragEnterEvent->ignore();
}
void MyWidget::dragLeaveEvent(QDragLeaveEvent *event)
{
update(QRect(0,0,picture.width(),picture.height()));
event->accept();
}
void MyWidget::dragMoveEvent(QDragMoveEvent *event)
{
if(event->mimeData()->hasFormat("chess"))
{
event->setDropAction(Qt::MoveAction);
event->accept();
}
else
event->ignore();
update(QRect(0,0,picture.width(),picture.height()));
}
void MyWidget::dropEvent(QDropEvent *event)
{
if(event->mimeData()->hasFormat("chess"))
{
event->setDropAction(Qt::MoveAction);
event->accept();
}
else
event->ignore();
update(QRect(0,0,picture.width(),picture.height()));
}
void MyWidget::paintEvent(QPaintEvent * event)
{
QPainter painter;
painter.begin(this);
picture=QPixmap("C:\\Board").scaled(600,600,Qt::KeepAspectRatioByExpanding,Qt::SmoothTransformation);
setFixedSize(picture.size());
painter.drawPixmap(0,0,picture.height(),picture.width(),picture);
temp=QPixmap("C:\\blackElephant").scaled(60,30,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
painter.drawPixmap(0,0,temp.height(),temp.width(),temp);
painter.end();
}
void MyWidget::mousePressEvent(QMouseEvent * mouse)
{
QByteArray array;
QDataStream stream(&array,QIODevice::WriteOnly);
stream << temp;
QMimeData mimeData;
mimeData.setData("chess",array);
QDrag * newDrag=new QDrag(this);
newDrag->setMimeData(&mimeData);
newDrag->setHotSpot(mouse->pos());
newDrag->setPixmap(temp);
update(QRect(0,0,picture.width(),picture.height()));
}
any help will be appreciated.
Have a look at QGraphicsView, it gives you a canvas to put items on, and even can do animations. Should make things a lot easier than painting pixmaps by hand.
For drag and drop, you have to use QDrag class (check Qt examples on drag for details). QDrag class has a property called pixmap (pixmap(), setPixmap()) that can be used to set the image associated with the drag operation.

Resources