Qt5 and QML: How to update QQuickPaintedItem after widget resize? - image

I'll be very appreciated for help!
i created a custom object, inherited from QQuickPaintedItem and send it to QML application.
It goes well, but there is some issue.
I need to repaint scaled image every time widget changes it's own size.
But i can't get it how to make it in C++. It call's paint method only once.
Any suggestions?
Source code:
myimage.h
#ifndef MYIMAGE_H
#define MYIMAGE_H
#include <QQuickPaintedItem>
#include <QQuickItem>
#include <QPainter>
class MyImage : public QQuickPaintedItem
{
Q_OBJECT
public:
explicit MyImage(QQuickItem *parent = 0);
void paint(QPainter* painter) override;
signals:
public slots:
};
#endif // MYIMAGE_H
myimage.cpp
#include "layerimage.h"
MyImage::MyImage(QQuickItem *parent) : QQuickPaintedItem(parent)
{
setImplicitWidth(600);
setImplicitHeight(600);
}
void MyImage::paint(QPainter *painter)
{
QImage firstImage("e:/image1.png");
QImage secondImage("e:/image2.png");
secondImage = secondImage.mirrored(false, true);
firstImage = firstImage.scaled(width(), height(),Qt::KeepAspectRatio);
secondImage = secondImage.scaled(width(), height(),Qt::KeepAspectRatio);
painter->drawImage(0,0, firstImage);
painter->setOpacity(0.5);
painter->drawImage(0,0, secondImage);
}
main.cpp
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "myimage.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
qmlRegisterType<MyImage>("CustomImage", 1, 0 , "MyImage");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
main.qml
import QtQuick 2.5
import QtQuick.Controls 1.3
import CustomImage 1.0
ApplicationWindow {
visible: true
width: 900
height: 900
minimumWidth: 900
minimumHeight: 480
title: qsTr("Checker")
Rectangle
{
id: image
color: "transparent"
border.color: "red"
anchors
{
margins: 20
centerIn: parent
fill: parent
}
MyImage
{
anchors
{
centerIn: parent
}
}
}
}

Okey. I have found a solution. Seems like i need make MyImage element anchors.fill: parent. Or set width and height equal to parents size.
After that it will call paint every resize window moment!

Related

Changing image's pixel values by using QSlider in Qt

I am new at programming Qt.I have a Gui. It has slider and button. Also I can
get image as input and put it to a second label. The thing that I cannot do
getting pixels of image and change them with respect to the slider value.
#ifndef UI_TEST_H
#define UI_TEST_H
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenu>
#include <QLabel>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QProgressBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QSlider>
#include <QtWidgets/QSplitter>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QToolBar>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_TestClass
{
public:
QWidget *centralWidget;
QPushButton *pushButton;
QSplitter *splitter;
QSlider *slider;
QProgressBar *progressBar;
QMenuBar *menuBar;
QMenu *menuTest;
QToolBar *mainToolBar;
QStatusBar *statusBar;
void setupUi(QMainWindow *TestClass)
{
if (TestClass->objectName().isEmpty())
TestClass->setObjectName(QStringLiteral("TestClass"));
TestClass->resize(528, 400);
centralWidget = new QWidget(TestClass);
centralWidget->setObjectName(QStringLiteral("centralWidget"));
pushButton = new QPushButton(centralWidget);
pushButton->setObjectName(QStringLiteral("pushButton"));
pushButton->setGeometry(QRect(50, 230, 75, 23));
splitter = new QSplitter(centralWidget);
splitter->setObjectName(QStringLiteral("splitter"));
splitter->setGeometry(QRect(40, 110, 241, 43));
splitter->setOrientation(Qt::Vertical);
slider = new QSlider(splitter);
slider->setObjectName(QStringLiteral("slide"));
slider->setOrientation(Qt::Horizontal);
splitter->addWidget(slider);
progressBar = new QProgressBar(splitter);
progressBar->setObjectName(QStringLiteral("progressBar"));
progressBar->setValue(24);
splitter->addWidget(progressBar);
TestClass->setCentralWidget(centralWidget);
menuBar = new QMenuBar(TestClass);
menuBar->setObjectName(QStringLiteral("menuBar"));
menuBar->setGeometry(QRect(0, 0, 528, 21));
menuTest = new QMenu(menuBar);
menuTest->setObjectName(QStringLiteral("menuTest"));
TestClass->setMenuBar(menuBar);
mainToolBar = new QToolBar(TestClass);
mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
TestClass->addToolBar(Qt::TopToolBarArea, mainToolBar);
statusBar = new QStatusBar(TestClass);
statusBar->setObjectName(QStringLiteral("statusBar"));
TestClass->setStatusBar(statusBar);
menuBar->addAction(menuTest->menuAction());
retranslateUi(TestClass);
QObject::connect(slider, SIGNAL(valueChanged(int)), progressBar, SLOT(setValue(int)));
QMetaObject::connectSlotsByName(TestClass);
} // setupUi
void retranslateUi(QMainWindow *TestClass)
{
TestClass->setWindowTitle(QApplication::translate("TestClass", "Test", 0));
pushButton->setText(QApplication::translate("TestClass", "Button", 0));
menuTest->setTitle(QApplication::translate("TestClass", "Test", 0));
} // retranslateUi
};
namespace Ui {
class TestClass: public Ui_TestClass {};
} /
#include "test.h"
#include <QtWidgets/QApplication>
#include <QtGui>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Test w;
w.show();
QImage myImage;
myImage.load("Baboon.bmp");
QLabel myLabel;
myLabel.setPixmap(QPixmap::fromImage(myImage));
myLabel.show();
return a.exec();
}

