<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Qt實戰16.構建甘特圖

      1 需求描述

      根據不同的飛機平臺,可視化展示其計劃飛行時間(段)和實際飛行時間(段),同時能夠展示飛行過程中人員的操作。

      2 設計思路

      這次我們換一種思路,站在使用者的角度去思考,如果是我,我希望這個控件具有哪些元素?再一個就是控件應該提供什么樣的接口?讓我用著更爽。

      好了,我們簡單分析下,首先控件要能展示時間(段),一般來說橫軸就是時間軸,縱軸用來顯示飛機型號。

      既然能顯示時間(段),給個起始時間和結束時間,控件能夠按照一定的步長把時間軸繪制出來。時間軸有了,飛機平臺是不是也可以一起指定,這個時候一個接口就出現了:

      void setAxisRange(const QDateTime &start, const QDateTime &end, const QStringList &platforms);
      

      兩軸內容有了,接下來就是時間條了,即一行需要有兩個時間條,一個是計劃時間、一個是實際時間,時間條也需要傳入起始時間和結束時間,同時還要知道對應的是哪個飛機平臺:

      CanttTimeBarItem *addPlanTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end);
      CanttTimeBarItem *addRealTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end);
      

      上面返回了一個CanttTimeBarItem指針,說明控件內部完成了時間條的實例化,時間條涉及到一個接口,那就是在什么時間點做了什么操作(事件),這個是需要進行標記的:

       void addEvent(const QDateTime &dateTime, EventType type);
      

      到這里,關節已經打通了,下面擼代碼。

      3 代碼實現

      沒有意外的情況下,我們依然選擇了圖形視圖框架,很簡單,只需要自定義三個類,自定義QGraphicsView、QGraphicsScene、QGraphicsRectItem。

      3.1 CanttChartScene

      場景類主要完成網格線的繪制,同時對外提供前面提到的添加時間條的兩個接口,以及時間步長設置接口,頭文件代碼如下:

      #ifndef CANTTCHARTSCENE_H
      #define CANTTCHARTSCENE_H
      
      #include <QGraphicsScene>
      #include <QDateTime>
      #include <QTime>
      #include <QHash>
      #include <QPair>
      
      class CanttTimeBarItem;
      class CanttChartScene : public QGraphicsScene
      {
          Q_OBJECT
      public:    
          explicit CanttChartScene(QObject *parent = 0);
      
          void setAxisRange(const QDateTime &start, const QDateTime &end, const QStringList &platforms);
      
          CanttTimeBarItem *addPlanTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end);
          CanttTimeBarItem *addRealTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end);
      
          void setStepTimeValue(const QTime &time);
      
      private:
          void drawGridLines();
          void drawVerticalAxis(const QStringList &platforms);
      
          int m_rowCount;
          int m_columnCount;
      
          QDateTime m_startDateTime;
          QDateTime m_endDateTime;
          QTime m_stepTimeValue;
          QStringList m_platforms;
      
          int m_firstTimeBarStartX;
          int m_firstTimeBarStartY;
          double m_perPixelHMsecs;
      
          QHash<QString, double> m_platformStartYHash;
          QHash<QString, QPair<QDateTime, QDateTime>> m_planTimeBarTemp;
          QHash<QString, QPair<QDateTime, QDateTime>> m_realTimeBarTemp;
          QMultiHash<QString, QGraphicsItem*> m_plaformTimeBarHash;
      };
      
      #endif // CANTTCHARTSCENE_H
      

      源文件中定義了一些const常量,無非就是一些網格的高度、寬度、偏移啥的,看名字應該能看懂,也可以改改試試效果:

      #include "canttchartscene.h"
      #include "definition.h"
      #include "cantttimebaritem.h"
      
      #include <QBrush>
      #include <QPen>
      #include <QGraphicsLineItem>
      #include <QGraphicsTextItem>
      #include <QDebug>
      #include <QCheckBox>
      #include <QGraphicsProxyWidget>
      #include <QCursor>
      
      const int firstHorizantalGridWidth = 100;
      const int horizontalGridWidth = 40;
      const int verticalGridHeight = 40;
      const int horizontalAxisTextHeight = 21;
      const int horizontalAxisTextOffset = 5;
      const QPoint axisStartPoint = QPoint(20, 40);
      const QPoint platformHeaderOffset = QPoint(6, 10);
      const QColor gridLineColor = QColor(48, 85, 93);
      const QColor scaleDateColor = QColor(253, 201, 115);
      const QColor scaleTimeColor = QColor(208, 216, 237);
      
      CanttChartScene::CanttChartScene(QObject *parent) : QGraphicsScene(parent),
          m_rowCount(0), m_columnCount(0), m_stepTimeValue(0, 30)
      {
          setBackgroundBrush(QBrush(QColor(43, 48, 54)));
      
          m_perPixelHMsecs =  m_stepTimeValue.msecsSinceStartOfDay() / (double)horizontalGridWidth;
      }
      
      void CanttChartScene::setAxisRange(const QDateTime &start, const QDateTime &end, const QStringList &platforms)
      {
          if (start >= end || 0 == platforms.count())
          {
              return;
          }
      
          m_rowCount = platforms.count();
          m_startDateTime = start;
          m_endDateTime = end;
          m_platforms = platforms;
          m_firstTimeBarStartX = axisStartPoint.x() + firstHorizantalGridWidth;
          m_firstTimeBarStartY = axisStartPoint.y();
      
          //清空現有圖形項
          clear();
      
          //繪制前先預留足夠空間
          double sceneMiniWidth = m_firstTimeBarStartX + horizontalGridWidth
                  + (end.toMSecsSinceEpoch() - start.toMSecsSinceEpoch()) / m_perPixelHMsecs;
          double sceneMiniHeight = m_firstTimeBarStartY + platforms.count() * verticalGridHeight;
      
          setSceneRect(0, 0, sceneMiniWidth, sceneMiniHeight + 800);
      
          drawVerticalAxis(platforms);
      
          QDateTime startDateTime = start;
          QDate startDate = start.date();
      
          double x = m_firstTimeBarStartX;
          for (; x <= sceneMiniWidth; x += horizontalGridWidth)
          {
              QGraphicsTextItem *timeItem = new QGraphicsTextItem(startDateTime.toString("hh:mm"));
              timeItem->setDefaultTextColor(scaleTimeColor);
              timeItem->setZValue(std::numeric_limits<int>::min());
              timeItem->setPos(x - horizontalAxisTextOffset, axisStartPoint.y() - horizontalAxisTextHeight);
              addItem(timeItem);
      
              if (x == axisStartPoint.x() + firstHorizantalGridWidth)
              {
                  QGraphicsTextItem *dateItem = new QGraphicsTextItem(startDateTime.date().toString("yyyy-MM-dd"));
                  dateItem->setDefaultTextColor(scaleDateColor);
                  dateItem->setZValue(std::numeric_limits<int>::min());
                  addItem(dateItem);
                  dateItem->setPos(x - horizontalAxisTextOffset, axisStartPoint.y() - horizontalAxisTextHeight*2);
              }
              else
              {
                  if (startDateTime.date() > startDate)
                  {
                      QGraphicsTextItem *dateItem = new QGraphicsTextItem(startDateTime.date().toString("yyyy-MM-dd"));
                      dateItem->setDefaultTextColor(scaleDateColor);
                      dateItem->setZValue(std::numeric_limits<int>::min());
                      addItem(dateItem);
                      dateItem->setPos(x - horizontalAxisTextOffset, axisStartPoint.y() - horizontalAxisTextHeight*2);
                      startDate = startDateTime.date();
                  }
              }
      
              startDateTime = startDateTime.addMSecs(m_stepTimeValue.msecsSinceStartOfDay());
      
              m_columnCount++;
      
              if (startDateTime > QDateTime::currentDateTime())
              {
                  break;
              }
          }
      
          drawGridLines();
      
          QRectF rect = this->sceneRect();
          setSceneRect(0, 0, rect.width() + 200, rect.height() + 200);
      }
      
      void CanttChartScene::drawVerticalAxis(const QStringList &platforms)
      {
          if (platforms.count() == 0)
          {
              return;
          }
      
          const double maxY = this->height();
      
          //繪制垂直表頭
          int index = 0;
          for (double y = axisStartPoint.y(); y <= maxY; y += verticalGridHeight)
          {
              if (index > platforms.count() - 1)
              {
                  break;
              }
      
              QCheckBox *box = new QCheckBox;
              box->setObjectName("PlatformCheckBox");
              box->setStyleSheet("#PlatformCheckBox {"
                                 "color: rgb(205, 218, 235);"
                                 "background-color: rgb(43, 48, 54);"
                                 "}"
                                 "#PlatformCheckBox::indicator:unchecked {"
                                 "border-image: url(:/img/checkbox/timebar-show.png) 0 0 0 0 stretch;"
                                 "}"
                                 "#PlatformCheckBox::indicator:checked {"
                                 "border-image: url(:/img/checkbox/timebar-hide.png) 0 0 0 0 stretch;"
                                 "}");
              connect(box, &QCheckBox::clicked, [=](bool checked) {
                  auto list = m_plaformTimeBarHash.values(box->text());
      
                  if (checked)
                  {
                      foreach (QGraphicsItem *item, list)
                      {
                          item->hide();
                      }
                  }
                  else
                  {
                      foreach (QGraphicsItem *item, list)
                      {
                          item->show();
                      }
                  }
              });
              box->setText(platforms.at(index));
              QGraphicsProxyWidget *proxy = addWidget(box);
              proxy->setCursor(QCursor(Qt::PointingHandCursor));
              proxy->setPos(QPoint(axisStartPoint.x(), y) + platformHeaderOffset);
              m_platformStartYHash.insert(platforms.at(index), y);
              index++;
          }
      }
      
      CanttTimeBarItem *CanttChartScene::addPlanTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end)
      {
          if (!m_platformStartYHash.keys().contains(platform))
          {
              return nullptr;
          }
      
          //添加到緩存
          auto pair = qMakePair(start, end);
          m_planTimeBarTemp.insert(platform, pair);
      
          //繪制時間條圖形項
          CanttTimeBarItem *item = new CanttTimeBarItem(start, end, CanttTimeBarItem::PlanTime, m_perPixelHMsecs);
      
          double x = m_firstTimeBarStartX + (start.toMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch()) / m_perPixelHMsecs;
          double y = m_platformStartYHash.value(platform) + 3;
      
          addItem(item);
          item->setPos(x, y);
      
          m_plaformTimeBarHash.insert(platform, item);
      
          return item;
      }
      
      CanttTimeBarItem *CanttChartScene::addRealTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end)
      {
          if (!m_platformStartYHash.keys().contains(platform))
          {
              return nullptr;
          }
      
          //添加到緩存
          auto pair = qMakePair(start, end);
          m_realTimeBarTemp.insert(platform, pair);
      
          //繪制時間條圖形項
          CanttTimeBarItem *item = new CanttTimeBarItem(start, end, CanttTimeBarItem::RealTime, m_perPixelHMsecs);
      
          double x = m_firstTimeBarStartX + (start.toMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch()) / m_perPixelHMsecs;
          double y = m_platformStartYHash.value(platform) + canttTimeBarHeight + 6;
      
          addItem(item);
          item->setPos(x, y);
      
          m_plaformTimeBarHash.insert(platform, item);
      
          return item;
      }
      
      void CanttChartScene::setStepTimeValue(const QTime &time)
      {
          m_stepTimeValue = time;
          m_perPixelHMsecs =  m_stepTimeValue.msecsSinceStartOfDay() / (double)horizontalGridWidth;
      
      #if 0
          //時間步長更新后需要更新坐標軸
          if (m_startDateTime.isNull() || m_endDateTime.isNull() || 0 == m_platforms.count())
          {
              return;
          }
          setAxisRange(m_startDateTime, m_endDateTime, m_platforms);
      #endif
      }
      
      void CanttChartScene::drawGridLines()
      {
          const double maxY = this->height();
          const double maxX = m_firstTimeBarStartX + m_columnCount * horizontalGridWidth;
      
          //繪制第一條水平網格線
          QGraphicsLineItem *item = new QGraphicsLineItem(axisStartPoint.x(), axisStartPoint.y(), axisStartPoint.x(), maxY);
          item->setPen(QPen(gridLineColor));
          item->setZValue(std::numeric_limits<int>::min());
          addItem(item);
      
          //繪制水平網格線
          for (double x = axisStartPoint.x() + firstHorizantalGridWidth; x <= maxX; x += horizontalGridWidth)
          {
              QGraphicsLineItem *item = new QGraphicsLineItem(x, axisStartPoint.y(), x, maxY);
              item->setPen(QPen(gridLineColor));
              item->setZValue(std::numeric_limits<int>::min());
              addItem(item);
          }
      
          //繪制垂直網格線
          for (double y = axisStartPoint.y(); y <= maxY; y += verticalGridHeight)
          {
              QGraphicsLineItem *item = new QGraphicsLineItem(axisStartPoint.x(), y, maxX, y);
              item->setPen(QPen(gridLineColor));
              item->setZValue(std::numeric_limits<int>::min());
              addItem(item);
          }
      }
      

      3.2 CanttChartView

      視圖類很簡單,主要就是把場景類的接口套了一下,因為視圖最終會提供給外部使用,所以這里就套一下接口:

      #ifndef CANTTCHARTVIEW_H
      #define CANTTCHARTVIEW_H
      
      #include <QGraphicsView>
      #include <QDateTime>
      
      class CanttChartScene;
      class CanttTimeBarItem;
      class CanttChartView : public QGraphicsView
      {
          Q_OBJECT
      public:
          explicit CanttChartView(QWidget *parent = 0);
      
          void setAxisRange(const QDateTime &start, const QDateTime &end, const QStringList &platforms);
      
          CanttTimeBarItem *addPlanTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end);
          CanttTimeBarItem *addRealTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end);
      
          void setStepTimeValue(const QTime &time);
      
      protected:
          virtual void wheelEvent(QWheelEvent *) override;
      
      private slots:
          void zoomIn();
          void zoomOut();
      
      private:
          void scaleBy(double factor);
      
      private:
          CanttChartScene *m_pScene;
      };
      
      #endif // CANTTCHARTVIEW_H
      
      #include "canttchartview.h"
      #include "canttchartscene.h"
      
      #include <QWheelEvent>
      
      CanttChartView::CanttChartView(QWidget *parent) : QGraphicsView(parent)
      {
          m_pScene = new CanttChartScene(this);
          setScene(m_pScene);
      
          setAlignment(Qt::AlignLeft | Qt::AlignTop);
          setDragMode(QGraphicsView::ScrollHandDrag);
          setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
      
          centerOn(0, 0);
      }
      
      void CanttChartView::setAxisRange(const QDateTime &start, const QDateTime &end, const QStringList &platforms)
      {
          m_pScene->setAxisRange(start, end, platforms);
      }
      
      CanttTimeBarItem *CanttChartView::addPlanTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end)
      {
          return m_pScene->addPlanTimeBar(platform, start, end);
      }
      
      CanttTimeBarItem *CanttChartView::addRealTimeBar(const QString &platform, const QDateTime &start, const QDateTime &end)
      {
          return m_pScene->addRealTimeBar(platform, start, end);
      }
      
      void CanttChartView::setStepTimeValue(const QTime &time)
      {
          m_pScene->setStepTimeValue(time);
      }
      
      void CanttChartView::wheelEvent(QWheelEvent *event)
      {
          if (event->delta() > 0)
          {
              zoomOut();
          }
          else
          {
              zoomIn();
          }
      }
      
      void CanttChartView::zoomIn()
      {
          scaleBy(1.1);
      }
      
      void CanttChartView::zoomOut()
      {
          scaleBy(1.0 / 1.1);
      }
      
      void CanttChartView::scaleBy(double factor)
      {
          scale(factor, factor);
      }
      
      

      3.3 CanttTimeBarItem

      這里要提一點就是,構造函數中factor參數,可以認為是每個像素代表多少毫秒,是一個縮放因子,由場景類中根據步長和網格寬度計算出的,從而計算出時間條對應的長度。

      #ifndef CANTTTIMEBARITEM_H
      #define CANTTTIMEBARITEM_H
      
      #include <QGraphicsRectItem>
      #include <QDateTime>
      #include "definition.h"
      
      class CanttTimeBarItem : public QGraphicsRectItem
      {
      public:
          enum {Type = canttTimeBarType};
          enum TimeType {
              PlanTime,
              RealTime
          };
          enum EventType {
              TakeoffEvent,
              RotationEvent,
              SwitchChannelEvent,
              LandEvent
          };
      
          explicit CanttTimeBarItem(const QDateTime &start, const QDateTime &end, TimeType type, double factor);
      
          void addEvent(const QDateTime &dateTime, EventType type);
      
      private:
          QGraphicsItem *createEventItem(EventType type);
      
      private:
          double m_pFactor;
      
          QDateTime m_startDateTime;
          QDateTime m_endDateTime;
      };
      
      #endif // CANTTTIMEBARITEM_H
      
      #include "cantttimebaritem.h"
      #include "definition.h"
      
      #include <QBrush>
      #include <QPen>
      #include <QCursor>
      #include <QPoint>
      #include <QLabel>
      #include <QGraphicsProxyWidget>
      
      const int eventItemYOffset = 2;
      
      CanttTimeBarItem::CanttTimeBarItem(const QDateTime &start, const QDateTime &end, TimeType type, double factor)
          : QGraphicsRectItem(nullptr),
            m_pFactor(factor),
            m_startDateTime(start),
            m_endDateTime(end)
      {
          double width = (end.toMSecsSinceEpoch() - start.toMSecsSinceEpoch()) / m_pFactor;
      
          setRect(0, 0, width, canttTimeBarHeight);
          setCursor(QCursor(Qt::PointingHandCursor));
      
          if (CanttTimeBarItem::PlanTime == type)
          {
              setBrush(QBrush(QColor(92, 201, 221)));
          }
          else
          {
              setBrush(QBrush(QColor(233, 252, 74)));
          }
      
          QPen pen;
          pen.setStyle(Qt::NoPen);
          setPen(pen);
      }
      
      void CanttTimeBarItem::addEvent(const QDateTime &dateTime, CanttTimeBarItem::EventType type)
      {
          if (dateTime < m_startDateTime || dateTime > m_endDateTime)
          {
              return;
          }
      
          QGraphicsItem *item = createEventItem(type);
      
          double x = (dateTime.toMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch()) / m_pFactor;
      
          item->setPos(x, eventItemYOffset);
      }
      
      QGraphicsItem *CanttTimeBarItem::createEventItem(CanttTimeBarItem::EventType type)
      {
          QLabel *label = new QLabel;
          label->setStyleSheet("QLabel {"
                               "background-color: transparent;"
                               "min-height: 12px;"
                               "max-height: 12px;"
                               "font-size: 11px;"
                               "padding-left: -2px;"
                               "border-width: 0 0 0 12;"
                               "border-image: url(:/img/event/takeoff.png) 0 0 0 64;}");
          label->setToolTip(QStringLiteral("開始起飛\n人員:張三\n地點:xxx根據地"));
      
          switch (type)
          {
          case CanttTimeBarItem::TakeoffEvent:
              label->setText(QStringLiteral("起飛"));
              break;
          case CanttTimeBarItem::RotationEvent:
              label->setText(QStringLiteral("轉角"));
              break;
          case CanttTimeBarItem::SwitchChannelEvent:
              label->setText(QStringLiteral("切換頻道"));
              break;
          case CanttTimeBarItem::LandEvent:
              label->setText(QStringLiteral("降落"));
              break;
          default:
              break;
          }
      
          QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(this);
          proxy->setWidget(label);
      
          return proxy;
      }
      

      4 總結

      在開發過程中,并不一定是先設計底層接口,有時候我們應該從業務角度去思考自己需要什么樣的接口,然后根據需要去開發,從上往下去想,往往會有事半功倍的效果。

      5 下載

      示例代碼

      posted @ 2023-12-12 17:47  Qt小羅  閱讀(2474)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 欧美大胆老熟妇乱子伦视频| 一个色综合亚洲热色综合| 亚洲av成人无网码天堂| 精品国产色情一区二区三区| 亚洲国产成人综合精品| 亚洲av无码之国产精品网址蜜芽| 亚洲成人av在线高清| 国产成人欧美综合在线影院| 亚洲综合无码久久精品综合| 亚洲国产精品久久无人区| 999久久久免费精品播放| L日韩欧美看国产日韩欧美| 亚洲精品不卡av在线播放| 色av专区无码影音先锋| 亚洲国产中文在线有精品| 无码国产69精品久久久久网站| 精品国产午夜理论片不卡| 国产人成777在线视频直播| 精品视频福利| 视频一区二区三区四区久久| 国产精品涩涩涩视频网站| 亚洲欧美国产免费综合视频| 久久综合亚洲鲁鲁九月天| 国产台湾黄色av一区二区| 久久无码中文字幕免费影院蜜桃 | 一区二区三区四区激情视频| 日韩精品毛片一区到三区| 高清dvd碟片 生活片| 国产精品爽爽久久久久久竹菊| 午夜高清福利在线观看| 最近免费中文字幕大全| 国产精品小仙女自拍视频| 最新亚洲人成无码WWW| 亚洲av无码之国产精品网址蜜芽| 国产午夜精品久久一二区| 国产露脸无套对白在线播放| 元码人妻精品一区二区三区9| 女人被爽到高潮视频免费国产| 人妻精品动漫h无码| 亚洲精品沙发午睡系列| 精品偷拍一区二区三区|