How to make a ruler on the border of a QGraphicsView

别说谁变了你拦得住时间么 提交于 2019-11-28 11:12:19

问题


I am working on a small .ui project and I am was trying to understand how to properly make a ruler on a QGraphicsView.

So when the use sees the image it looks like the following:

But if the user needs to zoom-in (or zoom-out) the ruler moves accordingly along with the value of the measurements:

Thanks for shedding light on this issue and sor providing any potential example or point to the right direction.


回答1:


Create a new class by subclassing QWidget to draw your ruler. Then, set a viewport margin based on the size of your ruler.

The main difficulty is to handle the units of your ruler: The painting process in Qt uses only pixels. So, you have to convert all the distance to the right unit.

An example of ruler (in millimeters) for any QAbstractScrollArea (including QGraphicsView):

class Ruler: public QWidget
{
    Q_OBJECT
public:
    Ruler(QAbstractScrollArea* parent=nullptr): QWidget(parent),
        offset(0)
    {
        setFixedSize(40, parent->height());
        move(0, 40);
        connect(parent->verticalScrollBar(), &QScrollBar::valueChanged, this, &Ruler::setOffset);
    }
    virtual void paintEvent(QPaintEvent* event)
    {
        QPainter painter(this);
        painter.translate(0, -offset);
        int const heightMM = height() * toMM();
        painter.setFont(font());
        QFontMetrics fm(font());
        for (int position = 0; position < heightMM; ++position)
        {
            int const positionInPix = int(position / toMM());
            if (position % 10 == 0)
            {
                if (position != 0)
                {
                    QString const txt = QString::number(position);
                    QRect txtRect = fm.boundingRect(txt).translated(0, positionInPix);
                    txtRect.translate(0, txtRect.height()/2);
                    painter.drawText(txtRect, txt);
                }
                painter.drawLine(width() - 15, positionInPix, width(), positionInPix);
            }
            else {
                painter.drawLine(width() - 10, positionInPix, width(), positionInPix);
            }
        }
    }

    virtual void resizeEvent(QResizeEvent* event)
    {

        int const maximumMM = event->size().height() * toMM();
        QFontMetrics fm(font());
        int w = fm.width(QString::number(maximumMM)) + 20;
        if (w != event->size().width())
        {
            QSize const newSize(w, event->size().height());
            sizeChanged(newSize);
            return setFixedSize(newSize);
        }
        return QWidget::resizeEvent(event);
    }

    void setOffset(int value)
    {
        offset = value;
        update();
    }
signals:
    void sizeChanged(QSize const&);
private:
    int offset;

    static qreal toMM()
    {
        return 25.4 / qApp->desktop()->logicalDpiY();
    }
};

The paintEvent() and resizeEvent() functions could be simplified if you want to draw the values at the vertical instead of horizontal (you will not have to resize the ruler to be able to display all digits).

How to use it:

class GraphicsView: public QGraphicsView
{
public:
    GraphicsView(QWidget* parent=nullptr): QGraphicsView(parent),
        ruler(new Ruler(this))
    {
        connect(ruler, &Ruler::sizeChanged, [this](QSize const& size) { setViewportMargins(size.width(), size.width(), 0, 0); });
    }

    void setScene(QGraphicsScene* scene)
    {
        QGraphicsView::setScene(scene);
        if (scene)
            ruler->setFixedHeight(scene->height());
    }
private:
    Ruler* ruler;
};

The conversion pixel -> millimeters is not really accurate and you should find another way to make it.

I didn't handle the resize of the scene, either.



来源:https://stackoverflow.com/questions/56588152/how-to-make-a-ruler-on-the-border-of-a-qgraphicsview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!