c++ - QFont错误将文本适合特定高度

标签 c++ qt

我需要在 QGraphicsView 的前景上绘制比例尺.为此,我创建了一个继承自它的类并重新实现了 drawForeground (它也可以使用具有高 z 值的自定义图形项来完成,但为了确保没有在其上绘制任何内容,我决定 drawForeground 是更好的解决方案)。在这种方法中,我根据需要绘制比例尺(带有黑白框的矩形)并且它具有所需的行为。但是,计算我需要在我的秤上显示的标签大小的部分不起作用。我的秤的标签相对于屏幕应始终具有相同的高度。这意味着,当我们放大和缩小时,需要计算字体大小以适合高度始终为 10 像素的矩形。计算文字高度复制自here

这是我的类实现:

标题

#ifndef CUSTOMGRAPHICSVIEW_H
#define CUSTOMGRAPHICSVIEW_H

#include <QGraphicsView>

class CustomGraphicsView : public QGraphicsView
{
  Q_OBJECT
public:
  CustomGraphicsView(QWidget* parent = nullptr);

protected:
  virtual void wheelEvent(QWheelEvent* event) override;

  virtual void drawForeground(QPainter* painter, const QRectF& rect);

  void scalePainterFontSizeToFit(QPainter* painter, float heightToFitIn);

  virtual void contextMenuEvent(QContextMenuEvent* event);

  QAction* action_show_text_;
};

#endif  // CUSTOMGRAPHICSVIEW_H

Cpp

#include "customgraphicsview.h"

#include <QAction>
#include <QDebug>
#include <QMenu>
#include <QWheelEvent>

#include <math.h>

CustomGraphicsView::CustomGraphicsView(QWidget* parent) : QGraphicsView(parent)
{
  setScene(new QGraphicsScene);
  action_show_text_ = new QAction("Show text");
  action_show_text_->setCheckable(true);
  action_show_text_->setChecked(false);
}

void CustomGraphicsView::drawForeground(QPainter* painter, const QRectF& rect)
{
  // Select scale
  std::vector<double> steps = { 0.1, 0.15, 0.25, 0.5, 1, 2, 5, 10, 15, 25, 50 };
  qDebug() << "Rect: " << rect.topLeft() << "->" << rect.bottomRight();
  int target_y = 10;
  double step0 = (rect.bottom() - rect.top()) / target_y;
  double step = step0;
  double min_d = 1000000;
  for (size_t i = 0; i < steps.size(); i++)
  {
    if (fabs(steps[i] - step0) < min_d)
    {
      step = steps[i];
      min_d = fabs(steps[i] - step0);
    }
  }
  qDebug() << "Step: " << step;

  // Bottom right scale bar corner
  QPointF aux = mapToScene(QPoint(10, 10)) - rect.topLeft();
  QPointF br = mapToScene(mapFromScene(rect.bottomRight()) - QPoint(10, 10));

  // Draw outside rectangle
  painter->setPen(QPen(Qt::black, step * 0.01, Qt::SolidLine, Qt::SquareCap));
  painter->drawRect(QRectF(br - QPointF(4 * step, aux.y()), br));

  // Draw left half
  painter->fillRect(QRectF(br - QPointF(4 * step, aux.y()), br - QPointF(3 * step, aux.y() / 2)), Qt::black);
  painter->fillRect(QRectF(br - QPointF(4 * step, aux.y() / 2), br - QPointF(3 * step, 0)), Qt::white);

  // Draw right half
  painter->fillRect(QRectF(br - QPointF(3 * step, aux.y()), br - QPointF(2 * step, aux.y() / 2)), Qt::white);
  painter->fillRect(QRectF(br - QPointF(3 * step, aux.y() / 2), br - QPointF(2 * step, 0)), Qt::black);
  painter->fillRect(QRectF(br - QPointF(2 * step, aux.y()), br - QPointF(0, aux.y() / 2)), Qt::black);
  painter->fillRect(QRectF(br - QPointF(2 * step, aux.y() / 2), br), Qt::white);

  // Add texts
  if (action_show_text_->isChecked())
  {
    QRectF rect_text(br - QPointF(5 * step, aux.y() * 2.1), br - QPointF(3 * step, aux.y() * 1.1));
    scalePainterFontSizeToFit(painter, rect_text.height());
    painter->drawText(rect_text, Qt::AlignCenter, QString::number(0));
    rect_text = QRectF(br - QPointF(4 * step, aux.y() * 2.1), br - QPointF(2 * step, aux.y() * 1.1));
    painter->drawText(rect_text, Qt::AlignCenter, QString::number(step));
    rect_text = QRectF(br - QPointF(3 * step, aux.y() * 2.1), br - QPointF(1 * step, aux.y() * 1.1));
    painter->drawText(rect_text, Qt::AlignCenter, QString::number(2 * step));
    rect_text = QRectF(br - QPointF(1 * step, aux.y() * 2.1), br - QPointF(-1 * step, aux.y() * 1.1));
    painter->drawText(rect_text, Qt::AlignCenter, QString::number(4 * step));
  }
}

