Browse Source

评估方案规划

chengxr 1 year ago
parent
commit
af39f28e59

+ 4 - 0
QFD/CCanvas/CCanvas.pri

@@ -8,6 +8,8 @@ HEADERS += \
     $$PWD/CNodeItem.h \
     $$PWD/CPathItem.h \
     $$PWD/CRectItem.h \
+    $$PWD/CSchemeItem.h \
+    $$PWD/CSchemeView.h \
     $$PWD/CTextItem.h
 
 SOURCES += \
@@ -18,5 +20,7 @@ SOURCES += \
     $$PWD/CNodeItem.cpp \
     $$PWD/CPathItem.cpp \
     $$PWD/CRectItem.cpp \
+    $$PWD/CSchemeItem.cpp \
+    $$PWD/CSchemeView.cpp \
     $$PWD/CTextItem.cpp
 

+ 3 - 0
QFD/CCanvas/CMindView.cpp

@@ -21,6 +21,9 @@ CMindView::CMindView(QWidget *parent) : QGraphicsView(new QGraphicsScene(), pare
     m_group->setHandlesChildEvents(false);
 
     scene()->addItem(m_group);
+
+    setStyleSheet("QGraphicsView {border: 1px solid rgba(0, 0, 0, 0.073);background: rgb(244, 244, "
+                  "255);}");
 }
 
 CMind *CMindView::mind() const

+ 3 - 3
QFD/CCanvas/CNodeItem.h

@@ -95,9 +95,9 @@ public slots:
 private:
     CNodeData m_data;
 
-    CRectItem *m_rectItem;
-    CTextItem *m_textItem;
-    CLineItem *m_lineItem;
+    CRectItem *m_rectItem = nullptr;
+    CTextItem *m_textItem = nullptr;
+    CLineItem *m_lineItem = nullptr;
 
     QPointF m_pos;
 

+ 11 - 5
QFD/CCanvas/CRectItem.cpp

@@ -1,5 +1,7 @@
 #include "CRectItem.h"
 
+#include <Widgets/Menu.h>
+
 #include <QGraphicsSceneContextMenuEvent>
 #include <QMenu>
 
@@ -13,10 +15,14 @@ CRectItem::CRectItem(const QRectF &rect, QGraphicsItem *parent) : CPathItem(pare
 
     updatePath();
 
-    m_menu    = new QMenu();
-    m_subNode = m_menu->addAction("添加子节点");
-    m_select  = m_menu->addAction("选中");
-    m_remove  = m_menu->addAction("删除");
+    m_menu    = new RoundMenu("menu");
+    m_subNode = new QAction("添加子节点");
+    m_select  = new QAction("选中");
+    m_remove  = new QAction("删除");
+
+    m_menu->addAction(m_subNode);
+    m_menu->addAction(m_select);
+    m_menu->addAction(m_remove);
 }
 
 QRectF CRectItem::rect() const
@@ -62,7 +68,7 @@ void CRectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
 {
     const QString txt = highlighted() ? "取消选中" : "选中";
     m_select->setText(txt);
-    m_menu->exec(event->screenPos());
+    m_menu->exec(event->screenPos() + QPoint(-40, -20));
 }
 
 void CRectItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { }

+ 3 - 1
QFD/CCanvas/CRectItem.h

@@ -3,6 +3,8 @@
 
 #include "CPathItem.h"
 
+class RoundMenu;
+
 class QMenu;
 class QAction;
 
@@ -43,7 +45,7 @@ private:
 
     qreal m_cornerRadius = 5;
 
-    QMenu *m_menu      = nullptr;
+    RoundMenu *m_menu  = nullptr;
     QAction *m_select  = nullptr;
     QAction *m_subNode = nullptr;
     QAction *m_remove  = nullptr;

+ 90 - 0
QFD/CCanvas/CSchemeItem.cpp

