【问题标题】:How to make a ruler on the border of a QGraphicsView如何在 QGraphicsView 的边框上制作标尺
【发布时间】:2019-10-28 11:59:43
【问题描述】:

我正在处理一个小型.ui 项目,我正在尝试了解如何在QGraphicsView 上正确制作尺子。

所以当用户看到图像时,它看起来像下面这样:

但是如果用户需要放大(或缩小)标尺会随着测量值相应地移动:

感谢您阐明这个问题,或者提供任何潜在的例子或指出正确的方向。

【问题讨论】:

  • 您需要自己绘制标尺。它们可能应该是普通的 QWidget 子类,然后您可以使用 QGridLayout 轻松定位它们和正确定位 QGraphicsView。一个相关的例子可能是它如何绘制行号:doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html
  • @hyde,感谢您的评论,这绝对是一个很好的起点!

标签: c++ qt qt5 qgraphicsview qgraphicsscene


【解决方案1】:

通过子类化QWidget 创建一个新类来绘制你的标尺。然后,根据标尺的大小设置视口边距。

主要的困难是处理你的标尺单位:Qt 中的绘画过程只使用像素。因此,您必须将所有距离转换为正确的单位。

任何QAbstractScrollArea(包括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();
    }
};

如果您想在垂直方向而不是水平方向绘制值,则可以简化 paintEvent()resizeEvent() 函数(您无需调整标尺大小即可显示所有数字)。

使用方法:

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;
};

转换像素 -> 毫米并不是很准确,您应该找到另一种方法。

我也没有处理场景的大小调整。

【讨论】:

  • 非常感谢您提供的详细示例,这正是我想要的:)
  • 我完全按照您描述的方式使用了您的代码。结果是我的 QGraphicsView 上出现了标尺区域,但没有绘制任何单位。为什么会这样?
  • @George,我还必须进行一些非常小的更改才能使其正常工作,尤其是 connect 部分用于 SIGNALSLOT。但它有效,您应该会看到类似this 的内容。不过我准备了一个基于 Romha Korev 代​​码的完整示例,您可以从here 下载它。让我知道它是否适合您。
  • @Emanuele 它有效,它肯定会帮助我。感谢您的宝贵时间
【解决方案2】:

在创建时,scene->height() 默认为零。如果 rule->setFixedHeight() 无意中将标尺的高度设置为 0,则不会调用标尺的paintEvent。

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

【讨论】:

    猜你喜欢
    • 2019-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-17
    • 1970-01-01
    • 1970-01-01
    • 2021-01-16
    相关资源
    最近更新 更多