我需要在QGraphicsView
的前景上绘制比例。为此,我创建了一个从其继承并重新实现drawForeground
的类(也可以使用具有较高z值的自定义图形项来完成该类,但为确保未在其上绘制任何内容,我决定将{{1 }}是一个更好的解决方案。在这种方法中,我可以根据需要绘制比例尺(带有黑白框的矩形),并且具有所需的行为。但是,我需要按比例显示的标签尺寸计算部分无法正常工作。我的体重秤标签相对于屏幕应始终具有相同的高度。这意味着,当我们放大和缩小时,需要计算字体大小以适合总是10像素高的矩形。计算文本高度是从here
这是我的课程实现:
标题
drawForeground
Cpp
#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
文本恒定高度或多或少起作用,尽管它不一定总是完全相同的高度,有时它似乎被裁剪了。此外,最重要的错误是,经过一定缩放后,将#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
在设置了一定的字体磅值后会冻结我的应用程序?我该如何解决?要测试示例代码,您必须通过在图形视图的左键单击上下文菜单中激活它们来显示比例尺标签。
答案 0 :(得分:1)
调用函数drawForeground
时,比例尺已应用于您的 painter 。
您可以调用painter->resetMatix()
将其删除(但是,它将删除包括旋转和剪切在内的所有变换。也许您应该重新计算没有比例因子的新矩阵)。
文本将始终以相同的高度绘制。但是,您的 painter 将在“真实”位置绘制文本。您必须将转换应用于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