@@ -0,0 +1,90 @@
+#include "CSchemeItem.h"
+
+#include "CRectItem.h"
+#include "CTextItem.h"
+#include "CLineItem.h"
+
+CSchemeItem::CSchemeItem(const QString text, QObject *parent) : QObject(parent)
+{
+    m_rectItem = new CRectItem();
+    m_textItem = new CTextItem(text, m_rectItem);
+    m_lineItem = new CLineItem(m_rectItem);
+
+    setMinHeight(100);
+    m_textItem->setAllowEdit(false);
+}
+
+CRectItem *CSchemeItem::rectItem() const
+{
+    return m_rectItem;
+}
+
+CTextItem *CSchemeItem::textItem() const
+{
+    return m_textItem;
+}
+
+CLineItem *CSchemeItem::lineItem() const
+{
+    return m_lineItem;
+}
+
+qreal CSchemeItem::xMargin() const
+{
+    return m_xMargin;
+}
+
+void CSchemeItem::setXMargin(qreal x)
+{
+    m_xMargin = x;
+}
+
+qreal CSchemeItem::yMargin() const
+{
+    return m_yMargin;
+}
+
+void CSchemeItem::setYMargin(qreal y)
+{
+    m_yMargin = y;
+}
+
+qreal CSchemeItem::minWidth() const
+{
+    return m_minWidth;
+}
+
+void CSchemeItem::setMinWidth(qreal w)
+{
+    m_minWidth = w;
+}
+
+qreal CSchemeItem::minHeight() const
+{
+    return m_minHeight;
+}
+
+void CSchemeItem::setMinHeight(qreal h)
+{
+    m_minHeight = h;
+}
+
+qreal CSchemeItem::textWidth() const
+{
+    return m_textItem->boundingRect().width();
+}
+
+qreal CSchemeItem::textHeight() const
+{
+    return m_textItem->boundingRect().height();
+}
+
+qreal CSchemeItem::borderWidth() const
+{
+    return std::max(textWidth() + m_xMargin * 2, m_minWidth);
+}
+
+qreal CSchemeItem::borderHeight() const
+{
+    return std::max(textHeight() + m_yMargin * 2, m_minHeight);
+}

+ 52 - 0
QFD/CCanvas/CSchemeItem.h

@@ -0,0 +1,52 @@
+#ifndef CSCHEMEITEM_H
+#define CSCHEMEITEM_H
+
+#include <QObject>
+
+class CRectItem;
+class CTextItem;
+class CLineItem;
+
+class CSchemeItem : public QObject
+{
+    Q_OBJECT
+public:
+    explicit CSchemeItem(const QString text, QObject *parent = nullptr);
+
+    CRectItem *rectItem() const;
+    CTextItem *textItem() const;
+    CLineItem *lineItem() const;
+
+    qreal xMargin() const;
+    void setXMargin(qreal x);
+
+    qreal yMargin() const;
+    void setYMargin(qreal y);
+
+    qreal minWidth() const;
+    void setMinWidth(qreal w);
+
+    qreal minHeight() const;
+    void setMinHeight(qreal h);
+
+    qreal textWidth() const;
+    qreal textHeight() const;
+
+    qreal borderWidth() const;
+    qreal borderHeight() const;
+
+signals:
+
+private:
+    CRectItem *m_rectItem = nullptr;
+    CTextItem *m_textItem = nullptr;
+    CLineItem *m_lineItem = nullptr;
+
+    qreal m_xMargin = 10;
+    qreal m_yMargin = 5;
+
+    qreal m_minWidth  = 100;
+    qreal m_minHeight = 30;
+};
+
+#endif  // CSCHEMEITEM_H

+ 85 - 0
QFD/CCanvas/CSchemeView.cpp

