I have created a main class called widget.cpp, which inherits QFrame. And from widget.cpp I create a subclass called frame.cpp in which I reimplement paintEvent() method for drawing image. The problem is that, when I try to draw image directly through widget.cpp by creating a paintEvent method for it , it works fine. But in the other case, when I implement it in the subclass frame.cpp its not working fine. Is there some thing I am doing wrong here.
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QFrame>
#include <QPainter>
#include "frame.h"
class frame;
namespace Ui {
class Widget;
}
class Widget : public QFrame
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
frame * f;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QFrame(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
f = new frame(ui->frame);
f->show();
}
Widget::~Widget()
{
delete ui;
}
frame.h
#ifndef FRAME_H
#define FRAME_H
#include <QObject>
#include <QWidget>
#include <QPainter>
class frame : public QWidget
{
Q_OBJECT
public:
explicit frame(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *p);
signals:
public slots:
};
#endif // FRAME_H
frame.cpp
#include "frame.h"
frame::frame(QWidget *parent) : QWidget(parent)
{
}
void frame::paintEvent(QPaintEvent *p)
{
QPainter* pPainter = new QPainter(this);
QImage img(":/left.png");
Q_ASSERT(!img.isNull());
QRect source(0,0,20,10);
QRect target(50,50,20,10);
pPainter->drawImage(target, img,source);
QWidget::paintEvent(p);
QWidget::update();
}
If I use QRect target(0,0,20,10) in the above code the image is drawn.
testImage.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = testImage
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += main.cpp\
widget.cpp \
frame.cpp
HEADERS += widget.h \
frame.h
FORMS += widget.ui
RESOURCES += \
src.qrc
DISTFILES +=
widget.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>823</width>
<height>468</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<widget class="QFrame" name="frame">
<property name="geometry">
<rect>
<x>200</x>
<y>60</y>
<width>420</width>
<height>300</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>420</width>
<height>300</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>420</width>
<height>306</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
If you want to replace a class X widget you must create a class that inherits from that class, in your case frame must inherit from QFrame
and not directly from QWidget
, since Qt Designer will use QFrame
methods that QWidget
does not have, instead a class that inherits from QFrame
if it will have them.
So you should change the next part in your code.
frame.h
class frame : public QFrame
{
...
frame.cpp
frame::frame(QWidget *parent) : QFrame(parent)
{
}
Another error that is observed in your code is that you call update()
inside paintEvent()
, this can generate an infinite loop since update()
calls paintEvent()
indirectly. Also a widget your a painting space, this space we can get through the method rect()
, if you draw outside that space not painted anything. Another bad practice is to create a pointer to QPainter
since it will continually be called to that method and you will be creating memory in addition to that you are eliminating it correctly. From the above I propose the following code:
void frame::paintEvent(QPaintEvent *p)
{
QWidget::paintEvent(p);
QPainter pPainter(this);
QImage img(":/left.png");
Q_ASSERT(!img.isNull());
QRect source(0,0,20,10);
QRect target(50,50,20,10);
pPainter.drawImage(target, img, source);
}
And most importantly, when you run f = new frame(ui->frame);
you are creating a new widget that by default takes a position relative to the parent, that's why you see the image, but this is not appropriate, what you should do is promote the widget.
To promote right click on the QFrame
that is in QtDesigner
, and will be displayed a menu, select Promoted Widgets, opening a dialog window, in it you must put in Promoted class name the name of the class you have created, in your case frame , and in header file the .h file of your class, in your case frame.h, then press the add button and then the Promote button. As shown in the following images:
After compiling your project, as final recommendation change the name of the widget in Qt Designer of frame to another for example myFrame so that there is no confusion with the name of the class.
The complete example can be found in the following link