Resize a QQuickPaintedItem in QML - qt

I use a custom QQuickPaintedItem to display a Qimage in QML.
I registered it using:
main.cpp
qmlRegisterType<ImageItem>("myextension", 1, 0, "ImageItem");
ImageItem.h
class ImageItem : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QImage image READ image WRITE setImage NOTIFY imageChanged)
public:
ImageItem(QQuickItem *parent = nullptr);
Q_INVOKABLE void setImage(const QImage &image);
Q_INVOKABLE void resize(const int& width);
void paint(QPainter *painter);
QImage image() const;
signals:
void imageChanged();
private:
QImage current_image;
};
How can I resize QImage in QML for displaying purposes?

Didnt expect it would be that simple.
ImageItem {
image: sqlImageData
id: myIcon
width: 50 //resizing
height:50 //resizing
}

Related

How not inherit class QGraphicsTextItem and implement class UTextItem?

How not inherit class QGraphicsTextItem and implement class UTextItem ,in Qt.
I don't need code similar to below
#include <QGraphicsTextItem>
class UTextItem: public QGraphicsTextItem
{
public:
UTextItem(QGraphicsItem *parent = nullptr);
}
I need code similar to below,I need code similar to below, and not the text drawn by the drawText function, because the drawn string will lose detail when scaled.
#include <QGraphicsItem>
class UTextItem: public QGraphicsItem
{
public:
UTextItem(QGraphicsItem *parent = nullptr);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
}
Because my current requirement is to have a TextItem that can be deformed, flipped horizontally and vertically, and the scaling of drawText will be distorted, so I can't use this method.
By reading the source code, I found the scaling problem solution myself.
void UTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QFont font;
font.setPixelSize(0.75 * qMin(boundingRect().width(), boundingRect().height()));
painter->save();
painter->setFont(font);
painter->drawText(boundingRect(), Qt::AlignCenter, "hello world");
painter->restore();
}

QImage and Threads

I am having problems with QImages and Qthreads.
I am trying to load big images in a Thread and then display them as QPixmap on a QLabel.
My problem is that as long as I don't use a different thread to load the QImages, everything is perfect but as soon as I use a different thread, nothing is renderder.
Though I still have a valid size for my QImage.
The thing that puzzles me is that, if I just comment the 22nd line in the cpp that moves the loader to the other thread, the label displays nicely.
Does anyone have an idea?
Here is my very simplified code:
Header :
class Loader : public QObject
{
Q_OBJECT
public:
explicit Loader(QObject *parent = 0);
signals:
void imageLoaded(QString, const QImage &);
public slots:
void loadImage(const QString& fichier);
};
namespace Ui {
class MainWindow;
}
class LoaderImages;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void loadImage(const QString& dossier);
private slots:
void imageAvailable(const QString& dossier, const QImage& img);
private:
Ui::MainWindow *ui;
//QString mDossier;
Loader* mLoader;
//QMap<QString, QImage*> mMapDesImages;
int mWidth;
};
cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFile>
#include <QPixmap>
#include <QImage>
#include <QDir>
#include <QThread>
#include <QDebug>
#include <QLabel>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
mLoader(new Loader(NULL)),
mWidth(0)
{
ui->setupUi(this);
QThread* thread = new QThread(this);
mLoader->moveToThread(thread);
thread->start();
connect(this, SIGNAL(loadImage(QString)), mLoader, SLOT(loadImage(QString)));
connect(mLoader, SIGNAL(imageLoaded(QString,QImage)), this, SLOT(imageAvailable(QString,QImage)));
emit loadImage("C:/img.jpg");
}
void MainWindow::imageAvailable(const QString &dossier, const QImage& img)
{
mWidth += (img.width() + 20);
ui->mScrollContent->setMinimumSize(mWidth,img.height());
QLabel* lab = new QLabel(ui->mScrollContent);
lab->setFixedSize(img.width(), img.height());
lab->setGeometry(mWidth - img.width() + 20, 0, img.width(), img.height());
lab->setPixmap(QPixmap::fromImage(img));
}
MainWindow::~MainWindow()
{
delete mLoader;
delete ui;
}
Loader::Loader(QObject *parent) :
QObject(parent)
{
}
void Loader::loadImage(const QString& fichier)
{
QImage* image = new QImage(fichier);
emit imageLoaded(fichier, *image);
}
Thx!
There are several mistakes:
You're not showing the label. When the image loader is in the GUI thread, the image is loaded and the label added to the contents pane before the main window is shown. Since the parent is shown, the children become visible.
When the loading is done in another thread, you'll be adding image labels to a widget that's already shown. Such child widgets are not visible unless you explicitly show() them.
You're leaking the image in loadImage. There's no reason to put that QImage on the heap.
You're allowing a running QThread to be destructed. That's a common error since QThread is essentially broken by design. Sane C++ classes should be always destructible. QThread isn't. Thus you need a workaround.
You're not setting the minimum height of the contents widget as well.
You might wish to consider the use QtConcurrent::run instead of a dedicated thread. This is especially worthwhile when the operation you're undertaking is a one liner, more or less. I've shown both, the implementations are alternated between at runtime. Note that you need to add the concurrent module and CONFIG += c++11 to the project file.
Style bugs:
There's no reason to pass NULL for default-valued parameters that are already zero.
There's no reason to keep QObject members that have the lifetime of the parent object on the heap, if such members are constructed along with the parent object.
Just because Qt Creator comes with silly template files doesn't mean that you shouldn't be using a std::unique_ptr or QScopedPointer to hold the ui member. Naked pointers should almost never be members unless they're pointers to QObjects with parents.
As quite a bit of the code is missing, I can't really tell what else might be wrong. Below is a complete example.
// https://github.com/KubaO/stackoverflown/tree/master/questions/image-loader-24853687
#include <QtWidgets>
#include <QtConcurrent>
class Thread final : public QThread {
public:
~Thread() { quit(); wait(); }
};
class Loader : public QObject
{
Q_OBJECT
public:
explicit Loader(QObject *parent = nullptr) : QObject(parent) {}
Q_SIGNAL void imageLoaded(const QString &, const QImage &);
Q_SLOT void loadImage(const QString& fichier) {
QImage img(fichier);
if (! img.isNull()) emit imageLoaded(fichier, img);
}
};
class MainWindow : public QWidget
{
Q_OBJECT
Loader m_loader;
Thread m_loaderThread;
QGridLayout m_layout{this};
QPushButton m_open{"Open"};
QScrollArea m_view;
QWidget m_content;
int m_width{};
bool m_threadImpl = true;
Q_SIGNAL void loadImage(const QString &);
Q_SIGNAL void imageLoaded(const QString &, const QImage & img);
Q_SLOT void imageAvailable(const QString &, const QImage & img) {
int spacing = 20;
if (m_width) m_width += spacing;
auto lab = new QLabel(&m_content);
lab->setFixedSize(img.width(), img.height());
lab->setGeometry(m_width, 0, img.width(), img.height());
lab->setPixmap(QPixmap::fromImage(img));
lab->show();
m_width += img.width();
m_content.setMinimumWidth(m_width);
m_content.setMinimumHeight(qMax(m_content.minimumHeight(), img.height()));
}
Q_SLOT void open() {
auto dialog = new QFileDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
if (m_threadImpl)
connect(dialog, &QFileDialog::fileSelected, this, &MainWindow::loadImage);
else
connect(dialog, &QFileDialog::fileSelected, [this](const QString & fichier){
QtConcurrent::run([this, fichier]{
QImage img(fichier);
if (! img.isNull()) emit this->imageLoaded(fichier, img);
});
});
m_threadImpl = !m_threadImpl;
}
public:
explicit MainWindow(QWidget *parent = nullptr) : QWidget(parent) {
m_layout.addWidget(&m_open);
m_layout.addWidget(&m_view);
m_view.setWidget(&m_content);
m_loader.moveToThread(&m_loaderThread);
m_loaderThread.start();
connect(&m_open, &QPushButton::clicked, this, &MainWindow::open);
connect(this, &MainWindow::loadImage, &m_loader, &Loader::loadImage);
connect(this, &MainWindow::imageLoaded, this, &MainWindow::imageAvailable);
connect(&m_loader, &Loader::imageLoaded, this, &MainWindow::imageAvailable);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
#include "main.moc"

How to handle right mouse click event for QGraphicsItem?

I have a class derived from QGraphicsItem, which is basically like this:
class MyRect: public QObject, public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
explicit MyRect(QObject *parent = 0);
MyRect(QColor fillColor, float val, QString txt = "", bool isLeaf = false);
int width, height;
protected:
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
virtual QRectF boundingRect() const;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};
The problem is the mouseReleaseEvent and mousePressEvent only accept QGraphicsSceneMouseEvent argument which cannot detect right button click. I know there is a mousePressEvent(QMouseEvent *event) version that I can use, but it seems not work for QGraphicsItem....Just cannot get stuck here...I appreciate your answer.
Try re-implementing QGraphicsItem::contextMenuEvent and checking the QGraphicsSceneContextMenuEvent::Reason for if the event was caused by a mouse click.

Extending QGraphicsScene

I am extending QGraphicsItem to be added to a extended QGraphicsSene. when I added the extended item to the scene and the scene to the graphics view in the normal way it shows the image but when I added the image as follows it does not show. could some one please check this out and tell me the issue.
header
#ifndef IMAGEMAP_H
#define IMAGEMAP_H
#include <QGraphicsItem>
#include <QGraphicsScene>
class ScanImage : public QGraphicsItem
{
public:
ScanImage(const QString imgsrc);
~ScanImage();
void setImageSource(const QString is);
QString imageSource();
QRectF boundingRect() const;
void paint( QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);
private:
QString imgsrc;
};
class ImageHolder : public QGraphicsScene
{
public:
ImageHolder();
~ImageHolder();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent);
private:
QRectF selectedRect;
};
#endif //
source
#include "imagemap.h"
#include "QtGui"
ScanImage::ScanImage(const QString is)
{
imgsrc=is;
update();
}
ScanImage::~ScanImage()
{
}
ImageHolder::ImageHolder()
{
setSceneRect(0.0,0.0,512.0,512.0);
ScanImage im("2.jpg");
im.setZValue(1.0);
im.setVisible(true);
addItem(&im);
}
ImageHolder::~ImageHolder()
{
}
void ScanImage::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
qDebug() <<event->pos();
}
void ImageHolder::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
qDebug() <<event->scenePos().rx();
selectedRect.setTopLeft(event->scenePos());
}
void ImageHolder::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
qDebug() <<mouseEvent->scenePos().ry();
selectedRect.setBottomRight(mouseEvent->scenePos());
addRect ( selectedRect);
}
QRectF ScanImage::boundingRect() const
{
return QRectF(0.0, 0.0, 512.0, 512.0);
}
void ScanImage::paint( QPainter* painter,
const QStyleOptionGraphicsItem*,
QWidget* )
{
QRectF target(0.0, 0.0, 512.0, 512.0);
QRectF source(0.0, 0.0, 512.0, 512.0);
painter->drawImage(target, QImage(imgsrc),source);
}
void ScanImage::setImageSource(QString is)
{
imgsrc = is;
}
QString ScanImage::imageSource()
{
return imgsrc;
}
main
int main(int argv, char* argc[])
{
QApplication app(argv,argc);
ImageHolder scene;
QGraphicsView view(&scene);
view.resize(512,512);
view.show();
return app.exec();
}
You are adding a QGraphicsItem allocated as a local variable on the QGraphicsScene constructor's stack. Once the constructor is finished, the objects on its stack are automatically deallocated (i.e. deleted) and in your case removed from the scene. Use new operator to create the item.