@@ -0,0 +1,85 @@
+#include "CSchemeView.h"
+
+#include "CSchemeItem.h"
+#include "CRectItem.h"
+#include "CLineItem.h"
+#include "CTextItem.h"
+
+#include <QGraphicsItem>
+
+#include <QDebug>
+
+CSchemeView::CSchemeView(QWidget *parent) : QGraphicsView(new QGraphicsScene(), parent)
+{
+    setRenderHints(QPainter::Antialiasing);  // 抗锯齿
+
+    m_group = new QGraphicsItemGroup();
+    m_group->setFlags(QGraphicsItem::ItemIsMovable);
+
+    scene()->addItem(m_group);
+
+    setStyleSheet("QGraphicsView {border: 1px solid rgba(0, 0, 0, 0.073);background: rgb(244, 244, "
+                  "255);}");
+}
+
+void CSchemeView::addItem(CSchemeItem *item)
+{
+    m_schemes.append(item);
+    refreshItems();
+}
+
+void CSchemeView::clear()
+{
+    qDeleteAll(m_schemes);
+    m_schemes.clear();
+    refreshItems();
+}
+
+void CSchemeView::refreshItems()
+{
+    for (QGraphicsItem *item : m_items) {
+        scene()->removeItem(item);
+    }
+    m_items.clear();
+    refreshItemsGeometry();
+    for (QGraphicsItem *item : m_items) {
+        m_group->addToGroup(item);
+    }
+    QRectF r = m_group->childrenBoundingRect();
+    setSceneRect(QRectF(QPointF(), r.size()));
+}
+
+qreal CSchemeView::maxItemHeight() const
+{
+    qreal h = 0;
+    for (CSchemeItem *item : m_schemes) {
+        h = std::max(h, item->borderHeight());
+    }
+    return h;
+}
+
+void CSchemeView::refreshItemsGeometry()
+{
+    qreal mh          = maxItemHeight();
+    int x             = 0;
+    CSchemeItem *left = nullptr;
+    for (CSchemeItem *item : m_schemes) {
+        QRect borderRect = QRect(x, (mh - item->borderHeight()) / 2, item->borderWidth(), item->borderHeight());
+        item->rectItem()->setRect(borderRect);
+
+        QPointF textPos = QPointF(borderRect.left() + (item->borderWidth() - item->textWidth()) / 2,
+                                  borderRect.top() + (item->borderHeight() - item->textHeight()) / 2);
+        item->textItem()->setPos(textPos);
+        item->rectItem()->setPos(QPoint(0, 0));
+
+        if (left != nullptr) {
+            item->lineItem()->setStartPos(left->rectItem()->centerRight());
+            item->lineItem()->setEndPos(item->rectItem()->centerLeft());
+        }
+
+        m_items.append(item->rectItem());
+
+        x += borderRect.width() + m_hNodeSpace;
+        left = item;
+    }
+}

+ 34 - 0
QFD/CCanvas/CSchemeView.h

@@ -0,0 +1,34 @@
+#ifndef CSCHEMEVIEW_H
+#define CSCHEMEVIEW_H
+
+#include <QGraphicsView>
+
+class CSchemeItem;
+
+class CSchemeView : public QGraphicsView
+{
+public:
+    CSchemeView(QWidget *parent = nullptr);
+
+    void addItem(CSchemeItem *item);
+
+    void clear();
+
+    void refreshItems();
+
+    qreal maxItemHeight() const;
+
+    void refreshItemsGeometry();
+
+private:
+    QGraphicsItemGroup *m_group = nullptr;
+
+    // 场景中显示的项目
+    QList<CSchemeItem *> m_schemes;
+
+    QList<QGraphicsItem *> m_items;
+
+    qreal m_hNodeSpace = 50;
+};
+
+#endif  // CSCHEMEVIEW_H

+ 14 - 1
QFD/CCanvas/CTextItem.cpp

@@ -16,7 +16,9 @@ CTextItem::CTextItem(const QString &text, QGraphicsItem *parent) : QGraphicsText
 void CTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
 {
     if (event->button() == Qt::LeftButton) {  //左键双击进入可编辑状态并打开焦点
-        beginEditing();
+        if (allowEdit()) {
+            beginEditing();
+        }
         QGraphicsTextItem::mouseDoubleClickEvent(event);
     }
 }
@@ -50,3 +52,14 @@ bool CTextItem::isEditing() const
 {
     return (textInteractionFlags() & Qt::TextEditorInteraction) == Qt::TextEditorInteraction;
 }
+
+bool CTextItem::allowEdit() const
+{
+    return m_allowEdit;
+}
+
+void CTextItem::setAllowEdit(bool a)
+{
+    m_allowEdit = a;
+    endEditing();
+}

+ 7 - 0
QFD/CCanvas/CTextItem.h

@@ -21,8 +21,15 @@ public:
 
     bool isEditing() const;
 
