我对代码中抽象对象好处的理解是:提高代码的复用性。
假设我们有这样的需求,要在界面上按下鼠标,拖动之后松开鼠标,然后就在界面上绘制出了线、矩形,如下图c所示:
那么我们首先贴上第一种方法的代码:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPainter>
#include <QMouseEvent>
namespace Ui {
class MainWindow;
}
class myLine//定义一个线类,里面用两个字段表示线的起点和终点
{
public:
QPoint start;
QPoint end;
myLine()
{
}
myLine(const QPoint& start,const QPoint& end)
{
this->start = start;
this->end = end;
}
};
class myRect//定义一个矩形类,里面定义3个字段,表示矩形起点、宽度、高度
{
public:
QPoint start;
int nWidth;
int nHeight;
myRect()
{
}
myRect(const QPoint& start,const int& nWidth,const int& nHeight)
{
this->start = start;
this->nWidth = nWidth;
this->nHeight = nHeight;
}
};
//1.add class myCircle
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
virtual void mousePressEvent(QMouseEvent *event);
virtual void mouseReleaseEvent(QMouseEvent *event);
virtual void paintEvent(QPaintEvent *event);
QVector<myLine> vmyLine;
myLine mylineCrt;
QVector<myRect> vmyRect;
myRect myrectCrt;
//2.add QVector<myCircle> vmyCircle;
//3.add myCircle mycircleCrt;
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::mousePressEvent(QMouseEvent *event)
{
mylineCrt.start = event->pos();
myrectCrt.start = event->pos();
//4.add mycircleCtr.centerpoint = event->pos();
}
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
mylineCrt.end = event->pos();
myrectCrt.nWidth = qAbs(event->x()-myrectCrt.start.x());
myrectCrt.nHeight = qAbs(event->y()-myrectCrt.start.y());
vmyLine.append(mylineCrt);
vmyRect.append(myrectCrt);
//5.add vmyCircle.append(mycircleCrt);
this->repaint();
}
void MainWindow::paintEvent(QPaintEvent *event)
{
//绘制一个从
QPen pen(QColor(0,0,255));
pen.setWidth(5);
QPainter g(this);
g.setPen(pen);
//画直线
for(int i = 0;i<vmyLine.count();i++)
{
g.drawLine(vmyLine[i].start,vmyLine[i].end);
}
//画矩形
for(int i = 0;i<vmyRect.count();i++)
{
g.drawRect(vmyRect[i].start.x(),vmyRect[i].start.y(),vmyRect[i].nWidth,vmyRect[i].nHeight);
}
//6.add 画圆形
}
好,这是第一种方法,也是很多新手常用的方法。
现在设想一下,如果客户的需求变了,需要我们添加绘制一个圆形,那么我们需要添加的代码包括上面标注出来的6个地方(这也是为什么我们这些程序猿天天加班的原因~)
然后我们来看第二种,即抽象之后的代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPainter>
#include <QMouseEvent>
#include <QtMath>
namespace Ui {
class MainWindow;
}
class myShape
{
public: myShape()
{
}
virtual ~myShape()//因为类里面有drawShape纯虚函数,所以要有虚析构函数
{
}
virtual void drawShape(QPen *pen,QPainter *g) = NULL;
};
class myLine:public myShape//定义一个线类,里面用两个字段表示线的起点和终点
{
public:
QPoint start;
QPoint end;
myLine()
{
}
myLine(const QPoint& start,const QPoint& end)
{
this->start = start;
this->end = end;
}
virtual void drawShape(QPen *pen,QPainter *g)
{
g->setPen(*pen);
g->drawLine(start,end);
}
};
class myRect:public myShape//定义一个矩形类,里面定义3个字段,表示矩形起点、宽度、高度
{
public:
QPoint start;
int nWidth;
int nHeight;
myRect()
{
}
myRect(const QPoint& start,const int& nWidth,const int& nHeight)
{
this->start = start;
this->nWidth = nWidth;
this->nHeight = nHeight;
}
virtual void drawShape(QPen *pen,QPainter *g)
{
g->setPen(*pen);
g->drawRect(start.x(),start.y(),nWidth,nHeight);
}
};
//1.add class myCircle
class myCircle:public myShape//定义一个矩形类,里面定义3个字段,表示矩形起点、宽度、高度
{
public:
QPoint centerpoint;
qreal nRadius;
myCircle()
{
}
myCircle(const QPoint& start,const qreal& nRadius)
{
this->centerpoint = start;
this->nRadius = nRadius;
}
virtual void drawShape(QPen *pen,QPainter *g)
{
g->setPen(*pen);
g->drawEllipse((int)centerpoint.x()-nRadius,(int)centerpoint.y()-nRadius,(int)nRadius*2,(int)nRadius*2);
}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
virtual void mousePressEvent(QMouseEvent *event);
virtual void mouseReleaseEvent(QMouseEvent *event);
virtual void paintEvent(QPaintEvent *event);
QPoint m_StartPoint;
QVector<myShape*> vMyShape;
//QVector<myLine> vmyLine;
//QVector<myRect> vmyRect;
//QVector<myCircle> vmyCircle;
private:
Ui::MainWindow *ui;
};
mainwindow.cpp
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::mousePressEvent(QMouseEvent *event)
{
m_StartPoint = event->pos();
}
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
vMyShape.append(new myLine(m_StartPoint,event->pos()));
vMyShape.append(new myRect(m_StartPoint,event->x()-m_StartPoint.x(),event->y()-m_StartPoint.y()));
//2.add
qreal nRadius = qSqrt(qAbs(event->x()-m_StartPoint.x())*qAbs(event->x()-m_StartPoint.x())+qAbs(event->y()-m_StartPoint.y())*qAbs(event->y()-m_StartPoint.y()));
vMyShape.append(new myCircle(m_StartPoint,nRadius));
this->repaint();
}
void MainWindow::paintEvent(QPaintEvent *event)
{
//绘制一个从
QPen pen(QColor(0,0,255));
pen.setWidth(5);
QPainter g(this);
g.setPen(pen);
// //画直线
// for(int i = 0;i<vmyLine.count();i++)
// {
// g.drawLine(vmyLine[i].start,vmyLine[i].end);
// }
// //画矩形
// for(int i = 0;i<vmyRect.count();i++)
// {
// g.drawRect(vmyRect[i].start.x(),vmyRect[i].start.y(),vmyRect[i].nWidth,vmyRect[i].nHeight);
// }
//画图形
for(int i = 0;i<vMyShape.size();i++)
{
vMyShape[i]->drawShape(&pen,&g);
}
}
可以看到,第二种方法用了抽象的概念,将三种图形抽象成了一个myShape,在代码中的体现就是定义了一个基类myShape类,其他所有的图像类都继承自这个基类,然后在每个子类中都添加了drawShape()方法,这样在界面的paintEvent(QPaintEvent *event)方法中绘图的时候就不需要分各种图形来单独绘制了。可以看到,用第二种方法在用户添加绘制圆形的需求的时候,需要添加更改代码的地方减少到了2处。极大提高了代码的复用性!
最后贴上一张运行结果图:
源码地址
https://download.csdn.net/download/weixin_43935474/12235320