效果演示:
主模块代码:
csharp
GraphViewProject::GraphViewProject(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
m_shapeType = NoType;
m_bll = BllData::getInstance();
m_scene = new GraphicsScene;
connect(m_bll, &BllData::pressShapePosSignal, this, &GraphViewProject::pressShapePosSlot);
connect(m_bll, &BllData::returnPolygonPosSignal, this, &GraphViewProject::returnPolygonPosSlot);
connect(m_bll, &BllData::returnDeletePosSignal, this, &GraphViewProject::returnDeletePosSlot);
// 隐藏水平/竖直滚动条
ui.graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui.graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// 设置场景范围
ui.graphicsView->setSceneRect(INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX);
// 反锯齿
ui.graphicsView->setRenderHints(QPainter::Antialiasing);
m_scene->setBackgroundBrush(Qt::gray);
ui.graphicsView->setScene(m_scene);
}
GraphViewProject::~GraphViewProject()
{
}
void GraphViewProject::pressShapePosSlot(QPointF pos, PointType type) {
if (m_shapeType == RectType) {
if (type == TopLeft) {
ShapeBase* rec = new ShapeBase(RectType);
m_shapeList.append(rec);
m_scene->addItem(rec);
rec->appendPoint(pos, TopLeft);
}
else if (type == BottomRight) {
m_shapeList[m_shapeList.size() - 1]->appendPoint(pos, BottomRight);
m_shapeType = NoType;
}
}
else if (m_shapeType==CircleType) {
if (type == Center) {
ShapeBase* cir = new ShapeBase(CircleType);
m_shapeList.append(cir);
m_scene->addItem(cir);
cir->appendPoint(pos, Center);
}
else if (type == Dot) {
m_shapeList[m_shapeList.size() - 1]->appendPoint(pos, Dot);
m_shapeType = NoType;
}
}
else if (m_shapeType == EllipseType) {
ShapeBase* ellipse = new ShapeBase(EllipseType);
m_shapeList.append(ellipse);
m_scene->addItem(ellipse);
ellipse->appendPoint(pos, Center);
m_shapeType = NoType;
}
}
void GraphViewProject::returnPolygonPosSlot(QPointF pos, QList<QPointF> list, bool flag) {
if (list.size() == 1) {
ShapeBase* polygon = new ShapeBase(PolygonType);
m_shapeList.append(polygon);
m_scene->addItem(polygon);
polygon->appendPolygonPoint(pos, list,flag);
}
else {
m_shapeList[m_shapeList.size() - 1]->appendPolygonPoint(pos, list, flag);
if (flag) {
m_shapeType = NoType;
}
}
}
void GraphViewProject::returnDeletePosSlot(QPointF pos) {
for (int i = 0; i < m_scene->items().size(); i++) {
ShapeBase* item = (ShapeBase*)m_scene->items()[i];
QPointF lt = item->getTopLeft();
if (pos == lt) {
qDebug() << "index: " << i;
m_scene->removeItem(item);
break;
}
}
}
void GraphViewProject::on_rectBtn_clicked() {
m_shapeType = RectType;
m_bll->setShapeEnable(RectType);
}
void GraphViewProject::on_circleBtn_clicked() {
m_shapeType = CircleType;
m_bll->setShapeEnable(CircleType);
}
void GraphViewProject::on_ellipseBtn_clicked() {
m_shapeType = EllipseType;
m_bll->setShapeEnable(EllipseType);
}
void GraphViewProject::on_polygonBtn_clicked() {
m_shapeType = PolygonType;
m_bll->setShapeEnable(PolygonType);
}
void GraphViewProject::on_deleteBtn_clicked() {
m_bll->deleteShapeEnable();
}
void GraphViewProject::on_clearBtn_clicked() {
m_scene->clear();
}
Scene代码:
csharp
GraphicsScene::GraphicsScene(QObject *parent)
: QGraphicsScene(parent)
{
m_enable = false;
m_bll = BllData::getInstance();
connect(m_bll, &BllData::setShapeEnableSignal, this, &GraphicsScene::setShapeEnableSlot);
}
GraphicsScene::~GraphicsScene()
{}
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent* event) {
if (m_enable) {
m_clickCnt++;
if (m_type == RectType) {
if (m_clickCnt == 1) {
m_bll->pressShapePos(event->scenePos(), TopLeft);
}
else if (m_clickCnt == 2) {
m_enable = false;
m_bll->pressShapePos(event->scenePos(), BottomRight);
}
}
else if (m_type == CircleType) {
if (m_clickCnt == 1) {
m_bll->pressShapePos(event->scenePos(), Center);
}
else if (m_clickCnt == 2) {
m_enable = false;
m_bll->pressShapePos(event->scenePos(), Dot);
}
}
else if (m_type == EllipseType) {
if (m_clickCnt == 1) {
m_enable = false;
m_bll->pressShapePos(event->scenePos(), Center);
}
}
else if (m_type == PolygonType) {
if (event->buttons() == Qt::LeftButton) {
m_list.push_back(event->scenePos());
m_bll->returnPolygonPos(event->scenePos(), m_list, false);
}
else {
if (m_list.size() >= 3) {
m_enable = false;
m_bll->returnPolygonPos(event->scenePos(), m_list, true);
m_list.clear();
}
}
}
}
else {
QGraphicsScene::mousePressEvent(event);
}
}
void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
QGraphicsScene::mouseMoveEvent(event);
}
void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) {
QGraphicsScene::mouseReleaseEvent(event);
}
void GraphicsScene::setShapeEnableSlot(ShapeType type) {
m_type = type;
m_enable = true;
m_clickCnt = 0;
m_list.clear();
}
Shape代码:
csharp
ShapeBase::ShapeBase(ShapeType type)
{
m_type = type;
m_deleteEnable = false;
m_polygonFinshed = false;
m_bll = BllData::getInstance();
connect(m_bll, &BllData::deleteShapeEnableSignal, this, &ShapeBase::deleteShapeEnableSlot);
m_pen_noSelected.setColor(QColor(0, 160, 230));
m_pen_noSelected.setWidth(2);
m_pen_isSelected.setColor(QColor(255, 0, 255));
m_pen_isSelected.setWidth(2);
this->setPen(m_pen_noSelected);
this->setFlags(QGraphicsItem::ItemIsSelectable |
QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemIsFocusable);
}
ShapeBase::~ShapeBase()
{}
ShapeType ShapeBase::getType() {
return m_type;
}
void ShapeBase::setTopLeft(QPointF tl) {
m_tl = tl;
}
QPointF ShapeBase::getTopLeft() {
return m_tl;
}
void ShapeBase::setBottomRight(QPointF br) {
m_br = br;
}
QPointF ShapeBase::getBottomRight() {
return m_br;
}
void ShapeBase::setCenter(QPointF center) {
m_center = center;
}
QPointF ShapeBase::getCenter() {
return m_center;
}
void ShapeBase::deleteShapeEnableSlot() {
m_deleteEnable = true;
}
void ShapeBase::setRandColor() {
QColor color(qrand() % 256, qrand() % 256, qrand() % 256);
for (int i = 0; i < m_pointList.size(); i++) {
m_pointList[i]->setBrush(QBrush(color));
}
}
void ShapeBase::appendPoint(QPointF pos, PointType type) {
if (m_type == RectType) {
if (type == TopLeft) {
setTopLeft(pos);
setBottomRight(pos);
PointBase* p1 = new PointBase(RectType, TopLeft, pos);
p1->setParentItem(this);
p1->setBrush(QBrush(QColor(0,255,0)));
m_pointList.append(p1);
}
else if (type == BottomRight) {
setBottomRight(pos);
PointBase* p2 = new PointBase(RectType, BottomRight, pos);
p2->setParentItem(this);
p2->setBrush(QBrush(QColor(0, 255, 0)));
m_pointList.append(p2);
this->update();
}
}
else if (m_type == CircleType) {
if (type == Center) {
setTopLeft(pos);
setBottomRight(pos);
setCenter(pos);
PointBase* p1 = new PointBase(CircleType, Center, pos);
p1->setParentItem(this);
p1->setBrush(QBrush(QColor(0, 255, 0)));
m_pointList.append(p1);
}
else if (type == Dot) {
m_radius = sqrt(pow(m_tl.x() - pos.x(), 2) + pow(m_tl.y() - pos.y(), 2));
double tlx = m_tl.x() - m_radius;
double tly = m_tl.y() - m_radius;
double brx = m_tl.x() + m_radius;
double bry = m_tl.y() + m_radius;
setDot(pos);
setTopLeft(QPointF(tlx, tly));
setBottomRight(QPointF(brx, bry));
PointBase* p2 = new PointBase(CircleType, Dot, pos);
p2->setParentItem(this);
p2->setBrush(QBrush(QColor(0, 255, 0)));
m_pointList.append(p2);
this->update();
}
}
else if (m_type == EllipseType) {
setCenter(pos);
PointBase* p1 = new PointBase(EllipseType, Center, pos);
p1->setParentItem(this);
p1->setBrush(QBrush(QColor(0, 255, 0)));
m_pointList.append(p1);
double tlx = pos.x() - 50;
double tly = pos.y() - 40;
double brx = pos.x() + 50;
double bry = pos.y() + 40;
setTopLeft(QPointF(tlx, tly));
setBottomRight(QPointF(brx, bry));
PointBase* p2 = new PointBase(EllipseType, BottomRight, QPointF(brx,bry));
p2->setParentItem(this);
p2->setBrush(QBrush(QColor(0, 255, 0)));
m_pointList.append(p2);
this->update();
}
}
void ShapeBase::appendPolygonPoint(QPointF pos, QList<QPointF> list, bool flag) {
m_polygonFinshed = flag;
if (list.size() == 1) {
setTopLeft(pos);
setBottomRight(pos);
PointBase* p1 = new PointBase(PolygonType, FirstDot, pos);
p1->setParentItem(this);
p1->setBrush(QBrush(QColor(0, 255, 0)));
m_pointList.append(p1);
}
else {
QPointF center = getCenter(list);
QRectF rect = getBoundingRect(list);
m_tl = rect.topLeft();
m_br = rect.bottomRight();
if (flag) {
PointBase* p = new PointBase(PolygonType, Center, center);
p->setParentItem(this);
p->setBrush(QBrush(QColor(0, 255, 0)));
m_pointList.append(p);
}
else {
PointBase* p = new PointBase(PolygonType, OtherDot, pos);
p->setParentItem(this);
p->setBrush(QBrush(QColor(0, 255, 0)));
m_pointList.append(p);
}
}
this->update();
}
QPointF ShapeBase::getCentroid(QList<QPointF> list) {
qreal x = 0;
qreal y = 0;
for (auto& temp : list)
{
x += temp.x();
y += temp.y();
}
x = x / list.size();
y = y / list.size();
return QPointF(x, y);
}
void ShapeBase::getMaxLength() {
QVector<qreal> vec;
for (auto& temp : m_pointList)
{
qreal dis = sqrt(pow(m_center.x() - temp->x(), 2) + pow(m_center.y() - temp->y(), 2));
vec.append(dis);
}
qreal ret = 0;
for (auto& temp : vec)
{
if (temp > ret) {
ret = temp;
}
}
m_radius = ret;
}
void ShapeBase::updatePolygonData(QPointF org, QPointF pos) {
QList<QPointF> list;
for (int i = 0; i < m_pointList.size(); i++) {
QPointF p = m_pointList[i]->getPoint();
qDebug() << " list index : " << i << " pos: " << p << " org: " << org;
if ( (abs(p.x()-org.x())<=2)&&(abs(p.y() - org.y()) <= 2)) {
qDebug() << "find it------------------------";
m_pointList[i]->setPoint(pos);
}
list.append(m_pointList[i]->getPoint());
}
/*QPointF center = getCenter(list);
qDebug() << "center: " << center;
QRectF rect = getBoundingRect(list);
m_tl = rect.topLeft();
m_br = rect.bottomRight();
m_pointList.at(m_pointList.size() - 1)->setPoint(center);*/
m_center = getCentroid(list);
m_pointList.at(m_pointList.size() - 1)->setPoint(m_center);
getMaxLength();
QRectF(m_center.x() - m_radius, m_center.y() - m_radius, m_radius * 2, m_radius * 2);
m_tl = QPointF(m_center.x() - m_radius, m_center.y() - m_radius);
m_br = QPointF(m_center.x() + m_radius, m_center.y() + m_radius);
}
QPointF ShapeBase::getCenter(QList<QPointF> list) {
std::vector<cv::Point> contours;
for (int i = 0; i < list.size(); i++) {
int x = list[i].x();
int y = list[i].y();
contours.push_back(cv::Point(x, y));
}
cv::Moments moment = cv::moments(contours);
cv::Point midPoint = cv::Point(int(moment.m10 / moment.m00), int(moment.m01 / moment.m00));
return QPointF(midPoint.x, midPoint.y);
}
QRectF ShapeBase::getBoundingRect(QList<QPointF> list) {
std::vector<cv::Point> contours;
for (int i = 0; i < list.size(); i++) {
int x = list[i].x();
int y = list[i].y();
contours.push_back(cv::Point(x, y));
}
cv::Rect rect = cv::boundingRect(contours);
int tlx = rect.tl().x;
int tly = rect.tl().y;
int w = rect.width;
int h = rect.height;
return QRectF(tlx, tly, w, h);
}
void ShapeBase::setDot(QPointF pos) {
m_dot = pos;
}
QPointF ShapeBase::getDot() {
return m_dot;
}
void ShapeBase::updateRadius() {
double radius = sqrt(pow(m_center.x() - m_dot.x(), 2) + pow(m_center.y() - m_dot.y(), 2));
double tlx = m_center.x() - radius;
double tly = m_center.y() - radius;
double brx = m_center.x() + radius;
double bry = m_center.y() + radius;
setTopLeft(QPointF(tlx, tly));
setBottomRight(QPointF(brx, bry));
}
void ShapeBase::updateEllipse() {
int w = abs(m_br.x() - m_center.x());
int h = abs(m_br.y() - m_center.y());
double tlx = m_center.x() - w;
double tly = m_center.y() - h;
double brx = m_center.x() + w;
double bry = m_center.y() + h;
setTopLeft(QPointF(tlx, tly));
setBottomRight(QPointF(brx, bry));
}
QRectF ShapeBase::boundingRect() const {
int w = abs(m_tl.x() - m_br.x());
int h = abs(m_tl.y() - m_br.y());
int x0 = m_tl.x() < m_br.x() ? m_tl.x() : m_br.x();
int y0 = m_tl.y() < m_br.y() ? m_tl.y() : m_br.y();
QRectF rect(x0, y0, w, h);
return rect;
}
void ShapeBase::focusInEvent(QFocusEvent* event) {
Q_UNUSED(event);
this->setPen(m_pen_isSelected);
}
void ShapeBase::focusOutEvent(QFocusEvent* event) {
Q_UNUSED(event);
this->setPen(m_pen_noSelected);
}
void ShapeBase::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setPen(this->pen());
painter->setBrush(this->brush());
int w = abs(m_tl.x() - m_br.x());
int h = abs(m_tl.y() - m_br.y());
int x0 = m_tl.x() < m_br.x() ? m_tl.x() : m_br.x();
int y0 = m_tl.y() < m_br.y() ? m_tl.y() : m_br.y();
QRectF rect(x0, y0, w, h);
if (m_type == RectType) {
painter->drawRect(rect);
}
else if (m_type == CircleType) {
painter->drawEllipse(rect);
}
else if (m_type == EllipseType) {
painter->drawEllipse(rect);
}
else if (m_type == PolygonType) {
if (m_polygonFinshed) {
for (int i = 1; i < m_pointList.size() - 1; i++)
{
painter->drawLine(m_pointList.at(i - 1)->getPoint(), m_pointList.at(i)->getPoint());
}
painter->drawLine(m_pointList.at(m_pointList.size() - 2)->getPoint(), m_pointList.at(0)->getPoint());
}
else {
for (int i = 1; i < m_pointList.size(); i++)
{
painter->drawLine(m_pointList.at(i - 1)->getPoint(), m_pointList.at(i)->getPoint());
}
}
}
}
void ShapeBase::mousePressEvent(QGraphicsSceneMouseEvent* event) {
if (m_deleteEnable) {
m_bll->returnDeletePos(m_tl);
}
}
void ShapeBase::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
qreal dx = event->scenePos().x() - event->lastScenePos().x();
qreal dy = event->scenePos().y() - event->lastScenePos().y();
this->moveBy(dx, dy);
}