+    bool allowEdit() const;
+
+    void setAllowEdit(bool a);
+
 signals:
     void sigTextChanged();
+
+private:
+    bool m_allowEdit = true;
 };
 
 #endif  // CTEXTITEM_H

+ 129 - 0
QFD/widgets/EvalSchemeWidget.cpp

@@ -1,6 +1,135 @@
 #include "EvalSchemeWidget.h"
 
+#include <CCanvas/CSchemeView.h>
+#include <CCanvas/CSchemeItem.h>
+
+#include <Widgets/Button.h>
+#include <Widgets/Menu.h>
+
+#include <QLayout>
+#include <QMetaEnum>
+
+#include <QDebug>
+
+QString EvalSchemeWidget::nameOfScheme(Scheme s)
+{
+    switch (s) {
+    case Input:
+        return "输入";
+    case Index:
+        return "指标体系";
+    case Collect:
+        return "收集数据";
+    case Process:
+        return "处理数据";
+    case Output:
+        return "输出报告";
+    }
+}
+
+QString EvalSchemeWidget::nameOfAlgorithm(EvalSchemeWidget::Algorithm a)
+{
+    switch (a) {
+    case Alg1:
+        return "层次分析法";
+    case Alg2:
+        return "集对分析法";
+    case Alg3:
+        return "熵值法";
+    case Alg4:
+        return "物元分析法";
+    case Alg5:
+        return "灰色聚类评估法";
+    }
+}
+
 EvalSchemeWidget::EvalSchemeWidget(ProjectInfo *proj, int type, QWidget *parent) : EvalWidget(proj, type, parent)
 {
     setTitle("评估方案规划");
+
+    initWidgets();
+}
+
+void EvalSchemeWidget::initWidgets()
+{
+    m_buttonLayout = new QHBoxLayout();
+
+    // 按照方案枚举值添加按钮
+    QMetaEnum sch = QMetaEnum::fromType<Scheme>();
+    for (int i = 0; i < sch.keyCount(); i++) {
+        Scheme s        = Scheme(sch.value(i));
+        PushButton *btn = new PushButton(nameOfScheme(s), this);
+        btn->setFixedWidth(100);
+        m_buttonLayout->addWidget(btn);
+        connect(btn, &PushButton::clicked, [this, s, btn]() { slotSelectScheme(s, btn); });
+    }
+    m_buttonLayout->setSpacing(15);
+    m_buttonLayout->addStretch();
+
+    m_clear = new PushButton("清空");
+    m_buttonLayout->addWidget(m_clear);
+    connect(m_clear, &PushButton::clicked, this, &EvalSchemeWidget::slotClearScheme);
+
+    // 按照算法枚举值添加算法选项
+    m_menu        = new RoundMenu("menu", this);
+    QMetaEnum alg = QMetaEnum::fromType<Algorithm>();
+    for (int i = 0; i < alg.keyCount(); i++) {
+        Algorithm t  = Algorithm(alg.value(i));
+        QAction *act = new QAction(nameOfAlgorithm(t));
+        m_menu->addAction(act);
+        connect(act, &QAction::triggered, [this, t]() { slotSelectAlgorithm(t); });
+    }
+
+    m_schemeView = new CSchemeView(this);
+
+    m_contentLayout->addLayout(m_buttonLayout);
+    m_contentLayout->addWidget(m_schemeView);
+}
+
+void EvalSchemeWidget::refreshSchemeView()
+{
+    m_schemeView->clear();
+    QMetaEnum sch = QMetaEnum::fromType<Scheme>();
+    for (int i = 0; i < sch.keyCount(); i++) {
+        Scheme s = Scheme(sch.value(i));
+        if (s == Process) {
+            for (Algorithm a : m_algs) {
+                CSchemeItem *item = new CSchemeItem(nameOfAlgorithm(a));
+                m_schemeView->addItem(item);
+            }
+
+        } else {
+            if ((m_scheme & s) == s) {
+                CSchemeItem *item = new CSchemeItem(nameOfScheme(s));
+                m_schemeView->addItem(item);
+            }
+        }
+    }
+}
+
+void EvalSchemeWidget::slotSelectScheme(EvalSchemeWidget::Scheme sch, PushButton *btn)
+{
+    if (sch == Process) {
+        QPoint pos = btn->mapToGlobal(QPoint()) + QPoint(btn->width(), -10);
+        m_menu->exec(pos, true);
+    } else {
+        m_scheme |= sch;
+        refreshSchemeView();
+    }
+}
+
+void EvalSchemeWidget::slotSelectAlgorithm(EvalSchemeWidget::Algorithm alg)
+{
+    if (m_algs.contains(alg)) {
+        return;
+    }
+    m_algs.append(alg);
+    refreshSchemeView();
+}
+
+void EvalSchemeWidget::slotClearScheme()
+{
+    m_scheme = 0;
+    m_algs.clear();
+    refreshSchemeView();
 }