void CustomGraphicsView::scalePainterFontSizeToFit(QPainter* painter, float heightToFitIn)
{
  float oldFontSize, newFontSize, oldHeight;
  QFont r_font = painter->font();

  // Init
  oldFontSize = r_font.pointSizeF();

  // Loop
  for (int i = 0; i < 3; i++)
  {
    qDebug() << i << "a";
    oldHeight = painter->fontMetrics().boundingRect('D').height();
    qDebug() << i << "b";
    newFontSize = (heightToFitIn / oldHeight) * oldFontSize;
    qDebug() << i << "c";
    r_font.setPointSizeF(newFontSize);
    qDebug() << i << "d";
    painter->setFont(r_font);
    qDebug() << i << "e";
    oldFontSize = newFontSize;
    qDebug() << "OldFontSize=" << oldFontSize << "HtoFitIn=" << heightToFitIn << "  fontHeight=" << oldHeight
             << "newFontSize=" << newFontSize;
  }

  // End
  r_font.setPointSizeF(newFontSize);
  painter->setFont(r_font);
}

void CustomGraphicsView::wheelEvent(QWheelEvent* event)
{
  // if ctrl pressed, use original functionality
  if (event->modifiers() & Qt::ControlModifier)
    QGraphicsView::wheelEvent(event);
  // otherwise, do yours
  else
  {
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    if (event->delta() > 0)
    {
      scale(1.1, 1.1);
    }
    else
    {
      scale(0.9, 0.9);
    }
  }
}

void CustomGraphicsView::contextMenuEvent(QContextMenuEvent* event)
{
  // Create menu
  QMenu menu(this);

  // Add Fit in view
  menu.addAction(action_show_text_);

  // Exectue menu
  menu.exec(event->globalPos());
}

文本恒定高度或多或少起作用,尽管它并不总是完全相同的高度并且有时看起来被裁剪了。此外,最重要的错误是,在一定缩放后,将 setPointSizeF 设置为 0.36127 的应用程序在 oldHeight = painter-> 行卡住fontMetrics().boundingRect('D').height();(从 qDebug 消息中看到)。

我的问题是:

  1. 如何强制文本的高度保持不变,以便用户在放大/缩小时看不到文本大小的变化?
  2. 为什么 oldHeight = painter->fontMetrics().boundingRect('D').height(); 在设置了特定字体大小后卡住我的应用程序?我该如何解决这个问题?

要测试示例代码,您必须通过左键单击图形 View 在上下文菜单中激活它们来显示比例标签。

最佳答案

当函数 drawForeground 被调用时,比例已经应用到您的painter

您可以调用 painter->resetMatix() 将其移除(但是,它将移除所有变换,包括旋转和剪切。也许,您应该重新计算一个没有比例因子的新矩阵)。

文本将始终以相同的高度绘制。但是,您的画家 将在“真实”位置绘制文本。您必须将转换应用于您的 QRect 才能修复它:

painter->save(); // Save the transformation

QTransform matrix(painter->transform()); // Get the current matrix containing the scale factor

painter->resetMatrix(); // Remove transformations

QRectF rect_text(br - QPointF(5 * step, aux.y() * 2.1), br - QPointF(3 * step, aux.y() * 1.1));
rect_text = matrix.mapRect(rect_text); // Get the position of rect_text with the right scale

painter->drawText(rect_text, Qt::AlignCenter, QString::number(0));

painter->restore(); // Reset the transformation

关于c++ - QFont错误将文本适合特定高度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54964002/

相关文章:

在 QVector 中使用指针和非指针参数的 C++ 模板

qt - Qt Creator 中的功能图标是什么意思?

c++ - QT中如何播放rtsp流

C++ reversePrint链表递归

C++ 继承

c++ - unsigned char 数组到 unsigned int 通过 memcpy 返回到 unsigned char 数组被反转

c++ - 解析一个 int(x) 参数

linux - Qt5 的 CMAKE_PREFIX_PATH

c++ - Qt Quick + CMake + 自定义 QObject 导致对 `vtable' 的 undefined reference

c++ - 如何找到应该是 const 的 C++ 函数?