当前位置: 首页 > news >正文

QGraphicsView、QGraphicsScene和QGraphicsItem图形视图框架(七)修改item属性

一、简要说明

本文介绍了使用Qt的QTableWidget与QStyledItemDelegate实现图形项属性显示与编辑功能。通过自定义委托类PropertyDelegate,支持多种属性类型的编辑控件(文本、颜色选择、线型等)。

实现原理:MainWindow类管理图形视图场景,当选中图形项时,将属性值显示在表格中,用户修改后自动更新图形项。

关键实现包括:

1) 重写委托类的创建编辑器、数据获取/设置方法;

2) 使用QVariant存储自定义编辑数据;

3) 图形项与属性表格的双向数据同步。该方案可灵活扩展,适用于需要可视化编辑对象属性的应用场景。

二、主要代码示例

1.mainwindow

.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QGraphicsScene>
#include <QTreeWidget>
#include <QTimer>
#include <QStandardItemModel>
#include <QTableView>
#include <QStyledItemDelegate>
#include <QToolBar>
#include <QTableWidget>
#include "graphicsview.h"
#include "graphicsscene.h"
#include "toolboxtreewidget.h"
#include "tabledelegate.h"namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = 0);~MainWindow();private://工具栏void initTool();void initItem();//翻转void flipItems(int Axis);//布局void align(AlignType alignType);//显示属性void getPropertyValue(QString propertyName, ItemProperty property, EditData *edit);void showProperty(ItemProperty property, long long propertyValue);public slots:void updateUI();void treeItemAddShape(QTreeWidgetItem *item, int column);void addShape(QAction *action);//缩小void onZoomIn();//放大void onZoomOut();//删除void onDeteleItems();//全选void onSelectAll();//布局void onAglinTriggered();//上移至最顶层void onBringToTopTriggered();//下移至最底层void onBringToBottomTriggered();//上移至上一层void onBringToFrontLayerTriggered();//下移至下一层void onBringToBackLayerTriggered();//点击图元触发的槽函数void onItemClicked(QGraphicsItem *Item);void onClearProperty();void onChangedProperty(QTableWidgetItem *item);
private:Ui::MainWindow *ui;QTimer m_timer;GraphicsView *graphicsView;GraphicsScene * graphicsScene;ToolBoxTreeWidget *itemTreeView;QTreeWidgetItem *ellipseItem;QTreeWidgetItem *rectItem;QTreeWidgetItem *lineItem;QTreeWidgetItem *roundRectItem;QTreeWidgetItem *polylineItem;QTreeWidgetItem *polygonItem;QTreeWidgetItem *bezierItem;//工具栏QToolBar *toolBarDraw;QActionGroup *actGroup;QAction *actSelection;        //选择QAction *actSelectAll;        //全选QAction *actRotation;         //旋转QAction *actFlipHorizontal;   //垂直翻转QAction *actFlipVertical;     //水平翻转QAction *actZoomIn;           //缩小QAction *actZoomOut;          //放大QAction *actDelete;           //删除QToolBar *toolBarAlign;QAction *actLeft;QAction *actRight;QAction *actUp;QAction *actDown;QAction *actCenterHor;QAction *actCenterVer;QAction *actEqualHorSpac;QAction *actEqualVerSpac;QAction *actEqualWidth;QAction *actEqualHeight;QAction *actEqualAll;QAction *actBringToBottom;QAction *actBringToTop;QAction *actBringToFrontLayer;QAction *actBringToBackLayer;//属性PropertyDelegate *m_delegateProperty;
};#endif // MAINWINDOW_H