+ 57 - 0
QFD/widgets/EvalSchemeWidget.h

@@ -3,6 +3,14 @@
 
 #include "EvalWidget.h"
 
+class CSchemeView;
+
+class PushButton;
+class RoundMenu;
+
+class QHBoxLayout;
+class QAction;
+
 /**
  * @brief The EvalSchemeWidget class
  * 评估方案
@@ -11,9 +19,58 @@ class EvalSchemeWidget : public EvalWidget
 {
     Q_OBJECT
 public:
+    enum Scheme
+    {
+        Input   = 0b1,
+        Index   = 0b1 << 1,
+        Collect = 0b1 << 2,
+        Process = 0b1 << 3,
+        Output  = 0b1 << 4,
+    };
+
+    Q_ENUM(Scheme)
+
+    static QString nameOfScheme(Scheme s);
+
+    enum Algorithm
+    {
+        Alg1 = Process | 0b1 << 11,
+        Alg2 = Process | 0b1 << 12,
+        Alg3 = Process | 0b1 << 13,
+        Alg4 = Process | 0b1 << 14,
+        Alg5 = Process | 0b1 << 15,
+    };
+
+    Q_ENUM(Algorithm)
+
+    static QString nameOfAlgorithm(Algorithm a);
+
     explicit EvalSchemeWidget(ProjectInfo *proj, int type, QWidget *parent);
 
+    void initWidgets();
+
+    void refreshSchemeView();
+
 signals:
+
+private slots:
+    void slotSelectScheme(Scheme sch, PushButton *btn);
+
+    void slotSelectAlgorithm(Algorithm alg);
+
+    void slotClearScheme();
+
+private:
+    PushButton *m_clear = nullptr;
+
+    RoundMenu *m_menu = nullptr;
+
+    CSchemeView *m_schemeView = nullptr;
+
+    QHBoxLayout *m_buttonLayout = nullptr;
+
+    int m_scheme = 0;
+    QList<Algorithm> m_algs;
 };
 
 #endif  // EVALSCHEMEWIDGET_H

+ 8 - 4
QFD/widgets/IndexSystemWidget.cpp

@@ -5,6 +5,8 @@
 #include <CCanvas/CMindView.h>
 #include <CMind.h>
 
+#include <Widgets/Menu.h>
+
 #include <QLayout>
 #include <QMenu>
 #include <QContextMenuEvent>
@@ -30,17 +32,19 @@ void IndexSystemWidget::initLayout()
 
 void IndexSystemWidget::contextMenuEvent(QContextMenuEvent *event)
 {
-    QMenu *menu = new QMenu();
+    RoundMenu *menu = new RoundMenu();
 
     if (m_mindView->root() == nullptr) {
-        QAction *act3 = menu->addAction("创建根节点");
+        QAction *act3 = new QAction("创建根节点");
+        menu->addAction(act3);
         connect(act3, &QAction::triggered, this, &IndexSystemWidget::slotCreateRootNode);
     } else {
-        QAction *act2 = menu->addAction("清空");
+        QAction *act2 = new QAction("清空");
+        menu->addAction(act2);
         connect(act2, &QAction::triggered, this, &IndexSystemWidget::slotClearAllNodes);
     }
 
-    menu->exec(event->globalPos());
+    menu->exec(event->globalPos() + QPoint(-40, -20));
 
     QWidget::contextMenuEvent(event);
 }