1.Qt图形系统中的关键角色
- QPainter
- Qt中的画家,能够绘制各种基础图形
- 拥有绘图所需的画笔(QPen)、画刷(QBrush)、字体(QFont)
- QPaintDevice
- Qt中的画布,画家(QPainter)的绘图板
- 所有的QWidget类都继承自QPaintDevice
注意:只能在QWidget::paintEvent中绘制图形
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPushButton>
#include <QPoint>
class Widget : public QWidget
{
Q_OBJECT
enum
{
LINE, //直线
RECT, //矩形
ELLIPSE //椭圆
};
struct DrawParam
{
int type; //样式类型值
Qt::PenStyle pen; //绘制样式
QPoint begin;
QPoint end;
};
QPushButton m_testBtn;
QList<DrawParam> m_list;
protected slots:
void onTestBtnClicked();
protected:
void paintEvent(QPaintEvent*);
public:
explicit Widget(QWidget *parent = nullptr);
~Widget() override;
};
#endif // WIDGET_H
Widget.cpp
#include "Widget.h"
#include <QPainter>
#include <QPoint>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
m_testBtn.setParent(this);
m_testBtn.move(400, 300);
m_testBtn.resize(70, 30);
m_testBtn.setText("Test");
resize(500, 350);
connect(&m_testBtn, SIGNAL(clicked()), this, SLOT(onTestBtnClicked()));
}
void Widget::onTestBtnClicked()
{
DrawParam dp =
{
qrand() % 3, //随机值
static_cast<Qt::PenStyle>(qrand() % 5 + 1),
QPoint(qrand()% 400, qrand() % 300),
QPoint(qrand()% 400, qrand() % 300)
};
m_list.append(dp);
update();
}
void Widget::paintEvent(QPaintEvent*)
{
QPainter painter;
painter.begin(this);
for(int i=0; i<m_list.count(); i++)
{
int x = (m_list[i].begin.x() < m_list[i].end.x() ? m_list[i].begin.x() : m_list[i].end.x());
int y = (m_list[i].begin.y() < m_list[i].end.y() ? m_list[i].begin.y() : m_list[i].end.y());
int w = qAbs(m_list[i].begin.x() - m_list[i].end.x()) + 1;
int h = qAbs(m_list[i].begin.y() - m_list[i].end.y()) + 1;
painter.setPen(m_list[i].pen);
switch (m_list[i].type) {
case LINE:
painter.drawLine(m_list[i].begin, m_list[i].end);
break;
case RECT:
painter.drawRect(x, y, w, h);
break;
case ELLIPSE:
painter.drawEllipse(x, y, w, h);
break;
}
}
painter.end();
}
Widget::~Widget() = default;
2.Qt图形系统中的坐标系
- 物理坐标系(设备坐标系)
- 原点(0,0)在左上角的位置,单位:像素
- x坐标向右增长,y坐标向下增长
- 逻辑坐标系
- 数学模型中的抽象坐标系,单位由具体问题决定
- 坐标轴的增长方向由具体问题决定
- QPaint用的就是逻辑坐标系
3.视口和窗口
- 视口:物理坐标系中一个任意指定的矩形
- 窗口:逻辑坐标系下对应到物理坐标系中的相同矩形
- 视口与窗口的变换方式
- 定义视口:左上角坐标,右下角坐标,计算宽度和高度
- 定义窗口:左上角坐标,右下角坐标,计算宽度和高度
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
protected:
void paintEvent(QPaintEvent* );
public:
explicit Widget(QWidget *parent = nullptr);
~Widget() override;
};
#endif // WIDGET_H
Widget.cpp
#include "Widget.h"
#include <QPainter>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
}
void Widget::paintEvent(QPaintEvent* )
{
QPainter painter(this);
painter.setViewport(0, 0, width(), height()); //设置物理坐标系统,即实际窗口的像素区域
//参数含义:(左上角x, 左上角y, 宽度, 高度)
painter.setWindow(-100, 100, 200, -200); //设置逻辑坐标系统
painter.drawLine(QPoint(0, 0), QPoint(80, 80));
}
Widget::~Widget() = default;
运行结果:

示例:正弦波形绘图示例
Widget.cpp
#include "Widget.h"
#include <QPainter>
#include <QPointF>
#include <qmath.h>
#include <QPen>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
}
void Widget::paintEvent(QPaintEvent* )
{
QPainter painter(this);
QPen pen;
pen.setColor(Qt::green);
pen.setStyle(Qt::SolidLine);
pen.setWidthF(0.01); //线条宽度为 0.01
painter.setPen(pen);
painter.setViewport(50, 50, width()-100, height()-100); //设置物理坐标系统,即实际窗口的像素区域
//参数含义:(左上角x, 左上角y, 宽度, 高度)
painter.setWindow(-10, 2, 20, -4); //设置逻辑坐标系统
painter.fillRect(-10, 2, 20, -4, Qt::black); //是在逻辑坐标系中绘制一个填充矩形
painter.drawLine(QPointF(-10, 0), QPointF(10, 0));
painter.drawLine(QPointF(0, 2), QPointF(0, -2));
for(float x=-10; x<10; x+=0.01)
{
float y = qSin(x);
painter.drawPoint(QPointF(x, y));
}
}
Widget::~Widget() = default;
运行结果:
