我需要在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_HCpp
#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消息中看到)。
我的问题是:
oldHeight = painter->fontMetrics().boundingRect('D').height();会冻结我的应用程序?我怎么才能解决这个问题?要测试示例代码,您必须通过从图形视图的左键激活上下文菜单中的缩放标签来显示它们。
发布于 2019-03-02 23:59:55
当函数drawForeground被调用时,刻度已经应用于您的画家。
您可以删除调用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 transformationhttps://stackoverflow.com/questions/54964002
复制相似问题