在 Qt 中绘制主 class 的子 class
Drawing on a main class's subclass in Qt
我创建了一个名为 widget.cpp 的主要 class,它继承了 QFrame。从 widget.cpp 我创建了一个名为 frame.cpp 的子 class,我在其中重新实现了用于绘制图像的 paintEvent() 方法。问题是,当我尝试通过 widget.cpp 通过为其创建一个 paintEvent 方法来直接绘制图像时,它工作正常。但在另一种情况下,当我在 subclass frame.cpp 中实现它时,它无法正常工作。我在这里做错了什么吗?
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();
}
如果我在上面的代码中使用 QRect target(0,0,20,10) 绘制图像。
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>
如果你想替换一个 class X 小部件,你必须创建一个继承自那个 class 的 class,在你的情况下,框架必须继承自 QFrame
并且不是直接来自 QWidget
,因为 Qt Designer 将使用 QWidget
没有的 QFrame
方法,而是从 QFrame
继承的 class 如果它有它们.
因此您应该更改代码中的下一部分。
frame.h
class frame : public QFrame
{
...
frame.cpp
frame::frame(QWidget *parent) : QFrame(parent)
{
}
在您的代码中观察到的另一个错误是您在 paintEvent()
中调用 update()
,这会产生无限循环,因为 update()
间接调用 paintEvent()
。还有一个widget你画space,这个space我们可以通过方法rect()
搞定,如果你在外面画那space什么都没画。另一个不好的做法是创建一个指向 QPainter
的指针,因为它会不断被调用到该方法,并且除了正确消除它之外,您还将创建内存。从上面我提出以下代码:
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);
}
最重要的是,当您 运行 f = new frame(ui->frame);
您正在创建一个新的小部件时,默认情况下它相对于父级占据一个位置,这就是您看到图像的原因,但这是不合适的, 你应该做的是推广小部件。
要推广右键单击 QtDesigner
中的 QFrame
,将显示一个菜单,select Promoted Widgets,打开一个对话框 window,在你必须在 Promoted class name 中输入你创建的 class 的名称,在你的例子中是 frame ,在头文件中是你的 .h 文件class,在您的情况下 frame.h,然后按添加按钮,然后按推广按钮。如下图所示:
编译项目后,作为最终建议,将框架的 Qt Designer 中的小部件名称更改为另一个名称,例如 myFrame,这样就不会与 class.[=31= 的名称混淆]
完整的例子可以在下面找到link
我创建了一个名为 widget.cpp 的主要 class,它继承了 QFrame。从 widget.cpp 我创建了一个名为 frame.cpp 的子 class,我在其中重新实现了用于绘制图像的 paintEvent() 方法。问题是,当我尝试通过 widget.cpp 通过为其创建一个 paintEvent 方法来直接绘制图像时,它工作正常。但在另一种情况下,当我在 subclass frame.cpp 中实现它时,它无法正常工作。我在这里做错了什么吗?
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();
}
如果我在上面的代码中使用 QRect target(0,0,20,10) 绘制图像。
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>
如果你想替换一个 class X 小部件,你必须创建一个继承自那个 class 的 class,在你的情况下,框架必须继承自 QFrame
并且不是直接来自 QWidget
,因为 Qt Designer 将使用 QWidget
没有的 QFrame
方法,而是从 QFrame
继承的 class 如果它有它们.
因此您应该更改代码中的下一部分。
frame.h
class frame : public QFrame
{
...
frame.cpp
frame::frame(QWidget *parent) : QFrame(parent)
{
}
在您的代码中观察到的另一个错误是您在 paintEvent()
中调用 update()
,这会产生无限循环,因为 update()
间接调用 paintEvent()
。还有一个widget你画space,这个space我们可以通过方法rect()
搞定,如果你在外面画那space什么都没画。另一个不好的做法是创建一个指向 QPainter
的指针,因为它会不断被调用到该方法,并且除了正确消除它之外,您还将创建内存。从上面我提出以下代码:
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);
}
最重要的是,当您 运行 f = new frame(ui->frame);
您正在创建一个新的小部件时,默认情况下它相对于父级占据一个位置,这就是您看到图像的原因,但这是不合适的, 你应该做的是推广小部件。
要推广右键单击 QtDesigner
中的 QFrame
,将显示一个菜单,select Promoted Widgets,打开一个对话框 window,在你必须在 Promoted class name 中输入你创建的 class 的名称,在你的例子中是 frame ,在头文件中是你的 .h 文件class,在您的情况下 frame.h,然后按添加按钮,然后按推广按钮。如下图所示:
编译项目后,作为最终建议,将框架的 Qt Designer 中的小部件名称更改为另一个名称,例如 myFrame,这样就不会与 class.[=31= 的名称混淆]
完整的例子可以在下面找到link