由于最近工作项目中涉及到了Qt自绘高级控件等知识,因此写一篇博客来记录一下Qt最简单的绘图功能的实现过程:
以下是自制白板的demo运行结果:(Win 11 + Qt 5.12.3 + VS 2017)
要开发类似于白板的绘图功能,首先需要构思整个功能的实现流程:
- 就好比我们上美术课,画图离不开画笔和纸。因此需要要给计算机“提供”纸和笔(在编程里,“纸”可以理解为绘图设备)。绘图离不开画家本身,所以,需要定义QPainter对象和QPen对象;
- 我们在纸上写(画)字的过程就类似于拖动鼠标在屏幕某区域里进行绘制。所以需要告诉计算机我们要在哪个区域绘制以及绘制的位置。抽象到编程里,就是需要记录绘图过程中鼠标走过的位置;
- 用白板绘图时,需要我们按压着鼠标,从起始点开始绘制出路径。当松开鼠标时,代表着本次绘制的结束。因此,需要我们重写鼠标的相关事件处理函数(鼠标按压事件mousePressEvent, 鼠标移动事件mouseMoveEvent, 鼠标释放事件mouseReleaseEvent)
- 进行所需的逻辑处理:Demo里把屏幕上每一笔线条里的所有点先存在一个vector里,再把每一个这样的vector存储在最外层的vector里。其实可以把这个“线”想象成由若干个小线条组成,每段线条的终末就是鼠标的终末QPoint值。即调用Qt内置的drawLine函数即可完成。
以下是部分核心代码:
QPoint m_bgnPos; //鼠标按压瞬间时的起始位置
QPoint m_endPos; //鼠标释放时的位置
QPoint m_curPos; //鼠标当前位置
bool m_bPressd; //标记鼠标是否按压
std::vector<QPoint> m_vecPoint;
std::vector< std::vector<QPoint> > m_vecVecPoint;
void MyDrawer::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPen pen;
pen.setWidth(ui.lEdtPenWidth->text().toInt());
pen.setColor(Qt::red);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(pen);
for (int i = 0; i < m_vecVecPoint.size(); ++i)
{
for (int j = 0; j < m_vecVecPoint[i].size() - 1; ++j)
{
painter.drawLine(m_vecVecPoint[i][j], m_vecVecPoint[i][j + 1]);
}
}
update();
}
void MyDrawer::mousePressEvent(QMouseEvent *event)
{
m_bgnPos = event->pos();
m_bPressd = true;
m_vecPoint.push_back(m_bgnPos);
}
void MyDrawer::mouseReleaseEvent(QMouseEvent *event)
{
m_endPos = event->pos();
m_bPressd = false;
m_vecVecPoint.push_back(m_vecPoint);
m_vecPoint.clear();
}
void MyDrawer::mouseMoveEvent(QMouseEvent *event)
{
m_curPos = event->pos();
if (m_bPressd)
{
m_vecPoint.push_back(m_curPos);
m_vecVecPoint.push_back(m_vecPoint);
}
}