Textarea slow for logging

I have a Qt application and I'd like to show some log. I use a TextArea. However, if the log is large or the events come too fast the GUI can't draw Textarea fast enough.
I have analyzed this problem with Qt Creator (QML Profiler) and if the log is large it takes 300 ms to draw the GUI. I use this software on a Raspberry Pi2.
Any ideas how to solve this? Should I use other QML controls? Thanks.
QML code:
TextArea {
text: appHandler.rawCommunication
readOnly: true
}
C++ code:
Q_PROPERTY(QString rawCommunication READ rawCommunication WRITE setrawCommunication NOTIFY rawCommunicationChanged)
void setrawCommunication(QString val)
{
val.append("\n");
val.append(m_rawCommunication);
m_rawCommunication = val;
emit rawCommunicationChanged(m_rawCommunication);
}
Use a view, like ListView. They instantiate their delegates as needed, based on which data the view says it needs to show depending on the position the user is at in the list. This means that they perform much better for visualising large amounts of data than items like TextArea, which in your case is going to keep a massive, ever-growing string in memory.
Your delegate could then be a TextArea, so you'd have one editable block of text per log line. However, if you don't need styling, I'd recommend going with something a bit lighter, like TextEdit. Taking it one step further: if you don't need editable text, use plain old Text. Switching to these might not make much of a difference, but if you're still seeing slowness (and have lots of delegates visible at a time), it's worth a try.
I tried the ListView suggestion but it has several drawbacks:
No easy way to keep the view positioned at the bottom when new output is added
No selection across lines/delegates
So I ended up using a cached TextArea, updating once every second:
TextArea {
id: outputArea_text
wrapMode: TextArea.Wrap
readOnly: true
font.family: "Ubuntu Mono, times"
function appendText(text){
logCache += text + "\n";
update_timer.start();
}
property string logCache: ""
Timer {
id: update_timer
// Update every second
interval: 1000
running: false
repeat: false
onTriggered: {
outputArea_text.append(outputArea_text.logCache);
outputArea_text.logCache = "";
}
}
Component.onCompleted: {
my_signal.connect(outputArea_text.appendText)
}
}
try this approach:
create a c++ logger class
append all logs to this class
and print them using some action, example a button click
this will solve your performance issue
Example of code:
Logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include <QQmlContext>
#include <QObject>
#include <QStringList>
#include <QQmlEngine>
#include <QString>
#include <QtCore>
#include <QDebug>
class Logger : public QObject
{
Q_OBJECT
public:
explicit Logger(QObject *parent = 0);
~Logger();
Q_INVOKABLE QStringList *getLogStream();
Q_INVOKABLE void printLogStream();
Q_INVOKABLE void appendLog(QString log);
Q_INVOKABLE void log(QString log="");
Q_INVOKABLE void log(QString fileName, QString log);
signals:
public slots:
private:
QStringList* stringStream_;
};
#endif // LOGGER_H
Logger.cpp
#include "logger.h"
Logger::Logger(QObject *parent) :
QObject(parent),
stringStream_(new QStringList)
{
}
~Logger(){
if(stringStream_ != NULL)
{
delete stringStream_;
stringStream_ = NULL;
}
}
QStringList* Logger::getLogStream(){
return stringStream_;
}
void Logger::printLogStream()
{
QStringListIterator itr(*stringStream_);
while (itr.hasNext())
qDebug()<< itr.next()<<"\n";
}
void Logger::appendLog(QString log){
stringStream_->push_back(log) ;
}
void Logger::log(QString fileName,QString log)
{
#ifdef ENABLElogs
fileName.push_front(" [");
if(!fileName.contains(".qml"))
{
fileName.append(".qml]:");
}
qDebug()<<fileName<<log;
#else
Q_UNUSED(log);
Q_UNUSED(fileName);
#endif
}
void Logger::log(QString log)
{
#ifdef ENABLElogs
qDebug()<<log;
#else
Q_UNUSED(log);
#endif
}
main.cpp
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include "logger.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QtQuick2ApplicationViewer *viewer = new QtQuick2ApplicationViewer;
Logger* stream = new Logger;
viewer->rootContext()->setContextProperty("Stream",stream);
viewer->setMainQmlFile(QStringLiteral("qml/project/main.qml"));
viewer->showExpanded();
return app.exec();
}
main.qml
import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
width: 800
height: 480
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
Component.onCompleted: Stream.appendLog("Text object is completed")
}
Column{
x:300
Button{
text:"append"
onClicked: {
Stream.appendLog("MouseArea object clicked")
}
Component.onCompleted: Stream.appendLog("Button object is completed")
}
Button{
text:"logger"
onClicked: {
Stream.printLogStream()
}
Component.onCompleted: Stream.appendLog("Button logger object is completed")
}
}
TextArea{
text:"blablabla"
Component.onCompleted: Stream.appendLog("TextArea object is completed")
}
Component.onCompleted: Stream.appendLog("the main object is completed")
}
project.pro
#add this line
# comment it, run qmake and recompile to disable logs
DEFINES += ENABLElogs
using this approch you can stop all logs with a single line change when you want to release your soft
However, I have included complete code, using "QAbstractListModel" for a Logging heavy data to QML
listmodel.h
#ifndef LISTMODEL_H
#define LISTMODEL_H
#include <QAbstractListModel>
class ListModel: public QAbstractListModel
{
Q_OBJECT
public:
ListModel();
// Q_PROPERTY(QStringList logs READ name WRITE nameChanged)
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
Q_INVOKABLE QVariant activate(int i);
private:
QStringList m_list;
};
#endif // LISTMODEL_H
listmodel.cpp
#include "listmodel.h"
#include <QFile>
#include <QHash>
ListModel::ListModel()
{
QFile file("/home/ashif/LogFile");
if(!file.open(QIODevice::ReadOnly))
{
qDebug( "Log file open failed" );
}
bool isContinue = true;
do
{
if(file.atEnd())
{
isContinue = false;
}
m_list.append(file.readLine());
}
while( isContinue);
}
int ListModel::rowCount(const QModelIndex & parent ) const
{
return m_list.count();
}
QVariant ListModel::data(const QModelIndex & index, int role ) const
{
if(!index.isValid()) {
return QVariant("temp");
}
return m_list.value(index.row());
}
QVariant ListModel::activate(int i)
{
return m_list[i];
}
main.qml
import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
visible: true
ListView
{
width: 200; height: 250
anchors.centerIn: parent
model:mylistModel
delegate: Text
{
text:mylistModel.activate(index)
}
}
}
main.cpp
#include <QGuiApplication>
#include <QQmlContext>
#include <QQmlApplicationEngine>
#include "logger.h"
#include "listmodel.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
Logger myLogger;
ListModel listModel;
engine.rootContext()->setContextProperty("mylistModel", &listModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}