.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QCheckBox>
#include <QColorDialog>
#include <QComboBox>
#include <QDateTime>
#include <QFontDialog>
#include <QLineEdit>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);graphicsScene = new GraphicsScene(this);graphicsScene->setSceneRect(QRectF(-2400 / 2 , -2400 / 2 , 2400, 2400));graphicsScene->setBackgroundBrush(Qt::white);graphicsView = new GraphicsView(this);setCentralWidget(graphicsView);graphicsView->setScene(graphicsScene);connect(graphicsView,&GraphicsView::SignalitemClicked,this,&MainWindow::onItemClicked);connect(graphicsView,&GraphicsView::ItemEmpty,this,&MainWindow::onClearProperty);connect(&m_timer,SIGNAL(timeout()),this,SLOT(updateUI()));m_timer.start(100);ui->dockWidget_item->setMinimumWidth(280);ui->dockWidget_property->setMinimumHeight(240);initItem();initTool();//m_delegateProperty = new PropertyDelegate;ui->tableWidget_property->setItemDelegateForColumn(1,m_delegateProperty);connect(ui->tableWidget_property,&QTableWidget::itemChanged,this,&MainWindow::onChangedProperty);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::initTool()
{//actSelection = new QAction(QIcon(":/image/arrow.png"),tr("选择"),this);actRotation = new QAction(QIcon(":/image/rotation.png"),tr("旋转"),this);actSelectAll = new QAction(QIcon(":/image/selectAll.png"),tr("全选"),this);actSelectAll->setShortcut(QKeySequence(tr("Ctrl+A")));actFlipHorizontal = new QAction(QIcon(":/image/FlipHorizontal.png"),tr("垂直翻转"),this);actFlipVertical = new QAction(QIcon(":/image/FlipVertical.png"),tr("水平翻转"),this);actZoomIn = new QAction(QIcon(":/image/zoomin.png"),tr("缩小"),this);actZoomOut  = new QAction(QIcon(":/image/zoomout.png"),tr("放大"),this);actDelete = new QAction(QIcon(":/image/delete.png"),tr("删除"),this);actSelection->setCheckable(true);actRotation->setCheckable(true);actGroup = new QActionGroup(this);actGroup->addAction(actSelection);actGroup->addAction(actRotation);actGroup->addAction(actSelectAll);actGroup->addAction(actFlipHorizontal);actGroup->addAction(actFlipVertical);actGroup->addAction(actZoomIn);actGroup->addAction(actZoomOut);actGroup->addAction(actDelete);connect(actGroup,&QActionGroup::triggered,this,&MainWindow::addShape);connect(actZoomIn, &QAction::triggered,this,&MainWindow::onZoomIn);connect(actZoomOut,&QAction::triggered,this,&MainWindow::onZoomOut);connect(actSelectAll, &QAction::triggered,this,&MainWindow::onSelectAll);connect(actFlipHorizontal,&QAction::triggered,this,[=](){flipItems(1);});connect(actFlipVertical,&QAction::triggered,this,[=](){flipItems(0);});connect(actDelete,&QAction::triggered,this,&MainWindow::onDeteleItems);//绘画工具栏toolBarDraw = addToolBar(tr("draw"));toolBarDraw->setIconSize(QSize(24,24));toolBarDraw->addAction(actSelection);toolBarDraw->addAction(actRotation);toolBarDraw->addAction(actDelete);toolBarDraw->addAction(actSelectAll);toolBarDraw->addAction(actFlipHorizontal);toolBarDraw->addAction(actFlipVertical);toolBarDraw->addAction(actZoomIn);toolBarDraw->addAction(actZoomOut);//对齐选项的设置actLeft = new QAction(QIcon(":/image/align_left.png"),tr("左对齐"),this);actRight = new QAction(QIcon(":/image/align_right.png"),tr("右对齐"),this);actUp = new QAction(QIcon(":/image/align_top.png"),tr("上对齐"),this);actDown = new QAction(QIcon(":/image/align_bottom.png"),tr("下对齐"),this);actCenterHor = new QAction(QIcon(":/image/align_hcenter.png"),tr("水平居中"),this);actCenterVer = new QAction(QIcon(":/image/align_vcenter.png"),tr("垂直居中"),this);actEqualHorSpac = new QAction(QIcon(":/image/align_horzeven.png"),tr("水平间距相等"),this);actEqualVerSpac = new QAction(QIcon(":/image/align_verteven.png"),tr("垂直间距相等"),this);actEqualWidth = new QAction(QIcon(":/image/align_width.png"),tr("等宽"),this);actEqualHeight = new QAction(QIcon(":/image/align_height.png"),tr("等高"),this);actEqualAll = new QAction(QIcon(":/image/align_all.png"),tr("等宽又等高"),this);actBringToTop = new QAction(QIcon(":/image/bringtofront.png"),tr("最顶层"),this);actBringToBottom   = new QAction(QIcon(":/image/sendtoback.png"),tr("最底层"),this);actBringToFrontLayer = new QAction(QIcon(":/image/bringtofrontlayer.png"),tr("上一层"),this);actBringToBackLayer = new QAction(QIcon(":/image/sendtobacklayer.png"),tr("下一层"),this);actLeft->setProperty("type",LEFT_ALIGN);actRight->setProperty("type",Right_ALIGN);actUp->setProperty("type",Up_ALIGN);actDown->setProperty("type",Down_ALIGN);actCenterHor->setProperty("type",CenterHor_ALIGN);actCenterVer->setProperty("type",CenterVer_ALIGN);actEqualHorSpac->setProperty("type",EqualHorSpac_ALIGN);actEqualVerSpac->setProperty("type",EqualVerSpac_ALIGN);actEqualWidth->setProperty("type",EqualWidth_ALIGN);actEqualHeight->setProperty("type",EqualHeight_ALIGN);actEqualAll->setProperty("type",EqualAll_ALIGN);//对齐工具栏toolBarAlign = addToolBar(tr("align"));toolBarAlign->setIconSize(QSize(24,24));toolBarAlign->addAction(actLeft);toolBarAlign->addAction(actRight);toolBarAlign->addAction(actUp);toolBarAlign->addAction(actDown);toolBarAlign->addAction(actCenterHor);toolBarAlign->addAction(actCenterVer);toolBarAlign->addAction(actEqualHorSpac);toolBarAlign->addAction(actEqualVerSpac);toolBarAlign->addAction(actEqualWidth);toolBarAlign->addAction(actEqualHeight);toolBarAlign->addAction(actEqualAll);toolBarAlign->addAction(actBringToBottom);toolBarAlign->addAction(actBringToTop);toolBarAlign->addAction(actBringToFrontLayer);toolBarAlign->addAction(actBringToBackLayer);connect(actLeft,&QAction::triggered,this,&MainWindow::onAglinTriggered);connect(actRight,&QAction::triggered,this,&MainWindow::onAglinTriggered);connect(actUp,&QAction::triggered,this,&MainWindow::onAglinTriggered);connect(actDown,&QAction::triggered,this,&MainWindow::onAglinTriggered);connect(actCenterHor,&QAction::triggered,this,&MainWindow::onAglinTriggered);connect(actCenterVer,&QAction::triggered,this,&MainWindow::onAglinTriggered);connect(actEqualHorSpac,&QAction::triggered,this,&MainWindow::onAglinTriggered);connect(actEqualVerSpac,&QAction::triggered,this,&MainWindow::onAglinTriggered);connect(actEqualWidth,&QAction::triggered,this,&MainWindow::onAglinTriggered);connect(actEqualHeight,&QAction::triggered,this,&MainWindow::onAglinTriggered);connect(actEqualAll,&QAction::triggered,this,&MainWindow::onAglinTriggered);connect(actBringToBottom,&QAction::triggered,this,&MainWindow::onBringToBottomTriggered);connect(actBringToTop,&QAction::triggered,this,&MainWindow::onBringToTopTriggered);connect(actBringToFrontLayer,&QAction::triggered,this,&MainWindow::onBringToFrontLayerTriggered);connect(actBringToBackLayer,&QAction::triggered,this,&MainWindow::onBringToBackLayerTriggered);}void MainWindow::initItem()
{itemTreeView = new ToolBoxTreeWidget;ui->verticalLayout_item->addWidget(itemTreeView);itemTreeView->setHeaderLabel("标准");connect(itemTreeView,&QTreeWidget::itemClicked,this,&MainWindow::treeItemAddShape);ellipseItem = new QTreeWidgetItem(itemTreeView,QStringList("椭圆"));ellipseItem->setData(0,Qt::UserRole+1,ellipse);rectItem = new QTreeWidgetItem(itemTreeView,QStringList("矩形"));rectItem->setData(0,Qt::UserRole+1,rectangle);lineItem = new QTreeWidgetItem(itemTreeView,QStringList("直线"));lineItem->setData(0,Qt::UserRole+1,line);roundRectItem = new QTreeWidgetItem(itemTreeView,QStringList("圆角矩形"));roundRectItem->setData(0,Qt::UserRole+1,roundrect);polylineItem = new QTreeWidgetItem(itemTreeView,QStringList("多边线"));polylineItem->setData(0,Qt::UserRole+1,polyline);polygonItem = new QTreeWidgetItem(itemTreeView,QStringList("多边形"));polygonItem->setData(0,Qt::UserRole+1,polygon);bezierItem = new QTreeWidgetItem(itemTreeView,QStringList("贝塞尔曲线"));bezierItem->setData(0,Qt::UserRole+1,bezier);
}void MainWindow::treeItemAddShape(QTreeWidgetItem *item, int column)
{Q_UNUSED(column);if(item == ellipseItem)DrawTool::c_drawShape = ellipse;if(item == rectItem)DrawTool::c_drawShape = rectangle;if(item == lineItem)DrawTool::c_drawShape = line;if(item == roundRectItem)DrawTool::c_drawShape = roundrect;if(item == polylineItem)DrawTool::c_drawShape = polyline;if(item == polygonItem)DrawTool::c_drawShape = polygon;if(item == bezierItem)DrawTool::c_drawShape = bezier;}void MainWindow::addShape(QAction *action)
{if(action == actSelection)DrawTool::c_drawShape = selection;if(action == actRotation)DrawTool::c_drawShape = rotation;
}void MainWindow::updateUI()
{if(DrawTool::c_drawShape == selection)actSelection->setChecked(true);else if(DrawTool::c_drawShape == rotation)actRotation->setChecked(true);actLeft->setEnabled(graphicsView->scene()->selectedItems().count() > 0);actRight->setEnabled(graphicsView->scene()->selectedItems().count() > 0);actUp->setEnabled(graphicsView->scene()->selectedItems().count() > 0);actDown->setEnabled(graphicsView->scene()->selectedItems().count() > 0);actCenterHor->setEnabled(graphicsView->scene()->selectedItems().count() > 0);actCenterVer->setEnabled(graphicsView->scene()->selectedItems().count() > 0);actEqualHorSpac->setEnabled(graphicsView->scene()->selectedItems().count() > 2);actEqualVerSpac->setEnabled(graphicsView->scene()->selectedItems().count() > 2);actEqualWidth->setEnabled(graphicsView->scene()->selectedItems().count() > 1);actEqualHeight->setEnabled(graphicsView->scene()->selectedItems().count() > 1);actEqualAll->setEnabled(graphicsView->scene()->selectedItems().count() > 1);actBringToBottom->setEnabled(graphicsView->scene()->selectedItems().count() > 0);actBringToTop->setEnabled(graphicsView->scene()->selectedItems().count() > 0);actBringToFrontLayer->setEnabled(graphicsView->scene()->selectedItems().count() > 0);actBringToBackLayer->setEnabled(graphicsView->scene()->selectedItems().count() > 0);
}void MainWindow::flipItems(int Axis)
{QList<QGraphicsItem*> list = graphicsView->scene()->selectedItems();if(list.isEmpty()) return;foreach (QGraphicsItem* item, list){GraphicsItem *item_ = dynamic_cast<GraphicsItem *>(item);if(item_){QTransform transform;transform.rotate(180,Qt::Axis(Axis));item_->setFlip(transform,Qt::Axis(Axis));}}graphicsView->scene()->update();
}void MainWindow::onZoomIn()
{graphicsView->zoomIn();
}void MainWindow::onZoomOut()
{graphicsView->zoomOut();
}void MainWindow::onDeteleItems()
{QList<QGraphicsItem *> list = graphicsView->scene()->selectedItems();if(!list.count()) return;foreach (QGraphicsItem* item, list){graphicsView->scene()->removeItem(item);}emit graphicsView->ItemEmpty();
}void MainWindow::onSelectAll()
{QList<QGraphicsItem *> itemList = graphicsView->scene()->items();if(!itemList.empty()){foreach(QGraphicsItem *item,itemList){item->setSelected(true);}}
}void MainWindow::onAglinTriggered()
{QAction *action = dynamic_cast<QAction *>(sender());align((AlignType)action->property("type").toInt());graphicsView->scene()->update();
}void MainWindow::onBringToTopTriggered()
{qDebug()<<"上移至最顶层";QList<QGraphicsItem *> list = graphicsView->scene()->selectedItems();if (list.isEmpty())return;QList<QGraphicsItem *> collideItems = list.first()->collidingItems();foreach(QGraphicsItem *Item,list){for (int i = collideItems.size()-1; i >= 0; --i){if(Item == collideItems[i]){collideItems.removeAt(i);}}}foreach(QGraphicsItem *Item,list){for (int i = collideItems.size()-1; i >= 0; --i){if(GraphicsItem *item = dynamic_cast<GraphicsItem *>(collideItems.at(i))){collideItems.at(i)->stackBefore(Item);}}}graphicsView->scene()->update();
}void MainWindow::onBringToBottomTriggered()
{qDebug()<<"下移至最底层";QList<QGraphicsItem *> list = graphicsView->scene()->selectedItems();if(list.isEmpty()) return;QList<QGraphicsItem *> collideItems = list.first()->collidingItems();foreach(QGraphicsItem *Item,list){for (int i = collideItems.size()-1; i >= 0; --i){if(Item == collideItems[i]){collideItems.removeAt(i);}}}foreach(QGraphicsItem *Item,list){for (int i = 0; i < collideItems.size(); ++i){if(GraphicsItem *item = dynamic_cast<GraphicsItem *>(collideItems.at(i)) ){Item->stackBefore(collideItems.at(i));}}}graphicsView->scene()->update();
}void MainWindow::onBringToFrontLayerTriggered()
{qDebug()<<"上移至上一层";//选中多个时思路为上面的图元先向上移动,下面的图元再向上移动if (graphicsView->scene()->selectedItems().isEmpty())return;std::map<int,QGraphicsItem*> itemMap;QList<QGraphicsItem *> itemList = graphicsView->scene()->items(Qt::AscendingOrder);QList<QGraphicsItem *> selectItems = graphicsView->scene()->selectedItems();foreach(QGraphicsItem *item,selectItems){itemMap[itemList.indexOf(item)] = item;}for(std::map<int,QGraphicsItem*>::reverse_iterator it = itemMap.rbegin();it != itemMap.rend();it++){QList<QGraphicsItem *> list = it->second->collidingItems();int index = itemList.indexOf(it->second);for(QList<QGraphicsItem *>::reverse_iterator it_l = list.rbegin(); it_l != list.rend();it_l++){if(GraphicsItem *item = dynamic_cast<GraphicsItem *>(*it_l)){if(index < itemList.indexOf(item) && selectItems.indexOf(item) == -1){item->stackBefore(it->second);break;}}}}graphicsView->scene()->update();
}void MainWindow::onBringToBackLayerTriggered()
{qDebug()<<"下移至下一层";//选中多个时思路为下面的图元先向下移动,上面的图元再向下移动if (graphicsView->scene()->selectedItems().isEmpty())return;std::map<int,QGraphicsItem*> itemMap;QList<QGraphicsItem *> itemList = graphicsView->scene()->items(Qt::AscendingOrder);QList<QGraphicsItem *> selectItems = graphicsView->scene()->selectedItems();foreach(QGraphicsItem *item,graphicsView->scene()->selectedItems()){itemMap[itemList.indexOf(item)] = item;}for(std::map<int,QGraphicsItem*>::iterator it = itemMap.begin();it != itemMap.end();it++){QList<QGraphicsItem *> list = it->second->collidingItems();int index = itemList.indexOf(it->second);for(QList<QGraphicsItem *>::iterator it_l = list.begin(); it_l != list.end();it_l++){if(GraphicsItem *item = dynamic_cast<GraphicsItem *>(*it_l)){if(index > itemList.indexOf(item) && selectItems.indexOf(item) == -1){it->second->stackBefore(item);break;}}}}graphicsView->scene()->update();
}bool operator< (const BBoxSort &a, const BBoxSort &b)
{return (a.anchor < b.anchor);
}//对齐函数
void MainWindow::align(AlignType alignType)
{QGraphicsItem *referenceItem = nullptr;QList<QGraphicsItem*> list;GraphicsScene *scene = dynamic_cast<GraphicsScene *>(graphicsView->scene());if(scene){list = scene->selectedItems();}switch ( alignType ){case Right_ALIGN://右对齐{foreach(QGraphicsItem *item,list){if(referenceItem == nullptr){referenceItem = item;}else{if(item->mapToScene(item->pos()).x() > referenceItem->mapToScene(referenceItem->pos()).x())referenceItem = item;}}}break;case Up_ALIGN://上对齐{foreach(QGraphicsItem *item,list){if(referenceItem == nullptr){referenceItem = item;}else{if(item->mapToScene(item->pos()).y() < referenceItem->mapToScene(referenceItem->pos()).y())referenceItem = item;}}}break;case Down_ALIGN://下对齐{foreach(QGraphicsItem *item,list){if(referenceItem == nullptr){referenceItem = item;}else{if(item->mapToScene(item->pos()).y() > referenceItem->mapToScene(referenceItem->pos()).y())referenceItem = item;}}}break;default://    case CenterHor_ALIGN://水平居中对齐//    case CenterVer_ALIGN://垂直居中对齐//    case EqualAll_ALIGN://相同宽度以及高度 对齐//    case EqualWidth_ALIGN://相同宽度对齐//    case EqualHeight_ALIGN://相同高度对齐//    case LEFT_ALIGN://左对齐{foreach(QGraphicsItem *item,list){if(referenceItem == nullptr){referenceItem = item;}else{if(item->mapToScene(item->pos()).x() < referenceItem->mapToScene(referenceItem->pos()).x())referenceItem = item;}}}break;}//GraphicsRectItem *firstItem = qgraphicsitem_cast<GraphicsRectItem *>(referenceItem);if (!firstItem) return;QRectF rectref = firstItem->mapRectToScene(firstItem->boundingRect());int nLeft, nRight, nTop, nBottom;qreal width = firstItem->width();qreal height = firstItem->height();nLeft=nRight=rectref.center().x();nTop=nBottom=rectref.center().y();QPointF pt = rectref.center();qDebug()<<"第一个图元的中心点"<<pt;//水平、垂直 间距相等if ( alignType == EqualHorSpac_ALIGN || alignType == EqualVerSpac_ALIGN ){std::vector< BBoxSort  > sorted;foreach (QGraphicsItem *item , list){QGraphicsItemGroup *g = dynamic_cast<QGraphicsItemGroup*>(item->parentItem());if(g)continue;sorted.push_back(BBoxSort(item,item->mapRectToScene(item->boundingRect()),alignType));}//sort bbox by anchorsstd::sort(sorted.begin(), sorted.end());unsigned int len = sorted.size();bool changed = false;//overall bboxes span跨度值float dist = (sorted.back().max()-sorted.front().min());//space eaten by bboxesfloat span = 0;for (unsigned int i = 0; i < len; i++){span += sorted[i].extent();}//new distance between each bboxfloat step = (dist - span) / (len - 1);float pos = sorted.front().min();for(std::vector<BBoxSort>::iterator it = sorted.begin();it<sorted.end();++it){QPointF t;if(alignType == EqualHorSpac_ALIGN)t.setX( pos - it->min() );elset.setY(pos - it->min());it->item_->setPos(t.x(),t.y());changed = true;pos += it->extent();pos += step;}return;}int i = 0;foreach (QGraphicsItem *item , list){QGraphicsItemGroup *g = dynamic_cast<QGraphicsItemGroup*>(item->parentItem());if(g)continue;QRectF rectItem = item->mapRectToScene(item->boundingRect());QPointF ptNew = rectItem.center();//第一个图元的中心点switch ( alignType ){case Up_ALIGN://上对齐ptNew.setY(nTop + (rectItem.height()-rectref.height())/2);break;case CenterHor_ALIGN://水平居中对齐ptNew.setY(pt.y());break;case CenterVer_ALIGN://垂直居中对齐ptNew.setX(pt.x());break;case Down_ALIGN://下对齐ptNew.setY(nBottom-(rectItem.height()-rectref.height())/2);break;case LEFT_ALIGN://左对齐ptNew.setX(nLeft-(rectref.width()-rectItem.width())/2);break;case Right_ALIGN://右对齐ptNew.setX(nRight+(rectref.width()-rectItem.width())/2);break;case EqualAll_ALIGN://相同宽度以及高度 对齐{GraphicsRectItem * aitem = qgraphicsitem_cast<GraphicsRectItem*>(item);if(aitem){qreal fx = width / aitem->width();qreal fy = height / aitem->height();if ( fx == 1.0 && fy == 1.0 ) break;aitem->updateCoordinate();}break;}case EqualWidth_ALIGN://相同宽度对齐{GraphicsRectItem * aitem = qgraphicsitem_cast<GraphicsRectItem*>(item);if(aitem){qreal fx = width / aitem->width();if(fx == 1.0) break;aitem->updateCoordinate();}}break;case EqualHeight_ALIGN://相同高度对齐{GraphicsRectItem * aitem = qgraphicsitem_cast<GraphicsRectItem*>(item);if(aitem){qreal fy = height / aitem->height();if(fy == 1.0) break;aitem->updateCoordinate();}}break;}QPointF ptLast= rectItem.center();QPointF ptMove = ptNew - ptLast;if ( !ptMove.isNull()){item->setPos(ptMove.x(),ptMove.y());}i++;}
}void MainWindow::getPropertyValue(QString propertyName, ItemProperty property, EditData *edit)
{if(propertyName == "位置X"){edit->Type = "STRING";edit->VariantData = QString("%1").arg(property.x);}else if(propertyName == "位置Y"){edit->Type = "STRING";edit->VariantData = QString("%1").arg(property.y);}else if(propertyName == "长度"){edit->Type = "STRING";edit->VariantData = QString("%1").arg(property.width);}else if(propertyName == "宽度"){edit->Type = "STRING";edit->VariantData = QString("%1").arg(property.height);}else if(propertyName == "角半径X"){edit->Type = "STRING";edit->VariantData = QString("%1").arg(property.xRadius);}else if(propertyName == "角半径Y"){edit->Type = "STRING";edit->VariantData = QString("%1").arg(property.yRadius);}else if(propertyName == "背景颜色"){edit->Type = "COLOR";edit->VariantData = property.backgroundColor;}else if(propertyName == "线条颜色"){edit->Type = "COLOR";edit->VariantData = property.lineBrush;}else if(propertyName == "线宽"){edit->Type = "STRING";edit->VariantData = QString("%1").arg(property.LineWidth);}else if(propertyName == "线型"){edit->Type = "LINETYPE";edit->VariantData = property.LineType;}else if(propertyName == "旋转角度"){edit->Type = "STRING";edit->VariantData = property.rotation;}else if(propertyName == "线端"){edit->Type = "LINEEND";edit->VariantData = QString("%1").arg(property.LineEnd);}
}void MainWindow::showProperty(ItemProperty property, long long propertyValue)
{long long tmpPropertyValue = PROPERTY_BACKGROUNDCOLOR|PROPERTY_POSITIONX|PROPERTY_POSITIONY|PROPERTY_WIDTH|PROPERTY_HEIGHT|PROPERTY_LINECOLOR|PROPERTY_LINEWIDTH|PROPERTY_LINETYPE|PROPERTY_RADIUSX|PROPERTY_RADIUSY|PROPERTY_ROTATION|PROPERTY_LINEEND;QStringList list;EditData *edit = new EditData;tmpPropertyValue &= propertyValue;getPropertyName(list,tmpPropertyValue);ui->tableWidget_property->setRowCount(list.size());ui->tableWidget_property->setColumnCount(2);for(int i = 0;i < list.size();i++){QString propertyName = list[i];getPropertyValue(propertyName,property,edit);QTableWidgetItem *item1 = new QTableWidgetItem(propertyName);item1->setFlags(item1->flags() & ~Qt::ItemIsEditable); // 移除可编辑标志ui->tableWidget_property->setItem(i,0,item1);QTableWidgetItem *item2 = new QTableWidgetItem();item2->setData(Qt::DisplayRole,QVariant::fromValue(*edit));ui->tableWidget_property->setItem(i,1,item2);}
}void MainWindow::onItemClicked(QGraphicsItem *Item)
{onClearProperty();if(GraphicsItem *i = dynamic_cast<GraphicsItem *>(Item)){ItemProperty property;i->getProperty(property);showProperty(property,i->m_property);}
}void MainWindow::onClearProperty()
{ui->tableWidget_property->clearContents();
}void MainWindow::onChangedProperty(QTableWidgetItem *item)
{EditData editdata = item->data(Qt::DisplayRole).value<EditData>();QList<QGraphicsItem *> list = graphicsView->scene()->selectedItems();if(item->column() == 1){if(ui->tableWidget_property->item(item->row(),0)){//获取属性名称QString propertyName = ui->tableWidget_property->item(item->row(),0)->text();if(list.size() == 1){GraphicsItem *Item = qgraphicsitem_cast<GraphicsItem *>(list[0]);if(Item == nullptr)return;ItemProperty property;Item->getProperty(property);if(propertyName == "背景颜色"){QColor v = editdata.VariantData.value<QColor>();QBrush *brush = new QBrush(v);property.backgroundColor = *brush;}else if(propertyName == "线条颜色"){QColor v = editdata.VariantData.value<QColor>();QBrush *brush = new QBrush(v);property.lineBrush = *brush;}else if(propertyName == "线宽"){property.LineWidth = editdata.VariantData.toInt();}else if(propertyName == "线型"){property.LineType = editdata.VariantData.toInt();}else if(propertyName == "位置X"){property.x = editdata.VariantData.toDouble();}else if(propertyName == "位置Y"){property.y = editdata.VariantData.toDouble();}else if(propertyName == "长度"){property.width = editdata.VariantData.toDouble() == 0 ? 2 :editdata.VariantData.toDouble();}else if(propertyName == "宽度"){property.height = editdata.VariantData.toDouble() == 0 ? 2 :editdata.VariantData.toDouble();}else if(propertyName == "角半径X"){property.xRadius = editdata.VariantData.toInt();}else if(propertyName == "角半径Y"){property.yRadius = editdata.VariantData.toInt();}else if(propertyName == "旋转角度"){property.rotation = editdata.VariantData.toInt();}else if(propertyName == "线端"){property.LineEnd = editdata.VariantData.toString();}Item->setProperty(property);Item->scene()->update();}}}
}

.ui

2.propertydialog

.h

#ifndef TABLEDELEGATE_H
#define TABLEDELEGATE_H#include <QObject>
#include <QStyledItemDelegate>
#include <QColorDialog>
#include <QDebug>
#include <QFontDialog>
#include <QLineEdit>
#include <QComboBox>
#include <QCheckBox>
#include <QApplication>
#include <QMouseEvent>
#include "propertydialog.h"typedef struct EditData
{QString Type;QVariant VariantData;
}EditData;
Q_DECLARE_METATYPE(EditData)//将自定义类型注册到Qt元对象系统,使其能被QVariant容器存储// 属性栏委托
class PropertyDelegate : public QStyledItemDelegate
{Q_OBJECT
public:PropertyDelegate(QObject *parent = 0);QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const override;void setEditorData(QWidget *editor, const QModelIndex &index) const override;void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const override;void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;public:};#endif // TABLEDELEGATE_H

.cpp

#include "tabledelegate.h"// 属性栏委托
PropertyDelegate::PropertyDelegate(QObject *parent): QStyledItemDelegate(parent)
{
}QWidget *PropertyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & option ,const QModelIndex & index ) const
{QWidget* ret = NULL;EditData edit = index.data().value<EditData>();//颜色窗口控件if(edit.Type == "COLOR" ){QColor color = edit.VariantData.value<QColor>();QColorDialog *colorDialog = new QColorDialog(parent);colorDialog->setOption(QColorDialog::DontUseNativeDialog); // 强制使用 Qt 自绘对话框//为窗口添加透明度值修改colorDialog->setOption(QColorDialog::ShowAlphaChannel);colorDialog->setCurrentColor(color);return colorDialog;}//LineEdit控件else if(edit.Type == "STRING"){QLineEdit *lineEdit = new QLineEdit(parent);return lineEdit;}//线型控件else if(edit.Type == "LINETYPE"  ){LineTypeDialog *linetype = new LineTypeDialog(parent);linetype->type = edit.VariantData.toInt();linetype->radiochaecked(linetype->type);return linetype;}//线端自定义控件else if(edit.Type == "LINEEND"  ){LineEndDialog *linedialog = new LineEndDialog(parent);linedialog->left = edit.VariantData.toString().section(',',0,0).toInt();linedialog->right = edit.VariantData.toString().section(',',1,1).toInt();linedialog->ischecked();return linedialog;}else{// 其它情况,直接使用父类提供的默认创建编辑器组件方式ret = QStyledItemDelegate::createEditor(parent, option, index);return ret;}return NULL;
}void PropertyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{EditData edit = index.data(Qt::DisplayRole).value<EditData>();if(edit.Type == "COLOR"){//QColorDialog *color = dynamic_cast<QColorDialog*>(editor);}else if(edit.Type == "STRING" ){QLineEdit *line = dynamic_cast<QLineEdit*>(editor);line->setText(edit.VariantData.toString());}else if(edit.Type == "LINETYPE"  ){//LineTypeDialog* cb = dynamic_cast<LineTypeDialog*>(editor);}else if(edit.Type == "LINEEND"  ){//LineEndDialog* cb = dynamic_cast<LineEndDialog*>(editor);}else{QStyledItemDelegate::setEditorData(editor, index);}
}void PropertyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const
{EditData edit = index.data(Qt::DisplayRole).value<EditData>();if(edit.Type == "COLOR"){QColorDialog *color = dynamic_cast<QColorDialog*>(editor);if( color != NULL ){if(color->selectedColor() != QColor()){edit.VariantData = color->selectedColor();model->setData(index, QVariant::fromValue(edit),Qt::DisplayRole);}}}else if( edit.Type == "STRING" ){QLineEdit* cb = dynamic_cast<QLineEdit*>(editor);if( cb != NULL ){edit.VariantData = cb->text();model->setData(index,QVariant::fromValue(edit) , Qt::DisplayRole);}}else if(edit.Type == "LINETYPE"  ){LineTypeDialog* cb = dynamic_cast<LineTypeDialog*>(editor);edit.VariantData = cb->type;model->setData(index, QVariant::fromValue(edit), Qt::DisplayRole);}else if(edit.Type == "LINEEND"  ){LineEndDialog* cb = dynamic_cast<LineEndDialog*>(editor);edit.VariantData = cb->s;model->setData(index, QVariant::fromValue(edit), Qt::DisplayRole);}else{QStyledItemDelegate::setModelData(editor, model, index);}
}void PropertyDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{if(QColorDialog* cb = dynamic_cast<QColorDialog*>(editor)){cb->resize(cb->width(),cb->height());}else if(LineTypeDialog* cb = dynamic_cast<LineTypeDialog*>(editor)){cb->resize(cb->width(),cb->height());}else if(LineEndDialog* cb = dynamic_cast<LineEndDialog*>(editor)){cb->resize(173, 231);}else{editor->setGeometry(option.rect);}
}void PropertyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{EditData edit = index.data(Qt::DisplayRole).value<EditData>();if(edit.Type == "COLOR"){EditData s = index.data(Qt::DisplayRole).value<EditData>();QColor s1 = s.VariantData.value<QColor>();s1.setAlpha(255);QStyleOptionViewItem viewOption(option);QPen pen;pen.setBrush(Qt::black);pen.setWidth(3);painter->setPen(pen);painter->setBrush(QBrush(s1));painter->drawRect(option.rect.x()+2,option.rect.y()+2,option.rect.width()-4,option.rect.height()-4);option.rect.left();}else if(edit.Type == "STRING"){EditData s = index.data(Qt::DisplayRole).value<EditData>();QStyleOptionViewItem viewOption(option);QPen pen;QFont font;font.setPointSize(10);pen.setBrush(Qt::black);pen.setWidth(2);painter->setFont(font);painter->setPen(pen);painter->drawText(option.rect.x(),option.rect.y()+20,s.VariantData.toString());}else if(edit.Type == "LINETYPE"){EditData s = index.data(Qt::DisplayRole).value<EditData>();QStyleOptionViewItem viewOption(option);QPen pen;QFont font;font.setPointSize(10);pen.setBrush(Qt::black);pen.setWidth(2);painter->setFont(font);painter->setPen(pen);PaintTypeLine(*painter,QPoint(option.rect.left()+10,option.rect.y()+15),QPoint(option.rect.right()-10,option.rect.y()+15),s.VariantData.toInt());}else if(edit.Type == "LINEEND"){EditData s = index.data(Qt::DisplayRole).value<EditData>();QStyleOptionViewItem viewOption(option);QPen pen;QFont font;font.setPointSize(10);pen.setBrush(Qt::black);pen.setWidth(2);painter->setFont(font);painter->setPen(pen);paintLine(*painter,QPoint(option.rect.left()+10,option.rect.y()+15),QPoint(option.rect.right()-10,option.rect.y()+15),s.VariantData.toString());}else{QStyledItemDelegate::paint(painter, option, index);}}

3.item

.h

#ifndef ITEM_H
#define ITEM_H#include <QGraphicsObject>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QPainterPath>
#include <QtMath>
#include <QDebug>
#include "sizehandle.h"#define PROPERTY_BACKGROUNDCOLOR 0x01
#define PROPERTY_POSITIONX 0x02
#define PROPERTY_POSITIONY 0x4
#define PROPERTY_WIDTH 0x08
#define PROPERTY_HEIGHT 0x10
#define PROPERTY_LINECOLOR 0x20
#define PROPERTY_LINEWIDTH 0x40
#define PROPERTY_LINETYPE 0x80
#define PROPERTY_RADIUSX 0x100
#define PROPERTY_RADIUSY 0x200
#define PROPERTY_ROTATION 0x400
#define PROPERTY_LINEEND 0x800void getPropertyName(QStringList  &list,long long propertyValue);//线段类型
enum LINE_END
{TYPR_NO_END,//无TYPE_HOLLOW_END,//TYPE_SOLID_LEFT_END,TYPE_SOLID_RIGHT_END,TYPE_LINE_END
};//
struct ItemProperty
{int x;int y;int width;int height;QBrush backgroundColor;QBrush lineBrush;qreal LineWidth;int LineType;//线型QString LineEnd;//线端(直线)int rotation;//旋转角int xRadius;//x半径(圆角矩形)int yRadius;//y半径(圆角矩形)};class GraphicsItem :public QGraphicsObject//QAbstractGraphicsShapeItem,public QObject
{
public:GraphicsItem(QGraphicsItem *parent = nullptr);enum {Type = UserType+1};int type() const override {return Type;}int  collidesTheSizeHandle(const QPoint & point) const;virtual void resizeTo(int dir, const QPoint &point);virtual QPoint origin() const {return QPoint(0,0);}//起点virtual Qt::CursorShape getCursor(int dir);virtual QRectF rect() const {return m_localRect;}virtual QPoint opposite(int dir);virtual void stretch(int handle , double sx , double sy , const QPoint & origin) = 0;// handle位置virtual QPoint pointHandle(Direction dir_1);typedef QVector<QGraphicsRectItem*> Handles;Handles m_handles;int collidesWithHandle(const QPoint &point,bool isHandle) const;//宽度或高度修改之后,及时更新外边框矩形等坐标信息virtual void updateCoordinate();//设置sizeHandle状态void setState(SelectionHandleState st);QPoint collidesHandlePos(int dir);QBrush brush() const{return m_brush;}QPen pen() const{return m_pen;}void setBrush(const QBrush &brush){m_brush = brush;update();}void setPen(const QPen &pen){m_pen = pen;update();}virtual void setFlip(QTransform transForm,Qt::Axis axis);qreal width() const {return m_width;}qreal height() const {return m_height;}//属性long long m_property;virtual void setProperty(ItemProperty property);virtual void getProperty(ItemProperty &property);
protected://更新handlesvirtual void updatehandles();virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override;void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;void mouseReleaseEvent(QGraphicsSceneMouseEvent *even) override;virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;int m_width;int m_height;//QRectF m_localRect;QBrush m_brush;QPen m_pen;
};//矩形
class GraphicsRectItem : public GraphicsItem
{Q_OBJECT
public:GraphicsRectItem(const QRect &rect,QGraphicsItem *parent = nullptr);QRectF boundingRect() const;QPainterPath shape() const;//拖拽sizehandle改变图元大小virtual void resizeTo(int dir, const QPoint &point);virtual QRectF rect() const {return m_localRect;}//virtual void stretch(int handle,double sx,double sy,const QPoint &origin);virtual void updateCoordinate();virtual void setProperty(ItemProperty property);virtual void getProperty(ItemProperty &property);
protected:void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);QRectF m_initialRect;
};//椭圆
class GraphicsEllipseItem :public GraphicsRectItem
{
public:GraphicsEllipseItem(const QRect &rect,QGraphicsItem *parent = nullptr);QPainterPath shape() const;protected:void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};//圆角矩形
class GraphicsRoundRectItem :public GraphicsRectItem
{
public:GraphicsRoundRectItem(const QRect &rect,QGraphicsItem *parent = nullptr);QPainterPath shape() const;//返回虚线图形void setProperty(ItemProperty property);void getProperty(ItemProperty &property);
protected:void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);private:int m_xRadius;int m_yRadius;
};//多边形
class GraphicsPolygonItem :public GraphicsItem
{
public:GraphicsPolygonItem(QGraphicsItem *parent = nullptr);QRectF boundingRect() const;QPainterPath shape() const;virtual void addPoint(const QPoint & point);virtual void endPoint(const QPoint & point);virtual void resizeTo(int dir, const QPoint &point);virtual QRectF rect() const {return m_localRect;}void stretch(int handle,double sx,double sy,const QPoint &origin);virtual Direction getCurrentCount(){return static_cast<Direction>(m_points.size()+ None);}virtual void updateCoordinate();void setFlip(QTransform transForm,Qt::Axis axis);void updatehandles();protected:void paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget);QPolygon m_points;//点集QPolygon m_initialPoints;QRectF m_localRect;
};//直线
class GraphicsLineItem :public GraphicsPolygonItem
{
public:GraphicsLineItem(QGraphicsItem *parent = nullptr);GraphicsLineItem(QPoint startPoint,QPoint endPoint,QGraphicsItem *parent = nullptr);QPainterPath shape() const;virtual void addPoint(const QPoint &point);virtual void endPoint(const QPoint &point);virtual void updateCoordinate();void updatehandles();void setProperty(ItemProperty property);void getProperty(ItemProperty &property);void painterLineEnd(QPainter *painter,QPoint LeftPoint,QPoint RightPoint);protected:void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);private:int m_nleftIndex;int m_nrightIndex;
};//折线
class GraphicsPolylineItem :public GraphicsPolygonItem
{
public:GraphicsPolylineItem(QGraphicsItem *parent = nullptr);QPainterPath shape() const override;protected:void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
};//贝塞尔曲线
class GraphicsBezierItem :public GraphicsPolygonItem
{
public:GraphicsBezierItem(QGraphicsItem *parent = nullptr);QPainterPath shape() const override;protected:void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
};#endif // ITEM_H

.cpp

#include "item.h"static QPainterPath qt_graphicsItem_shapeFromPath(const QPainterPath &path, const QPen &pen)
{// We unfortunately need this hack as QPainterPathStroker will set a width of 1.0// if we pass a value of 0.0 to QPainterPathStroker::setWidth()const qreal penWidthZero = qreal(0.00000001);if (path == QPainterPath() || pen == Qt::NoPen)return path;QPainterPathStroker ps;ps.setCapStyle(pen.capStyle());if (pen.widthF() <= 0.0)ps.setWidth(penWidthZero);elseps.setWidth(pen.widthF());ps.setJoinStyle(pen.joinStyle());ps.setMiterLimit(pen.miterLimit());QPainterPath p = ps.createStroke(path);p.addPath(path);return p;
}GraphicsItem::GraphicsItem(QGraphicsItem *parent):QGraphicsObject(parent)
{//添加sizihandle,设置可移动、可选择、改变大小信号功能m_handles.reserve(None);for (int i= LeftTop;i <= Left;++i){SizeHandleRect *shr = new SizeHandleRect(this, static_cast<Direction>(i), false);m_handles.push_back(shr);}setFlag(QGraphicsItem::ItemIsMovable, true);setFlag(QGraphicsItem::ItemIsSelectable, true);setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);setPen(QPen(QBrush(QColor("black")),2));setBrush(QBrush(QColor(Qt::red)));//this->setAcceptHoverEvents(true);m_property = PROPERTY_BACKGROUNDCOLOR | PROPERTY_POSITIONX | PROPERTY_POSITIONY| PROPERTY_LINECOLOR | PROPERTY_LINEWIDTH | PROPERTY_LINETYPE | PROPERTY_ROTATION;
}void GraphicsItem::updatehandles()
{const QRectF &geom = this->boundingRect();const Handles::iterator hend =  m_handles.end();for (Handles::iterator it = m_handles.begin(); it != hend; ++it){SizeHandleRect *hndl = static_cast<SizeHandleRect*>(*it);switch (hndl->dir()) {case LeftTop:hndl->move(geom.x(),geom.y());break;case Top:hndl->move(geom.x()+geom.width()/2,geom.y());break;case RightTop:hndl->move(geom.x()+geom.width(),geom.y());break;case Right:hndl->move(geom.x()+geom.width(),geom.y()+geom.height()/2);break;case RightBottom:hndl->move(geom.x()+geom.width(),geom.y()+geom.height());break;case Bottom:hndl->move(geom.x()+geom.width()/2,geom.y()+geom.height());break;case LeftBottom:hndl->move(geom.x(),geom.y()+geom.height());break;case Left:hndl->move(geom.x(),geom.y()+geom.height()/2);break;default:break;}}
}void GraphicsItem::updateCoordinate()
{}void GraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{QGraphicsItem::mousePressEvent(event);if(event->button() == Qt::RightButton){if(!isSelected()){scene()->clearSelection();setSelected(true);}}
}void GraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{QGraphicsItem::mouseMoveEvent(event);
}void GraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *even)
{QGraphicsItem::mouseReleaseEvent(even);
}QVariant GraphicsItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{if ( change == QGraphicsItem::ItemSelectedHasChanged ){//qDebug()<<" Item Selected : " << value.toString();setState(value.toBool() ? SelectionHandleActive : SelectionHandleOff);}else if ( change == QGraphicsItem::ItemRotationHasChanged ){//qDebug()<<"Item Rotation Changed:" << value.toString();}else if ( change == QGraphicsItem::ItemTransformOriginPointHasChanged ){//qDebug()<<"ItemTransformOriginPointHasChanged:" << value.toPointF();}return value;
}void GraphicsItem::setState(SelectionHandleState st)
{const Handles::iterator hend =  m_handles.end();for (Handles::iterator it = m_handles.begin();it != hend;++it)dynamic_cast<SizeHandleRect*>(*it)->setState(static_cast<SelectionHandleState>(st));
}int GraphicsItem::collidesTheSizeHandle(const QPoint &point) const
{const Handles::const_reverse_iterator hend =  m_handles.rend();for (Handles::const_reverse_iterator it = m_handles.rbegin(); it != hend; ++it){if (dynamic_cast<SizeHandleRect*>(*it)->hitTest(point)){return dynamic_cast<SizeHandleRect*>(*it)->dir();}}return None;
}Qt::CursorShape GraphicsItem::getCursor(int dir)
{switch (dir) {case Right:return Qt::SizeHorCursor;case RightTop:return Qt::SizeBDiagCursor;case RightBottom:return Qt::SizeFDiagCursor;case LeftBottom:return Qt::SizeBDiagCursor;case Bottom:return Qt::SizeVerCursor;case LeftTop:return Qt::SizeFDiagCursor;case Left:return Qt::SizeHorCursor;case Top:return Qt::SizeVerCursor;default:return Qt::SizeAllCursor;}return Qt::ArrowCursor;
}QPoint GraphicsItem::opposite(int dir)
{int diraction;switch (dir) {case 0:diraction = 4;break;case 1:diraction = 5;break;case 2:diraction = 6;break;case 3:diraction = 7;break;case 4:diraction = 0;break;case 5:diraction = 1;break;case 6:diraction = 2;break;case 7:diraction = 3;break;}return pointHandle((Direction)diraction);
}QPoint GraphicsItem::pointHandle(Direction dir_1)
{Direction dir = static_cast<Direction>(dir_1);return m_handles.at(dir)->pos().toPoint();
}int GraphicsItem::collidesWithHandle(const QPoint &point, bool isHandle) const
{const Handles::const_reverse_iterator hend = m_handles.rend();for (Handles::const_reverse_iterator it = m_handles.rbegin();it != hend;++it){QPoint pt = (*it)->mapFromScene(point).toPoint();if(!isHandle){//扩大handle范围更容易被选中qreal width = (m_width/3)*2;qreal height = (m_height/3)*2;QPoint point_1 = (*it)->boundingRect().center().toPoint();QRectF rect(point_1.x()-m_width/3,point_1.y()-m_height/3,width,height);if (rect.contains(pt)&& contains(pt))  //{int a = dynamic_cast<SizeHandleRect*>(*it)->dir();//只允许上下左右点连接,其余点不可连接if(a%2){return a;}}}else{if ((*it)->contains(pt))  // && contains(pt){return dynamic_cast<SizeHandleRect*>(*it)->dir();}}}return None;
}QPoint GraphicsItem::collidesHandlePos(int dir)
{return mapToScene(m_handles.at(dir)->pos()).toPoint();
}void GraphicsItem::resizeTo(int dir, const QPoint &point)
{Q_UNUSED(dir);Q_UNUSED(point);
}void GraphicsItem::setFlip(QTransform transForm, Qt::Axis axis)
{Q_UNUSED(axis);setTransform(transForm);
}void GraphicsItem::setProperty(ItemProperty property)
{QColor linecolor = property.lineBrush.color();//linecolor.setAlpha(property.Linealpha);QPen pen(QBrush(linecolor),property.LineWidth);switch(property.LineType){case 0:pen.setStyle(Qt::SolidLine);break;case 1:pen.setStyle(Qt::DashLine);break;case 2:pen.setStyle(Qt::DotLine);break;case 3:pen.setStyle(Qt::DashDotLine);break;case 4:pen.setStyle(Qt::DashDotDotLine);break;}setPen(pen);QColor color = property.backgroundColor.color();setBrush(QBrush(color));setPos(property.x,property.y);setRotation(property.rotation);
}void GraphicsItem::getProperty(ItemProperty &property)
{property.LineWidth = pen().width();property.lineBrush = pen().brush();//property.Linealpha = pen().brush().color().alpha();property.x = pos().x();property.y = pos().y();property.backgroundColor = brush();//property.alpha = brush().color().alpha();property.LineType = pen().style()-1;property.rotation = rotation();
}//矩形
GraphicsRectItem::GraphicsRectItem(const QRect & rect , QGraphicsItem *parent):GraphicsItem(parent)
{//初始化属性m_width = rect.width();m_height = rect.height();m_initialRect = rect;m_localRect = m_initialRect;updatehandles();m_property = m_property | PROPERTY_WIDTH | PROPERTY_HEIGHT;
}void GraphicsRectItem::stretch(int handle , double sx, double sy, const QPoint &origin)
{QTransform trans;switch (handle) {case Right:case Left:sy = 1;break;case Top:case Bottom:sx = 1;break;default:break;}trans.translate(origin.x(),origin.y());trans.scale(sx,sy);trans.translate(-origin.x(),-origin.y());prepareGeometryChange();m_localRect = trans.mapRect(m_initialRect);m_width = m_localRect.width();m_height = m_localRect.height();updatehandles();
}void GraphicsRectItem::updateCoordinate()
{GraphicsItem::updateCoordinate();QPoint pt1,pt2,delta;//在项坐标中返回转换的源点(用于旋转和放缩)pt1 = mapToScene(transformOriginPoint()).toPoint();pt2 = mapToScene(m_localRect.center()).toPoint();delta = pt1 - pt2;m_width < 2 ? m_width = 2 : m_width = m_width;m_height < 2 ? m_height = 2 : m_height = m_height;if (!parentItem()){prepareGeometryChange();//为了通过m_width和m_height来改变boundingRectm_localRect = QRectF(-m_width/2,-m_height/2,m_width,m_height);m_width = m_localRect.width();m_height = m_localRect.height();setTransform(transform().translate(delta.x(),delta.y()));setTransformOriginPoint(m_localRect.center());moveBy(-delta.x(),-delta.y());setTransform(transform().translate(-delta.x(),-delta.y()));updatehandles();}m_initialRect = m_localRect;
}//定义一个矩形(包含左上点坐标以及宽度、高度)
QRectF GraphicsRectItem::boundingRect() const
{return m_localRect;
}QPainterPath GraphicsRectItem::shape() const
{QPainterPath path;path.addRect(rect());return qt_graphicsItem_shapeFromPath(path,pen());
}void GraphicsRectItem::resizeTo(int dir, const QPoint &point)
{QPoint local = mapFromScene(point).toPoint();QRect delta = this->rect().toRect();switch (dir) {case Right:delta.setRight(local.x());break;case RightTop:delta.setTopRight(local);break;case RightBottom:delta.setBottomRight(local);break;case LeftBottom:delta.setBottomLeft(local);break;case Bottom:delta.setBottom(local.y());break;case LeftTop:delta.setTopLeft(local);break;case Left:delta.setLeft(local.x());break;case Top:delta.setTop(local.y());break;default:break;}prepareGeometryChange();m_width = delta.width()>0?delta.width():-delta.width();m_height = delta.height()>0?delta.height():-delta.height();updatehandles();
}void GraphicsRectItem::setProperty(ItemProperty property)
{GraphicsItem::setProperty(property);m_width = property.width;m_height = property.height;//setRotation(m_angle);updateCoordinate();
}void GraphicsRectItem::getProperty(ItemProperty &property)
{GraphicsItem::getProperty(property);property.width = m_width;property.height = m_height;
}void GraphicsRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{Q_UNUSED(option);Q_UNUSED(widget);painter->setPen(pen());painter->setBrush(brush());painter->drawRect(m_localRect);updatehandles();
}//椭圆
GraphicsEllipseItem::GraphicsEllipseItem(const QRect &rect, QGraphicsItem *parent):GraphicsRectItem(rect,parent)
{}QPainterPath GraphicsEllipseItem::shape() const
{QPainterPath path;path.addEllipse(boundingRect());return qt_graphicsItem_shapeFromPath(path,pen());
}void GraphicsEllipseItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{Q_UNUSED(option);Q_UNUSED(widget);QRectF rc = rect();painter->setPen(pen());painter->setBrush(brush());painter->drawEllipse(rc);updatehandles();
}//圆角矩形
GraphicsRoundRectItem::GraphicsRoundRectItem(const QRect &rect, QGraphicsItem *parent):GraphicsRectItem(rect,parent)
{m_xRadius = 15;m_yRadius = 15;m_property = m_property | PROPERTY_RADIUSX | PROPERTY_RADIUSY;
}QPainterPath GraphicsRoundRectItem::shape() const
{QPainterPath path;path.addRoundedRect(boundingRect(),m_xRadius,m_yRadius);return qt_graphicsItem_shapeFromPath(path,pen());
}void GraphicsRoundRectItem::setProperty(ItemProperty property)
{GraphicsRectItem::setProperty(property);m_xRadius = property.xRadius;m_yRadius = property.yRadius;
}void GraphicsRoundRectItem::getProperty(ItemProperty &property)
{GraphicsRectItem::getProperty(property);property.xRadius = m_xRadius;property.yRadius = m_yRadius;
}void GraphicsRoundRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{Q_UNUSED(option);Q_UNUSED(widget);QRectF rc = boundingRect();painter->setPen(pen());painter->setBrush(brush());painter->drawRoundedRect(rc,m_xRadius,m_yRadius);updatehandles();
}//多边形
GraphicsPolygonItem::GraphicsPolygonItem(QGraphicsItem *parent): GraphicsItem(parent)
{m_points.clear();setPen(QPen(Qt::black));setBrush(QBrush(Qt::red));
}QRectF GraphicsPolygonItem::boundingRect() const
{return shape().controlPointRect();
}QPainterPath GraphicsPolygonItem::shape() const
{QPainterPath path;path.addPolygon(m_points);path.closeSubpath();return qt_graphicsItem_shapeFromPath(path,pen());
}void GraphicsPolygonItem::addPoint(const QPoint &point)
{QPoint pt = QPoint(mapFromScene(point).toPoint().x() ,mapFromScene(point).toPoint().y());m_points.append(pt);Direction dir = static_cast<Direction>(m_points.size()+None) ;SizeHandleRect *shr = new SizeHandleRect(this,dir,true);shr->setState(SelectionHandleState::SelectionHandleActive);m_handles.push_back(shr);updatehandles();
}void GraphicsPolygonItem::endPoint(const QPoint &point)
{Q_UNUSED(point);int nPoints = m_points.count();if(nPoints>3){QVector<QGraphicsRectItem *>::iterator it = m_handles.end() - 1;delete *it;m_handles.erase(it);m_points.remove(nPoints - 1);m_handles.resize(m_handles.size());}m_initialPoints = m_points;
}void GraphicsPolygonItem::resizeTo(int dir, const QPoint &point)
{QPoint pt = mapFromScene(point).toPoint();if(dir <= None) return;m_points[dir - None -1] = pt;prepareGeometryChange();m_localRect = m_points.boundingRect();m_initialPoints = m_points;updatehandles();
}void GraphicsPolygonItem::updateCoordinate()
{GraphicsItem::updateCoordinate();QPoint pt1,pt2,delta;QPolygonF pts = mapToScene(m_points);if (parentItem()==NULL){pt1 = mapToScene(transformOriginPoint()).toPoint();pt2 = mapToScene(boundingRect().center()).toPoint();delta = pt1 - pt2;for (int i = 0; i < pts.count() ; ++i )pts[i]+=delta;prepareGeometryChange();m_points = mapFromScene(pts).toPolygon();m_localRect = m_points.boundingRect();setTransform(transform().translate(delta.x(),delta.y()));moveBy(-delta.x(),-delta.y());setTransform(transform().translate(-delta.x(),-delta.y()));updatehandles();}m_initialPoints = m_points;
}void GraphicsPolygonItem::stretch(int handle, double sx, double sy, const QPoint &origin)
{QTransform trans;switch (handle) {case Top:case Bottom:sx = 1;break;case Left:case Right:sy = 1;break;default:break;}//沿着x轴移动坐标系dx,沿着y轴移动坐标系dy,并返回一个矩阵的引用。trans.translate(origin.x(),origin.y());trans.scale(sx,sy);trans.translate(-origin.x(),-origin.y());prepareGeometryChange();m_points = trans.map(m_initialPoints);m_localRect = m_points.boundingRect();updatehandles();
}void GraphicsPolygonItem::setFlip(QTransform transForm, Qt::Axis axis)
{Q_UNUSED(axis);m_points = transForm.map(m_points);updatehandles();updateCoordinate();
}void GraphicsPolygonItem::updatehandles()
{GraphicsItem::updatehandles();for(int i = 0;i<m_points.size();i++){dynamic_cast<SizeHandleRect*>( m_handles[Center + i] )->move(m_points[i].x(),m_points[i].y());}
}void GraphicsPolygonItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{Q_UNUSED(option);Q_UNUSED(widget);painter->setBrush(brush());painter->setPen(pen());painter->drawPolygon(m_points);
}//直线
GraphicsLineItem::GraphicsLineItem(QGraphicsItem *parent):GraphicsPolygonItem(parent)
{m_handles.clear();m_property = m_property &~ PROPERTY_BACKGROUNDCOLOR;m_property = m_property | PROPERTY_LINEEND;
}GraphicsLineItem::GraphicsLineItem(QPoint startPoint, QPoint endPoint, QGraphicsItem *parent):GraphicsPolygonItem(parent)
{m_handles.clear();addPoint(mapToScene(startPoint).toPoint());addPoint(mapToScene(endPoint).toPoint());m_property = m_property &~ PROPERTY_BACKGROUNDCOLOR;m_property = m_property | PROPERTY_LINEEND;
}QPainterPath GraphicsLineItem::shape() const
{QPainterPath path;path.addPolygon(m_points);path.closeSubpath();return qt_graphicsItem_shapeFromPath(path,pen());
}void GraphicsLineItem::addPoint(const QPoint &point)
{m_points.push_back(mapFromScene(point).toPoint());Direction dir = static_cast<Direction>(m_points.size()+None);SizeHandleRect *rect = new SizeHandleRect(this,dir,true);rect->setState(SelectionHandleActive);m_handles.push_back(rect);
}void GraphicsLineItem::endPoint(const QPoint &point)
{Q_UNUSED(point);m_initialPoints = m_points;updatehandles();
}void GraphicsLineItem::updateCoordinate()
{GraphicsItem::updateCoordinate();QPoint pt1,pt2,delta;QPolygon pts = mapToScene(m_points).toPolygon();if (parentItem() == nullptr){pt1 = mapToScene(transformOriginPoint()).toPoint();pt2 = mapToScene(boundingRect().center()).toPoint();delta = pt1 - pt2;for(int i=0;i<pts.count();++i)pts[i] += delta;prepareGeometryChange();m_points = mapFromScene(pts).toPolygon();m_localRect = m_points.boundingRect();setTransform(transform().translate(delta.x(),delta.y()));moveBy(-delta.x(),-delta.y());setTransform(transform().translate(-delta.x(),-delta.y()));updatehandles();}m_initialPoints = m_points;
}void GraphicsLineItem::updatehandles()
{for(int i = 0;i<m_handles.size();i++){m_handles.at(i)->setPos(m_points[i]);}
}void GraphicsLineItem::setProperty(ItemProperty property)
{GraphicsItem::setProperty(property);m_nleftIndex = property.LineEnd.section(',',0,0).toUInt();m_nrightIndex = property.LineEnd.section(',',1,1).toUInt();
}void GraphicsLineItem::getProperty(ItemProperty &property)
{GraphicsItem::getProperty(property);property.LineEnd = QString("%1,%2").arg(m_nleftIndex).arg(m_nrightIndex);
}void GraphicsLineItem::painterLineEnd(QPainter *painter, QPoint LeftPoint, QPoint RightPoint)
{static const double Pi = 3.14159265358979323846264338327950288419717;static double TwoPi = 2.0 * Pi;QLineF line(LeftPoint,RightPoint);if (qFuzzyCompare(line.length(), qreal(0.)))//qFuzzyCompare比较两个浮点型的大小,如果相等,返回truereturn;painter->setPen(pen());painter->drawLine(line);painter->setPen(QPen(pen().color(), pen().width()));//, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoinqreal arrowSize = 10;double angle = ::acos(line.dx() / line.length());if (line.dy() >= 0)angle = TwoPi - angle;QPoint leftPoint1 = LeftPoint - QPoint(sin(angle - Pi / 3) * arrowSize,cos(angle - Pi / 3) * arrowSize);QPoint leftPoint2 = LeftPoint - QPoint(sin(angle - Pi + Pi / 3) * arrowSize,cos(angle - Pi + Pi / 3) * arrowSize);QPoint rightPoint1 = RightPoint + QPoint(sin(angle - Pi / 3) * arrowSize,cos(angle - Pi / 3) * arrowSize);QPoint rightPoint2 = RightPoint + QPoint(sin(angle - Pi + Pi / 3) * arrowSize,cos(angle - Pi + Pi / 3) * arrowSize);if(m_nleftIndex == TYPE_HOLLOW_END){painter->drawLine(QLineF(leftPoint1,LeftPoint));painter->drawLine(QLineF(leftPoint2,LeftPoint));}else if(m_nleftIndex == TYPE_SOLID_LEFT_END){QPolygonF points;points.append(leftPoint1);points.append(leftPoint2);points.append(LeftPoint);painter->setBrush(Qt::black);painter->drawPolygon(points);}else if(m_nleftIndex == TYPE_SOLID_RIGHT_END){QPoint centralPoint = (leftPoint1 + leftPoint2)/2;QPoint destArrowP1 = centralPoint + QPoint(sin(angle - Pi / 3) * arrowSize,cos(angle - Pi / 3) * arrowSize);QPoint destArrowP2 = centralPoint + QPoint(sin(angle - Pi + Pi / 3) * arrowSize,cos(angle - Pi + Pi / 3) * arrowSize);QPolygonF points;points.append(destArrowP1);points.append(destArrowP2);points.append(centralPoint);painter->setBrush(Qt::black);painter->drawPolygon(points);}else if(m_nleftIndex == TYPE_LINE_END){QPoint centralPoint = (leftPoint1 + leftPoint2)/2;QPoint destArrowP1 = centralPoint + QPoint(sin(angle - Pi / 3) * arrowSize,cos(angle - Pi / 3) * arrowSize);QPoint destArrowP2 = centralPoint + QPoint(sin(angle - Pi + Pi / 3) * arrowSize,cos(angle - Pi + Pi / 3) * arrowSize);painter->drawLine(destArrowP1,destArrowP2);}if(m_nrightIndex == TYPE_HOLLOW_END){painter->drawLine(QLineF(rightPoint1,RightPoint));painter->drawLine(QLineF(rightPoint2,RightPoint));}else if(m_nrightIndex == TYPE_SOLID_LEFT_END){QPolygonF points;points.append(rightPoint1);points.append(rightPoint2);points.append(RightPoint);painter->setBrush(Qt::black);painter->drawPolygon(points);}else if(m_nrightIndex == TYPE_SOLID_RIGHT_END){QPoint centralPoint = (rightPoint1 + rightPoint2)/2;QPoint destArrowP5 = centralPoint - QPoint(sin(angle - Pi / 3) * arrowSize,cos(angle - Pi / 3) * arrowSize);QPoint destArrowP6 = centralPoint - QPoint(sin(angle - Pi + Pi / 3) * arrowSize,cos(angle - Pi + Pi / 3) * arrowSize);QPolygonF points;points.append(destArrowP5);points.append(destArrowP6);points.append(centralPoint);painter->setBrush(Qt::black);painter->drawPolygon(points);}else if(m_nrightIndex == TYPE_LINE_END){QPoint centralPoint = (rightPoint1 + rightPoint2)/2;QPoint destArrowP5 = centralPoint - QPoint(sin(angle - Pi / 3) * arrowSize,cos(angle - Pi / 3) * arrowSize);QPoint destArrowP6 = centralPoint - QPoint(sin(angle - Pi + Pi / 3) * arrowSize,cos(angle - Pi + Pi / 3) * arrowSize);painter->drawLine(destArrowP5,destArrowP6);}
}void GraphicsLineItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{Q_UNUSED(option);Q_UNUSED(widget);if(m_points.size() > 1)painterLineEnd(painter,m_points[0],m_points[1]);
}//折线
GraphicsPolylineItem::GraphicsPolylineItem(QGraphicsItem *parent): GraphicsPolygonItem(parent)
{m_property = m_property &~ PROPERTY_BACKGROUNDCOLOR;
}QPainterPath GraphicsPolylineItem::shape() const
{QPainterPath path;path.addPolygon(m_points);return qt_graphicsItem_shapeFromPath(path,pen());
}void GraphicsPolylineItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{Q_UNUSED(option);Q_UNUSED(widget);painter->setPen(pen());painter->drawPolyline(m_points);
}//贝塞尔曲线
GraphicsBezierItem::GraphicsBezierItem(QGraphicsItem *parent): GraphicsPolygonItem(parent)
{m_property = m_property &~ PROPERTY_BACKGROUNDCOLOR;
}QPainterPath GraphicsBezierItem::shape() const
{QPainterPath path;path.addPolygon(m_points);return qt_graphicsItem_shapeFromPath(path,pen());
}void GraphicsBezierItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{Q_UNUSED(option);Q_UNUSED(widget);QPainterPath path;path.moveTo(m_points.at(0));int i = 1;while(i+2 < m_points.size()){path.cubicTo(m_points[i],m_points[i+1],m_points[i+2]);i += 3;}while(i<m_points.size()){path.lineTo(m_points[i]);i += 1;}painter->drawPath(path);
}void getPropertyName(QStringList &list, long long propertyValue)
{if(propertyValue & PROPERTY_BACKGROUNDCOLOR){list << "背景颜色";}if(propertyValue & PROPERTY_POSITIONX){list << "位置X";}if(propertyValue & PROPERTY_POSITIONY){list << "位置Y";}if(propertyValue & PROPERTY_WIDTH){list << "长度";}if(propertyValue & PROPERTY_HEIGHT){list << "宽度";}if(propertyValue & PROPERTY_LINECOLOR){list << "线条颜色";}if(propertyValue & PROPERTY_LINEWIDTH){list << "线宽";}if(propertyValue & PROPERTY_LINETYPE){list << "线型";}if(propertyValue & PROPERTY_RADIUSX){list << "角半径X";}if(propertyValue & PROPERTY_RADIUSY){list << "角半径Y";}if(propertyValue & PROPERTY_ROTATION){list << "旋转角度";}if(propertyValue & PROPERTY_LINEEND){list << "线端";}
}

三、运行结果

http://www.xdnf.cn/news/694063.html

相关文章:

  • Golang分布式系统开发实践指南
  • GO语言进阶:掌握进程OS操作与高效编码数据转换
  • 命象架构法 02|你的系统有“用神”吗?
  • [Python] 如何使用 Python 调用 Dify 工作流服务实现自动化翻译
  • Java常用加密方式
  • 聊一聊如何使用自动化测试来提高接口测试效率的?
  • PowerBI企业运营分析—绩效考核分析
  • 如何使用DeepSpeed来训练大模型
  • CPU特权级别:硬件与软件协同构建系统安全的基石
  • UDP组播套接字与URI/URL/URN技术详解
  • WHAT - useWebSocket 推荐
  • 深入理解设计模式之职责链模式
  • Python包管理器 uv替代conda?
  • 基于bp神经网络的adp算法
  • Django 中的路由系统
  • Elasticsearch父子关系解析
  • SpringBoot3.4.5 开启虚拟线程(JDK21)
  • WPF的基础设施:XAML基础语法
  • ISOLAR软件生成报错处理(三)
  • PR2020+MS1824+MS7210+MS2130 1080P@60Hz USB3.0采集
  • 用户关注表的设计
  • 【深度学习-pytorch篇】5. 卷积神经网络与LLaMA分类模型
  • 钩子函数的作用(register_hook)
  • 基于c++11重构的muduo核心库项目梳理
  • 动态规划-LCR 091.粉刷房子-力扣(LeetCode)
  • xcode 编译运行错误 Sandbox: rsync(29343) deny(1) file-write-create
  • pycharm生成图片
  • 【设计模式】简单工厂模式,工厂模式,抽象工厂模式,单例,代理,go案例区分总结
  • 自动化测试基础知识详解(全)
  • 如何通过知识共享构建企业创新文化