Background image not showing on QWidget

I am designing a window using QWidget and set a background image, when i run my code i am not getting background image but showing window with default background.
Can anyone help me what may be the reason.
// In header file
class STUDY : public QMainWindow, public Ui::STUDYClass
{
Q_OBJECT
public:
STUDY(QWidget *parent = 0, Qt::WFlags flags = 0);
~STUDY();
QPaintEvent *p2;
void backgroundImage();
void paintEvent(QPaintEvent *);
public slots:
};
//Constructor and paintEvent function in Cpp file
STUDY::STUDY(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
setupUi(this);
backgroundImage();
update();
paintEvent(p2);
}
void STUDY::paintEvent(QPaintEvent *p2)
{
QPixmap pixmap;
pixmap.load(":/STUDY/Resources/Homepage.png");
QPainter paint(this);
paint.drawPixmap(0, 0, pixmap);
QWidget::paintEvent(p2);
}
There are many ways to set the background color to window,
I will give you one simple technique. i.e Override, the paintEvent of the QWidget. and draw the pixmap there.
Here is the sample widget code, i hope it helps
Header file
#ifndef QBACKGROUNDIMAGE_H
#define QBACKGROUNDIMAGE_H
#include <QtGui/QMainWindow>
#include "ui_QbackgroundImage.h"
#include <QtGui>
class backgroundImgWidget;
class QbackgroundImage : public QMainWindow
{
Q_OBJECT
public:
QbackgroundImage(QWidget *parent = 0);
~QbackgroundImage();
private:
Ui::QbackgroundImage ui;
};
class backgroundImgWidget : public QWidget
{
Q_OBJECT
public:
backgroundImgWidget(QWidget *parent = 0);
~backgroundImgWidget();
protected:
void paintEvent(QPaintEvent *p2);
};
#endif // QBACKGROUNDIMAGE_H
CPP file
#include "QbackgroundImage.h"
QbackgroundImage::QbackgroundImage(QWidget *parent)
: QMainWindow(parent)
{
// ui.setupUi(this);
backgroundImgWidget* widget = new backgroundImgWidget();
setCentralWidget(widget);
}
QbackgroundImage::~QbackgroundImage()
{
}
backgroundImgWidget::backgroundImgWidget(QWidget *parent):QWidget(parent)
{
}
backgroundImgWidget::~backgroundImgWidget()
{
}
void backgroundImgWidget::paintEvent(QPaintEvent *p2)
{
QPixmap pixmap;
pixmap.load(":/new/prefix1/Sunset.jpg");
QPainter paint(this);
paint.drawPixmap(0, 0, pixmap);
QWidget::paintEvent(p2);
}
You can reimplement paintEvent:
void Widget::paintEvent( QPaintEvent* e )
{
QPainter painter( this );
painter.drawPixmap( 0, 0, QPixmap(":/new/prefix1/picture001.png").scaled(size()));
QWidget::paintEvent( e );
}

Resources