Transient scrollbar in Qt

I want to use transient scrollbar (Transient scroll bars appear when the content is scrolled and disappear when they are no longer needed) in Qt application. For this purpose I have inheritanced class QproxyStyle and reimplemented function styleHint. Code placed below.
File ScrollBar.h:
#include <QStyle>
#include <QCommonStyle>
#include <QProxyStyle>
class ScrollBarStyle : public QProxyStyle
{
public:
int styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *hret) const;
};
File ScrollBar.c:
#include "ScrollBar.h"
int ScrollBarStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *widget,QStyleHintReturn *hret) const
{
int ret = 0;
switch (sh) {
case SH_ScrollBar_Transient:
ret = true;
break;
default:
return QProxyStyle::styleHint(sh, opt, widget, hret);
}
return ret;
}
File MainWindow.h:
#include <QMainWindow>
#include <QTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
};
File MainWindow.cpp:
#include <QTextEdit>
#include "MainWindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QTextEdit *l = new (std::nothrow) QTextEdit(this);
if (l == 0)
return;
setCentralWidget(l);
}
MainWindow::~MainWindow()
{
}
File main.cpp:
#include "ScrollBar.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
ScrollBarStyle *style = new (std::nothrow) ScrollBarStyle;
if(style == 0)
return -1;
style->setBaseStyle(a.style());
w.show();
return a.exec();
}
But I have got a problem: transient scrollbar has been appearing only once (when text doesn't fit in the text area) then it has been disappeared and never come back visible.
So how can I fix this problem?
Thanks!
You have forgotten to set the style to application.
a.setStyle(style);

How to create a window without a title bar but with the close/minimize/maximizie buttons in QML?

I want to create an application without the title bar, but with native close, minimize and maximize buttons. This is the intent of the layout:
The app is built using Go and QML. I was able to remove the title bars by adding:
flags: Qt.FramelessWindowHint | Qt.Window
But this means that I'm having to recreate all kinds of native behaviors, like window moving and resizing. I'm also recreating the close/minimize/fullscreen buttons by hand, but it means I lose all kinds of native OS behaviour like the window snapping in windows or the zoom option on mac.
Is there a better way to do this? Is it possible at least to create the native max-min-close buttons instead of building it by scratch?
Thanks for all
You can use objective-c to setup your window correctly. This might be a little buggy, but I got it working through this (create a separate .mm class):
#include "macwindow.h"
#include <Cocoa.h>
MacWindow::MacWindow(long winid)
{
NSView *nativeView = reinterpret_cast<NSView *>(winid);
NSWindow* nativeWindow = [nativeView window];
[nativeWindow setStyleMask:[nativeWindow styleMask] | NSFullSizeContentViewWindowMask | NSWindowTitleHidden];
[nativeWindow setTitlebarAppearsTransparent:YES];
[nativeWindow setMovableByWindowBackground:YES];
}
In your main.cpp you need to pass the window id like this:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QWindow>
#include "macwindow.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QWindowList windows = QGuiApplication::allWindows();
QWindow* win = windows.first();
MacWindow* mac = new MacWindow(win->winId());
return app.exec();
}
In your .pro file you'll need to add the Cocoa reference:
macx:LIBS += -framework Foundation -framework Cocoa
macx:INCLUDEPATH += /System/Library/Frameworks/Foundation.framework/Versions/C/Headers \
/System/Library/Frameworks/AppKit.framework/Headers \
/System/Library/Frameworks/Cocoa.framework/Headers
Not sure why, but I had to add a TextEdit with the focus attribute to get the window drawn correctly, otherwise it appeared just black (my main.qml):
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
ApplicationWindow {
visible: true
color: "white"
width: 600
height: 400
minimumWidth: width
minimumHeight: height
maximumWidth: width
maximumHeight: height
Rectangle {
anchors.fill: parent
color: "white"
TextEdit {
opacity: 0
focus: true
}
}
}
My solution (based on Eduard's one, adjusted so window is draggable).
(Complete source code https://github.com/teimuraz/qt-macos-without-title)
Create macos.h and macos.mm files (If you create it with qt creator rename macos.cpp to macos.mm)
macos.h
#ifndef MACOS_H
#define MACOS_H
#include <QGuiApplication>
#include <QWindow>
class MacOS {
MacOS(long winid);
public:
static void removeTitlebarFromWindow(long winId = -1);
};
#endif // MACOS_H
macos.mm
#include "macos.h"
#include <Cocoa/Cocoa.h>
#include <QGuiApplication>
#include <QWindow>
void MacOS::removeTitlebarFromWindow(long winId)
{
if(winId == -1) {
QWindowList windows = QGuiApplication::allWindows();
QWindow* win = windows.first();
winId = win->winId();
}
NSView *nativeView = reinterpret_cast<NSView *>(winId);
NSWindow* nativeWindow = [nativeView window];
[nativeWindow setStyleMask:[nativeWindow styleMask] | NSFullSizeContentViewWindowMask | NSWindowTitleHidden];
[nativeWindow setTitlebarAppearsTransparent:YES];
[nativeWindow setMovableByWindowBackground:YES];
}
main.qml
import QtQuick
import QtQuick.Controls
ApplicationWindow {
id: mainWindow
visible: true
width: 640
height: 480
// Make windows draggable, currently whole windows area is draggable, but can be adjusted to make draggable only top area
property int previousX
property int previousY
MouseArea {
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
right: parent.right
}
onPressed: {
previousX = mouseX
previousY = mouseY
}
onMouseXChanged: {
var dx = mouseX - previousX
mainWindow.setX(mainWindow.x + dx)
}
onMouseYChanged: {
var dy = mouseY - previousY
mainWindow.setY(mainWindow.y + dy)
}
}
}
main.cpp
Just add MacWindow::removeTitlebarFromWindow();
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "macos.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(u"qrc:/qt-macos-without-title/main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
MacOS::removeTitlebarFromWindow();
return app.exec();
}
And finally include cocoa lib in .pro file
yourapp.pro
...
macx:LIBS += -framework Foundation -framework Cocoa
macx:INCLUDEPATH += /System/Library/Frameworks/Foundation.framework/Versions/C/Headers \
/System/Library/Frameworks/AppKit.framework/Headers \
/System/Library/Frameworks/Cocoa.framework/Headers

drawing a point over an image on QLabel

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.

Resources