【问题标题】:Draw a scale ruler in QGraphicsScene?在 QGraphicsScene 中绘制比例尺?
【发布时间】:2014-11-15 19:56:26
【问题描述】:

我正在使用 Qt 构建地图小部件(类似于谷歌地图),基本上我使用 QGraphicsScene 来显示地图图块。

现在我想在小部件中添加一个比例尺,就像谷歌地图中的那样。 关于我如何实现这一点的任何建议?

【问题讨论】:

    标签: c++ qt qgraphicsscene


    【解决方案1】:

    看看this example

    按照以下方式构建您的代码库:

    • 写一个继承QAbstractScrollArea后代类的类(如QGraphicsView、QMdiArea、QPlainTextEdit、QScrollArea、QTextEdit、QColumnView、QHeaderView、QListView、QTableView、QTreeView等)
    • 在类的构造函数中调用 setViewportMargins 并设置左/上/右/下区域的边距长度。
    • 创建一个 QGridLayout 并在布局中添加您的自定义标尺/刻度。
    • 调用 setLayout 设置此布局

    例子:

    setViewportMargins(RULER_BREADTH,RULER_BREADTH,0,0);
    QGridLayout* gridLayout = new QGridLayout();
    gridLayout->setSpacing(0);
    gridLayout->setMargin(0);
    
    mHorzRuler = new QDRuler(QDRuler::Horizontal);
    mVertRuler = new QDRuler(QDRuler::Vertical);
    
    QWidget* fake = new QWidget();
    fake->setBackgroundRole(QPalette::Window);
    fake->setFixedSize(RULER_BREADTH,RULER_BREADTH);
    gridLayout->addWidget(fake,0,0);
    gridLayout->addWidget(mHorzRuler,0,1);
    gridLayout->addWidget(mVertRuler,1,0);
    gridLayout->addWidget(this->viewport(),1,1);
    
    this->setLayout(gridLayout);
    

    QDRuler:标尺类

    #define RULER_BREADTH 20
    
    class QDRuler : public QWidget
    {
    Q_OBJECT
    Q_ENUMS(RulerType)
    Q_PROPERTY(qreal origin READ origin WRITE setOrigin)
    Q_PROPERTY(qreal rulerUnit READ rulerUnit WRITE setRulerUnit)
    Q_PROPERTY(qreal rulerZoom READ rulerZoom WRITE setRulerZoom)
    public:
      enum RulerType { Horizontal, Vertical };
    QDRuler(QDRuler::RulerType rulerType, QWidget* parent)
    : QWidget(parent), mRulerType(rulerType), mOrigin(0.), mRulerUnit(1.),
      mRulerZoom(1.), mMouseTracking(false), mDrawText(false)
    {
      setMouseTracking(true);
        QFont txtFont("Goudy Old Style", 5,20);
        txtFont.setStyleHint(QFont::TypeWriter,QFont::PreferOutline);
        setFont(txtFont);
    }
    
    QSize minimumSizeHint() const
    {
      return QSize(RULER_BREADTH,RULER_BREADTH);
    }
    
    QDRuler::RulerType rulerType() const
    {
      return mRulerType;
    }
    
    qreal origin() const
    {
      return mOrigin;
    }
    
    qreal rulerUnit() const
    {
      return mRulerUnit;
    }
    
    qreal rulerZoom() const
    {
      return mRulerZoom;
    }
    
    public slots:
    
    void setOrigin(const qreal origin)
    {
      if (mOrigin != origin)
      {
        mOrigin = origin;
        update();
      }
    }
    
    void setRulerUnit(const qreal rulerUnit)
    {
      if (mRulerUnit != rulerUnit)
      {
        mRulerUnit = rulerUnit;
        update();
      }
    }
    
    void setRulerZoom(const qreal rulerZoom)
    {
      if (mRulerZoom != rulerZoom)
      {
        mRulerZoom = rulerZoom;
        update();
      }
    }
    
    
    void setCursorPos(const QPoint cursorPos)
    {
      mCursorPos = this->mapFromGlobal(cursorPos);
      mCursorPos += QPoint(RULER_BREADTH,RULER_BREADTH);
      update();
    }
    
    void setMouseTrack(const bool track)
    {
      if (mMouseTracking != track)
      {
        mMouseTracking = track;
        update();
      }
    }
    
    protected:
    void mouseMoveEvent(QMouseEvent* event)
    { 
      mCursorPos = event->pos();
      update(); 
      QWidget::mouseMoveEvent(event); 
    }
    
    void paintEvent(QPaintEvent* event)
    {
      QPainter painter(this);
        painter.setRenderHints(QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing);
        QPen pen(Qt::black,0); // zero width pen is cosmetic pen
        //pen.setCosmetic(true);
        painter.setPen(pen);
      // We want to work with floating point, so we are considering
      // the rect as QRectF
      QRectF rulerRect = this->rect();
    
      // at first fill the rect
      //painter.fillRect(rulerRect,QColor(220,200,180));
      painter.fillRect(rulerRect,QColor(236,233,216));
    
      // drawing a scale of 25
      drawAScaleMeter(&painter,rulerRect,25,(Horizontal == mRulerType ? rulerRect.height()
            : rulerRect.width())/2);
      // drawing a scale of 50
      drawAScaleMeter(&painter,rulerRect,50,(Horizontal == mRulerType ? rulerRect.height()
            : rulerRect.width())/4);
      // drawing a scale of 100
      mDrawText = true;
      drawAScaleMeter(&painter,rulerRect,100,0);
      mDrawText = false;
    
      // drawing the current mouse position indicator
        painter.setOpacity(0.4);
      drawMousePosTick(&painter);
        painter.setOpacity(1.0);
    
      // drawing no man's land between the ruler & view
      QPointF starPt = Horizontal == mRulerType ? rulerRect.bottomLeft()
          : rulerRect.topRight();
      QPointF endPt = Horizontal == mRulerType ? rulerRect.bottomRight()
          : rulerRect.bottomRight();
      painter.setPen(QPen(Qt::black,2));
      painter.drawLine(starPt,endPt);
    }
    
    private:
    void drawAScaleMeter(QPainter* painter, QRectF rulerRect, qreal scaleMeter, qreal startPositoin)
    {
      // Flagging whether we are horizontal or vertical only to reduce
      // to cheching many times
      bool isHorzRuler = Horizontal == mRulerType;
    
      scaleMeter  = scaleMeter * mRulerUnit * mRulerZoom;
    
      // Ruler rectangle starting mark
      qreal rulerStartMark = isHorzRuler ? rulerRect.left() : rulerRect.top();
      // Ruler rectangle ending mark
      qreal rulerEndMark = isHorzRuler ? rulerRect.right() : rulerRect.bottom();
    
      // Condition A # If origin point is between the start & end mard,
      //we have to draw both from origin to left mark & origin to right mark.
      // Condition B # If origin point is left of the start mark, we have to draw
      // from origin to end mark.
      // Condition C # If origin point is right of the end mark, we have to draw
      // from origin to start mark.
      if (mOrigin >= rulerStartMark && mOrigin <= rulerEndMark)
      {    
        drawFromOriginTo(painter, rulerRect, mOrigin, rulerEndMark, 0, scaleMeter, startPositoin);
        drawFromOriginTo(painter, rulerRect, mOrigin, rulerStartMark, 0, -scaleMeter, startPositoin);
      }
      else if (mOrigin < rulerStartMark)
      {
            int tickNo = int((rulerStartMark - mOrigin) / scaleMeter);
            drawFromOriginTo(painter, rulerRect, mOrigin + scaleMeter * tickNo,
                rulerEndMark, tickNo, scaleMeter, startPositoin);
      }
      else if (mOrigin > rulerEndMark)
      {
            int tickNo = int((mOrigin - rulerEndMark) / scaleMeter);
        drawFromOriginTo(painter, rulerRect, mOrigin - scaleMeter * tickNo,
                rulerStartMark, tickNo, -scaleMeter, startPositoin);
      }
    }
    
    void drawFromOriginTo(QPainter* painter, QRectF rulerRect, qreal startMark, qreal endMark, int startTickNo, qreal step, qreal startPosition)
    {
      bool isHorzRuler = Horizontal == mRulerType;
      int iterate = 0;
    
      for (qreal current = startMark;
          (step < 0 ? current >= endMark : current <= endMark); current += step)
      {
        qreal x1 = isHorzRuler ? current : rulerRect.left() + startPosition;
        qreal y1 = isHorzRuler ? rulerRect.top() + startPosition : current;
        qreal x2 = isHorzRuler ? current : rulerRect.right();
        qreal y2 = isHorzRuler ? rulerRect.bottom() : current;
        painter->drawLine(QLineF(x1,y1,x2,y2));
        if (mDrawText)
        {
          QPainterPath txtPath;
                txtPath.addText(x1 + 1,y1 + (isHorzRuler ? 7 : -2),this->font(),QString::number(qAbs(int(step) * startTickNo++)));
          painter->drawPath(txtPath);
          iterate++;
        }
      }
    }
    
    void drawMousePosTick(QPainter* painter)
    {
      if (mMouseTracking)
      {
        QPoint starPt = mCursorPos;
        QPoint endPt;
        if (Horizontal == mRulerType)
        {
          starPt.setY(this->rect().top());
          endPt.setX(starPt.x());
          endPt.setY(this->rect().bottom());
        }
        else
        {
          starPt.setX(this->rect().left());
          endPt.setX(this->rect().right());
          endPt.setY(starPt.y());
        }
        painter->drawLine(starPt,endPt);
      }
    }
    private:
      RulerType mRulerType;
      qreal mOrigin;
      qreal mRulerUnit;
      qreal mRulerZoom;
      QPoint mCursorPos;
      bool mMouseTracking;
      bool mDrawText;
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-21
      • 2017-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-17
      相关资源
      最近更新 更多