在QGraphicsScene中绘制标尺
Draw a scale ruler in QGraphicsScene?
本文关键字:绘制 QGraphicsScene 更新时间:2023-10-16
我正在使用Qt构建一个地图小部件(类似于谷歌地图),基本上我使用了QGraphicsScene来显示地图瓦片。
现在我想像谷歌地图中的那个一样,给这个小部件添加一个标尺。关于我该如何实现这一点,有什么建议吗?
看看这个例子:
按照以下方式构建代码库:
- 编写一个继承QAbstractScrollArea的子类的类(例如QGraphicsView、QMdiArea、QPlainTextEdit、QScrollArea、QTextEdit、QColumnView、QHeaderView、QListView、QTableView、QTreeView等)
- 在类的构造函数中,调用setViewportMargins并设置左/上/右/下区域长度的边距
- 创建一个QGridLayout并在布局中添加自定义标尺/比例
- 调用setLayout设置此布局
示例:
setViewportMargins(RULER_BREADTH,RULER_BREADTH,0,0);
QGridLayout* gridLayout = new QGridLayout();
gridLayout->setSpacing(0);
gridLayout->setMargin(0);
mHorzRuler = new QDRuler(QDRuler::Horizontal);
mVertRuler = new QDRuler(QDRuler::Vertical);
QWidget* fake = new QWidget();
fake->setBackgroundRole(QPalette::Window);
fake->setFixedSize(RULER_BREADTH,RULER_BREADTH);
gridLayout->addWidget(fake,0,0);
gridLayout->addWidget(mHorzRuler,0,1);
gridLayout->addWidget(mVertRuler,1,0);
gridLayout->addWidget(this->viewport(),1,1);
this->setLayout(gridLayout);
QDRuler:标尺类
#define RULER_BREADTH 20
class QDRuler : public QWidget
{
Q_OBJECT
Q_ENUMS(RulerType)
Q_PROPERTY(qreal origin READ origin WRITE setOrigin)
Q_PROPERTY(qreal rulerUnit READ rulerUnit WRITE setRulerUnit)
Q_PROPERTY(qreal rulerZoom READ rulerZoom WRITE setRulerZoom)
public:
enum RulerType { Horizontal, Vertical };
QDRuler(QDRuler::RulerType rulerType, QWidget* parent)
: QWidget(parent), mRulerType(rulerType), mOrigin(0.), mRulerUnit(1.),
mRulerZoom(1.), mMouseTracking(false), mDrawText(false)
{
setMouseTracking(true);
QFont txtFont("Goudy Old Style", 5,20);
txtFont.setStyleHint(QFont::TypeWriter,QFont::PreferOutline);
setFont(txtFont);
}
QSize minimumSizeHint() const
{
return QSize(RULER_BREADTH,RULER_BREADTH);
}
QDRuler::RulerType rulerType() const
{
return mRulerType;
}
qreal origin() const
{
return mOrigin;
}
qreal rulerUnit() const
{
return mRulerUnit;
}
qreal rulerZoom() const
{
return mRulerZoom;
}
public slots:
void setOrigin(const qreal origin)
{
if (mOrigin != origin)
{
mOrigin = origin;
update();
}
}
void setRulerUnit(const qreal rulerUnit)
{
if (mRulerUnit != rulerUnit)
{
mRulerUnit = rulerUnit;
update();
}
}
void setRulerZoom(const qreal rulerZoom)
{
if (mRulerZoom != rulerZoom)
{
mRulerZoom = rulerZoom;
update();
}
}
void setCursorPos(const QPoint cursorPos)
{
mCursorPos = this->mapFromGlobal(cursorPos);
mCursorPos += QPoint(RULER_BREADTH,RULER_BREADTH);
update();
}
void setMouseTrack(const bool track)
{
if (mMouseTracking != track)
{
mMouseTracking = track;
update();
}
}
protected:
void mouseMoveEvent(QMouseEvent* event)
{
mCursorPos = event->pos();
update();
QWidget::mouseMoveEvent(event);
}
void paintEvent(QPaintEvent* event)
{
QPainter painter(this);
painter.setRenderHints(QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing);
QPen pen(Qt::black,0); // zero width pen is cosmetic pen
//pen.setCosmetic(true);
painter.setPen(pen);
// We want to work with floating point, so we are considering
// the rect as QRectF
QRectF rulerRect = this->rect();
// at first fill the rect
//painter.fillRect(rulerRect,QColor(220,200,180));
painter.fillRect(rulerRect,QColor(236,233,216));
// drawing a scale of 25
drawAScaleMeter(&painter,rulerRect,25,(Horizontal == mRulerType ? rulerRect.height()
: rulerRect.width())/2);
// drawing a scale of 50
drawAScaleMeter(&painter,rulerRect,50,(Horizontal == mRulerType ? rulerRect.height()
: rulerRect.width())/4);
// drawing a scale of 100
mDrawText = true;
drawAScaleMeter(&painter,rulerRect,100,0);
mDrawText = false;
// drawing the current mouse position indicator
painter.setOpacity(0.4);
drawMousePosTick(&painter);
painter.setOpacity(1.0);
// drawing no man's land between the ruler & view
QPointF starPt = Horizontal == mRulerType ? rulerRect.bottomLeft()
: rulerRect.topRight();
QPointF endPt = Horizontal == mRulerType ? rulerRect.bottomRight()
: rulerRect.bottomRight();
painter.setPen(QPen(Qt::black,2));
painter.drawLine(starPt,endPt);
}
private:
void drawAScaleMeter(QPainter* painter, QRectF rulerRect, qreal scaleMeter, qreal startPositoin)
{
// Flagging whether we are horizontal or vertical only to reduce
// to cheching many times
bool isHorzRuler = Horizontal == mRulerType;
scaleMeter = scaleMeter * mRulerUnit * mRulerZoom;
// Ruler rectangle starting mark
qreal rulerStartMark = isHorzRuler ? rulerRect.left() : rulerRect.top();
// Ruler rectangle ending mark
qreal rulerEndMark = isHorzRuler ? rulerRect.right() : rulerRect.bottom();
// Condition A # If origin point is between the start & end mard,
//we have to draw both from origin to left mark & origin to right mark.
// Condition B # If origin point is left of the start mark, we have to draw
// from origin to end mark.
// Condition C # If origin point is right of the end mark, we have to draw
// from origin to start mark.
if (mOrigin >= rulerStartMark && mOrigin <= rulerEndMark)
{
drawFromOriginTo(painter, rulerRect, mOrigin, rulerEndMark, 0, scaleMeter, startPositoin);
drawFromOriginTo(painter, rulerRect, mOrigin, rulerStartMark, 0, -scaleMeter, startPositoin);
}
else if (mOrigin < rulerStartMark)
{
int tickNo = int((rulerStartMark - mOrigin) / scaleMeter);
drawFromOriginTo(painter, rulerRect, mOrigin + scaleMeter * tickNo,
rulerEndMark, tickNo, scaleMeter, startPositoin);
}
else if (mOrigin > rulerEndMark)
{
int tickNo = int((mOrigin - rulerEndMark) / scaleMeter);
drawFromOriginTo(painter, rulerRect, mOrigin - scaleMeter * tickNo,
rulerStartMark, tickNo, -scaleMeter, startPositoin);
}
}
void drawFromOriginTo(QPainter* painter, QRectF rulerRect, qreal startMark, qreal endMark, int startTickNo, qreal step, qreal startPosition)
{
bool isHorzRuler = Horizontal == mRulerType;
int iterate = 0;
for (qreal current = startMark;
(step < 0 ? current >= endMark : current <= endMark); current += step)
{
qreal x1 = isHorzRuler ? current : rulerRect.left() + startPosition;
qreal y1 = isHorzRuler ? rulerRect.top() + startPosition : current;
qreal x2 = isHorzRuler ? current : rulerRect.right();
qreal y2 = isHorzRuler ? rulerRect.bottom() : current;
painter->drawLine(QLineF(x1,y1,x2,y2));
if (mDrawText)
{
QPainterPath txtPath;
txtPath.addText(x1 + 1,y1 + (isHorzRuler ? 7 : -2),this->font(),QString::number(qAbs(int(step) * startTickNo++)));
painter->drawPath(txtPath);
iterate++;
}
}
}
void drawMousePosTick(QPainter* painter)
{
if (mMouseTracking)
{
QPoint starPt = mCursorPos;
QPoint endPt;
if (Horizontal == mRulerType)
{
starPt.setY(this->rect().top());
endPt.setX(starPt.x());
endPt.setY(this->rect().bottom());
}
else
{
starPt.setX(this->rect().left());
endPt.setX(this->rect().right());
endPt.setY(starPt.y());
}
painter->drawLine(starPt,endPt);
}
}
private:
RulerType mRulerType;
qreal mOrigin;
qreal mRulerUnit;
qreal mRulerZoom;
QPoint mCursorPos;
bool mMouseTracking;
bool mDrawText;
};
相关文章:
- QuadTree只在窗口的右上角绘制
- 绘制旋转的三角形
- flutter:即使shouldRepaint()返回true,自定义画家也不会重新绘制
- 如何在QT中的自定义视频小工具t上绘制矩形
- 如何在Visual Basic中使用矩形函数OpenGL绘制矩形
- 无法使用VAO和EBO(openGL)绘制多个对象
- 为什么我的点没有在 OpenGL 中绘制鼠标所在的位置?
- 绘制顺时针三角形,重新排序点
- 在顶点着色器中使用 OpenGl 的未声明标识符,我在顶点着色器中绘制三角形时遇到问题
- SFML 文本未绘制在窗口上
- 如何在快板的屏幕中显示子位图的绘制?
- 如何绘制自定义形状的元素?
- QPainter 将 QBrush 设置为 在 QT/C++ 中绘制文本
- 除非重新绘制大小,否则SDL_Texture在调整大小后呈现黑色
- 绘制文本问题
- 在 QT C++中绘制/操作多边形
- 如何在 Gnuplot 中分别绘制 2 个文件数据?我有一个文件"sin.txt",另一个文件"cos.txt",我想将它们分别绘制在一个图表上
- 在现代OpenGL中,绘制GL_TRIANGLE奇怪的z轴行为的填充圆
- OpenGL 着色器不绘制任何东西 - 糟糕的精灵类
- 要在屏幕上绘制一些小瓷砖,我应该使用 QQuickItem 还是 QQuickPaintedItem?