Qt (高仿Visio)流程图组件开发(三) 图元基类如何定义,流程图多种图元类型实现
文章目錄
- 本系列目錄
- 前言
- 一、圖元基類的定義
- 1、圖元信息基類結(jié)構(gòu)體
- 2、圖元位置
- 3、父子對(duì)象關(guān)系
- 二、自定義圖元實(shí)現(xiàn)
- 1、自定義圖元基類(FlowchartGraphicsItem)與Qt原生圖元基類(QGraphicsRectItem)相互轉(zhuǎn)化關(guān)系
- 2、流程圖元、判斷圖元
- 3、自循環(huán)圖元
- 4、線圖元
- 總結(jié)
本系列目錄
Qt (高仿Visio)流程圖組件開發(fā)(一) 效果展示及基本開發(fā)框架構(gòu)思
Qt (高仿Visio)流程圖組件開發(fā)(二) 基本圖元繪制 圖元間連線繪制
Qt (高仿Visio)流程圖組件開發(fā)(三) 圖元基類如何定義,流程圖多種圖元類型實(shí)現(xiàn)
Qt (高仿Visio)流程圖組件開發(fā)(四) 流程圖 圖元對(duì)齊 磁吸線功能
Qt (高仿Visio)流程圖組件開發(fā)(五) 流程圖 雙擊編輯圖元內(nèi)容實(shí)現(xiàn)
Qt (高仿Visio)流程圖組件開發(fā)(六) 流程圖 線圖元 如何繪制曲線 連接線移除視口后無(wú)法顯示
Qt (高仿Visio)流程圖組件開發(fā)(七) 流程圖 簡(jiǎn)單操作界面搭建
Qt (高仿Visio)流程圖組件開發(fā)(八) 流程圖 鼠標(biāo)拖動(dòng)圖元到場(chǎng)景(QGraphicsScene)創(chuàng)建
Qt (高仿Visio)流程圖組件開發(fā)(九) 流程圖 代碼展示
前言
??本文主要講解一些基本流程圖圖元的實(shí)現(xiàn),例如:流程圖元、自循環(huán)圖元、判斷圖元、線圖元,這里只實(shí)現(xiàn)這四種,其他圖元類型的實(shí)現(xiàn)大同小異。同時(shí)也會(huì)講解如何從這些圖元中抽離出通用部分,定義圖元基類。只是經(jīng)驗(yàn)分享,描述內(nèi)容并不絕對(duì),如有誤差歡迎指正。
一、圖元基類的定義
1、圖元信息基類結(jié)構(gòu)體
??首先,所有圖元都具有一些信息(內(nèi)容、id、提示信息等等),抽離出通用的部分可以聲明在一個(gè)結(jié)構(gòu)體基類中,并維護(hù)在圖元基類中。如下為基類結(jié)構(gòu)體:
enum class ItemType {Null = 0, // 空Nomal, // 代表全局常態(tài)Link, // 連接線Rect, // 流程Condition, // 判定Circulation, // 自循環(huán) };struct FlowchartItemType {ItemType type = ItemType::Null; };enum class FlowchartCursor {ArrowCursor = 0,DrawLinkCursor,SizeAllCurSor,OpenHandCursor,ClosedHandCursor, };// 圖元樣式信息 struct FlowchartStyleBase {QPen pen_; // 基本畫筆樣式--背景相關(guān)QBrush brush_; // 基本畫刷樣式--背景相關(guān)QPen text_pen_; // 文本畫筆樣式QFont font_; // 字體樣式FlowchartStyleBase(){pen_ = QPen();pen_.setColor(QColor(65, 113, 156));pen_.setWidth(1);brush_ = QBrush(QColor(89, 152, 209));text_pen_ = QPen();;text_pen_.setColor(QColor(254, 255, 255));text_pen_.setWidth(1);font_ = QFont("Microsoft YaHei", 12, 2);} };// 圖元數(shù)據(jù)信息 struct FlowchartContentBase {QString id_; // 圖元idQString content_; // 圖元內(nèi)容QString tooltip_; // 圖元提示信息FlowchartContentBase(){id_ = QUuid::createUuid().toString();content_ = "Text";tooltip_ = "Tooltip";} };// 圖元父子結(jié)構(gòu)關(guān)系信息 struct FlowchartStructuralData {FlowchartStructuralData(){}QVector<QString> father_ids_; // 父節(jié)點(diǎn)id集合QVector<QString> children_ids_; // 子節(jié)點(diǎn)id集合 };// 圖元結(jié)構(gòu)體基類 struct FlowchartInforBase {double position_x_, position_y_, width_, height_;FlowchartStyleBase item_style_;FlowchartContentBase item_content_;FlowchartItemType item_type_;FlowchartStructuralData item_structural_;FlowchartInforBase(){position_x_ = 0.0;position_y_ = 0.0;width_ = 160.0;height_ = 40.0;item_style_ = FlowchartStyleBase();item_content_ = FlowchartContentBase();item_structural_ = FlowchartStructuralData();};FlowchartInforBase(double _x, double _y, double _width = 160.0, double _height = 40.0){position_x_ = _x;position_y_ = _y;width_ = _width;height_ = _height;item_style_ = FlowchartStyleBase();item_content_ = FlowchartContentBase();item_structural_ = FlowchartStructuralData();}; }; typedef std::vector<FlowchartInforBase*> FlowchartInforBases;2、圖元位置
??所有的圖元都需要獲取其在場(chǎng)景上的位置,用來創(chuàng)建連線、判斷彈出框位置等等。
virtual QPointF GetCenterPoint(){ return center_point_; };virtual QPointF GetLeftPoint(){ return left_point_; };virtual QPointF GetRightPoint(){ return right_point_; };virtual QPointF GetTopPoint(){ return top_point_; };virtual QPointF GetBottomPoint(){ return bottom_point_; };3、父子對(duì)象關(guān)系
??基類中還應(yīng)該存有父子對(duì)象,相關(guān)連線對(duì)象,提供添加父子對(duì)象節(jié)點(diǎn)、清空依賴關(guān)系,獲取父子對(duì)象集合等接口,減少實(shí)現(xiàn)一個(gè)自定義圖元對(duì)象時(shí)需要實(shí)現(xiàn)的內(nèi)容。接口定義如下:
// 獲取圖元idQString GetItemId();// 獲取圖元類型ItemType GetItemType();// 添加子節(jié)點(diǎn)void AddChild(FlowchartGraphicsItem* _item, FlowcharGraphicsLink* _link_item);// 刪除子節(jié)點(diǎn)及其連線void DelChild(QString _id);// 添加父節(jié)點(diǎn)void AddFather(FlowchartGraphicsItem* _item, FlowcharGraphicsLink* _link_item);// 刪除父節(jié)點(diǎn)連線及其連線void DelFather(QString _id);// 清空?qǐng)D元依賴關(guān)系void ItemClear();// 獲取子對(duì)象集合QMap<QString, FlowchartGraphicsItem*> GetChildrenItems();// 獲取父對(duì)象集合QMap<QString, FlowchartGraphicsItem*> GetFatherItems();二、自定義圖元實(shí)現(xiàn)
??有了圖元基類后,所有的自定義圖元只需要繼承圖元基類,實(shí)現(xiàn)虛函數(shù)接口,繪制需要的圖形樣式即可。
1、自定義圖元基類(FlowchartGraphicsItem)與Qt原生圖元基類(QGraphicsRectItem)相互轉(zhuǎn)化關(guān)系
??因?yàn)樽远x的圖元基類為c++類,所以在調(diào)用Qt相關(guān)接口時(shí),需要轉(zhuǎn)化為原生基類來使用,轉(zhuǎn)化關(guān)系如下:
// 對(duì)象轉(zhuǎn)化 qt原生對(duì)象->圖元基類對(duì)象FlowchartGraphicsItem* QGraphToFlow(QGraphicsItem* _item);// 對(duì)象轉(zhuǎn)化 圖元基類對(duì)象->qt原生對(duì)象QGraphicsItem* FlowToQGraph(FlowchartGraphicsItem* _item);// 對(duì)象轉(zhuǎn)化 qt原生對(duì)象->圖元基類對(duì)象FlowchartGraphicsItem* FlowchartScene::QGraphToFlow(QGraphicsItem* _item){if (_item == nullptr)return nullptr;FlowchartGraphicsRectItem* item = (FlowchartGraphicsRectItem*)_item;return (FlowchartGraphicsItem*)item;}// 對(duì)象轉(zhuǎn)化 圖元基類對(duì)象->qt原生對(duì)象QGraphicsItem* FlowchartScene::FlowToQGraph(FlowchartGraphicsItem* _item){if (_item == nullptr)return nullptr;FlowchartGraphicsRectItem* item = (FlowchartGraphicsRectItem*)_item;return (QGraphicsItem*)item;}2、流程圖元、判斷圖元
??流程圖元與判斷圖元示意圖如下:
??流程圖元與判斷圖元包括之后的自定義流程圖實(shí)現(xiàn)都大同小異,現(xiàn)已流程圖元為例進(jìn)行詳細(xì)講解。講解內(nèi)容大都集中在代碼注釋中。流程圖元類(FlowchartGraphicsRectItem)
??首先,需要?jiǎng)?chuàng)建一個(gè)屬于該圖元的結(jié)構(gòu)體(FlowchartItemRectInfo),繼承之前定義的基類結(jié)構(gòu)體(FlowchartInforBase),如果有特殊的需求可以添加在結(jié)構(gòu)體聲明中,這樣是為了保證在開發(fā)自定義圖元類過程中需要保存一些特殊的數(shù)據(jù)。
??其次,流程圖元類(FlowchartGraphicsRectItem)需要繼承QObject、QGraphicsRectItem、FlowchartGraphicsItem,QObject類不必多說,繼承QGraphicsRectItem是因?yàn)橐獙?shí)現(xiàn)的流程圖元為一矩形圖元,所以直接繼承現(xiàn)有的矩形圖元類即可,包括之后的自定義圖元也是根據(jù)圖元需求來繼承適合的類,FlowchartGraphicsItem類為我們的自定義結(jié)構(gòu)體基類,類的父子關(guān)系、信息等都由該基類維護(hù)。
// 流程矩形 class FlowchartGraphicsRectItem: public QObject, public QGraphicsRectItem, public FlowchartGraphicsItem {Q_OBJECTpublic:explicit FlowchartGraphicsRectItem(FlowchartItemRectInfo* _infor, QObject *parent = nullptr);~FlowchartGraphicsRectItem();// 修改文本內(nèi)容virtual void SetText(QString _content, QString _tooltip = "") override;// 獲取界面信息virtual FlowchartInforBase* GetItemInformation() override;/****************獲取圖元點(diǎn)--中心、左、右、上、下*******************/virtual QPointF GetCenterPoint() override { return mapToScene(center_point_); };virtual QPointF GetLeftPoint() override{ return mapToScene(left_point_); };virtual QPointF GetRightPoint() override{ return mapToScene(right_point_); };virtual QPointF GetTopPoint() override{ return mapToScene(top_point_); };virtual QPointF GetBottomPoint() override{ return mapToScene(bottom_point_); };private:// 繪制文本內(nèi)容void DrawItemText(QPainter *_painter);public:virtual QRectF boundingRect() const;virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR);private:// 流程矩形結(jié)構(gòu)體方便取用FlowchartItemRectInfo* item_infor_;};FlowchartGraphicsRectItem::FlowchartGraphicsRectItem(FlowchartItemRectInfo* _infor, QObject *parent): QObject(parent), FlowchartGraphicsItem(_infor, ItemType::Rect) {// ! [1] 初始化圖元位置大小item_infor_ = _infor;setRect({ QPointF(-item_infor_->width_ / 2, -item_infor_->height_ / 2), QSizeF(item_infor_->width_, item_infor_->height_) });setPos(0,0);center_point_ = pos();left_point_ = pos() + QPointF(-item_infor_->width_ / 2 - 3, 0);right_point_ = pos() + QPointF(item_infor_->width_ / 2 + 3, 0);top_point_ = pos() + QPointF(0, -item_infor_->height_ / 2 - 3);bottom_point_ = pos() + QPointF(0, item_infor_->height_ / 2 + 3);setPos(item_infor_->position_x_, item_infor_->position_y_);// ! [2] 圖元相關(guān)設(shè)置setFlag(QGraphicsItem::ItemIsMovable, true);setFlag(QGraphicsItem::ItemIsSelectable, true);setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);// 設(shè)置圖元層級(jí)setZValue(2);// ! [3] 圖元信息設(shè)置this->setToolTip(item_infor_->item_content_.tooltip_);}FlowchartGraphicsRectItem::~FlowchartGraphicsRectItem() { }void FlowchartGraphicsRectItem::DrawItemText(QPainter *_painter) {_painter->save();/*[] 計(jì)算字體寬度 根據(jù)item大小*/_painter->setFont(item_infor_->item_style_.font_);QFontMetrics font_metrics = _painter->fontMetrics();QRectF rect = this->rect();QRectF resize_rect = rect;QString text = item_infor_->item_content_.content_;QString tremporart_text;resize_rect.setHeight(rect.height());resize_rect.setWidth(rect.width());tremporart_text = font_metrics.elidedText(text, Qt::ElideRight, resize_rect.width());_painter->setPen(item_infor_->item_style_.text_pen_);tremporart_text.replace(text, "");if (!tremporart_text.isEmpty())resize_rect.setWidth(rect.width());resize_rect.moveCenter(rect.center());_painter->drawText(resize_rect, Qt::AlignCenter | Qt::TextWrapAnywhere, text);_painter->restore(); }void FlowchartGraphicsRectItem::SetText(QString _content, QString _tooltip) {item_infor_->item_content_.content_ = _content;if (_tooltip.compare("") == 0)return;item_infor_->item_content_.tooltip_ = _tooltip;this->setToolTip(item_infor_->item_content_.tooltip_);this->update(); }FlowchartInforBase* FlowchartGraphicsRectItem::GetItemInformation() {// 位置信息更新item_infor_->position_x_ = this->scenePos().x();item_infor_->position_y_ = this->scenePos().y();item_infor_->width_ = this->boundingRect().width();item_infor_->height_ = this->boundingRect().height();// 父子關(guān)系更新FlowchartStructuralData structural_data;QMap<QString, FlowchartGraphicsItem*> father_items = GetFatherItems();for (QMap<QString, FlowchartGraphicsItem*>::iterator iter = father_items.begin(); iter != father_items.end(); iter++){structural_data.father_ids_.push_back(iter.key());}QMap<QString, FlowchartGraphicsItem*> children_items = GetChildrenItems();for (QMap<QString, FlowchartGraphicsItem*>::iterator iter = children_items.begin(); iter != children_items.end(); iter++) {structural_data.children_ids_.push_back(iter.key());}item_infor_->item_structural_ = structural_data;item_base_info_ = (FlowchartInforBase*)item_infor_;return item_base_info_; }QRectF FlowchartGraphicsRectItem::boundingRect() const {QRectF rect = QGraphicsRectItem::boundingRect().adjusted(-3, -3, 3, 3);return rect; }void FlowchartGraphicsRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget /*= Q_NULLPTR*/) {painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);painter->save();painter->setPen(item_infor_->item_style_.pen_);painter->setBrush(item_infor_->item_style_.brush_);painter->drawRect(this->boundingRect());painter->restore();/*[] 繪制選中外框*/if (this->isSelected()) {/*[1]: 繪制外圍的矩形框 */QPen selected_pen(QColor(147, 147, 147));selected_pen.setWidth(0.5);selected_pen.setStyle(Qt::DashLine);painter->setPen(selected_pen);painter->setBrush(Qt::NoBrush);painter->drawRect(this->boundingRect());const auto left_center_rect = QRectF((left_point_ - QPointF(2, 2)), QSizeF(5, 5));const auto right_center_rect = QRectF((right_point_ - QPointF(3, 3)), QSizeF(5, 5));const auto top_center_rect = QRectF((top_point_ - QPointF(2, 2)), QSizeF(5, 5));const auto bottom_center_rect = QRectF((bottom_point_ - QPointF(3, 3)), QSizeF(5, 5));/*[2]: 繪制四個(gè)方向的連接點(diǎn) */painter->setPen(QColor(147, 147, 147));painter->setBrush(QColor(255, 255, 255));painter->drawRect(left_center_rect);painter->drawRect(right_center_rect);painter->drawRect(top_center_rect);painter->drawRect(bottom_center_rect);}DrawItemText(painter); }??最后,代碼完整實(shí)現(xiàn)如上,針對(duì)其中幾個(gè)要點(diǎn)進(jìn)行解釋。
3、自循環(huán)圖元
??這里單獨(dú)把自循環(huán)列出是因?yàn)槠涫且粋€(gè)較為典型的特殊圖元,自循環(huán)圖元自帶一條指向自己首尾的曲線,這里的實(shí)現(xiàn)基本與上文相同,只是多出了一個(gè)設(shè)置自循環(huán)連線的接口,多維護(hù)了一個(gè)連線對(duì)象。
// 添加自循環(huán)連線void SetCirculationLink(FlowcharGraphicsLink* _item); private:FlowcharGraphicsLink *graphics_link_;??玩家想實(shí)現(xiàn)一些特殊的圖元也可以通過這種方式擴(kuò)展。
4、線圖元
??也是一個(gè)特殊圖元,只不過涉及箭頭繪制、曲線的計(jì)算、特殊接口定義等等,這里將其單獨(dú)寫出,之后會(huì)有對(duì)該類的詳細(xì)講解
總結(jié)
本文主要講解圖元基類的定義,及一些簡(jiǎn)單自定義圖元如何去實(shí)現(xiàn)。
本文只是經(jīng)驗(yàn)分享,描述內(nèi)容并不絕對(duì),如有誤差歡迎指正。
如果此文幫助到你( ?? ω ?? )?,動(dòng)動(dòng)小手點(diǎn)個(gè)贊可好O(∩_∩)O。
原創(chuàng)文章,轉(zhuǎn)載請(qǐng)標(biāo)明本文出處。總結(jié)
以上是生活随笔為你收集整理的Qt (高仿Visio)流程图组件开发(三) 图元基类如何定义,流程图多种图元类型实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SLAM学习笔记(二十)LIO-SAM流
- 下一篇: 使用HP LaserJet Pro MF