项目简介
图像刻度轴绘制器是一款基于 Qt/C++ 开发的小型绘图工具,旨在实现带有刻度轴的图像显示功能。该项目主要用于需要精确测量或标注图像坐标的场景。通过左侧和底部的坐标轴以及对应的刻度线,可以直观地了解图像内容在二维空间中的位置。
项目功能
- 支持背景图像显示:用户可以设置任意背景图像,图像内容会紧贴刻度轴绘制。
- 动态刻度轴绘制:
- 左侧和底部的刻度线由用户设置的密度动态生成。
- 刻度线支持长短交替显示,便于区分主要刻度与次级刻度。
- 数字刻度绘制:
- 刻度数字根据实际像素位置生成,确保刻度数字对齐并完整显示。
- 刻度数字自动右对齐,且为四位数字预留充足空间。
- 绘制主轴线:X轴和Y轴的主轴线贯穿整个窗口,与刻度线相连,提供明确的坐标参考。
- 完全响应式:
- 图像与刻度轴的绘制适配窗口大小变化。
- 图像内容不因窗口缩放而变形。
代码讲解
1. 主体构造与初始化
在 EdgeScaleDrawer 类的构造函数中完成初始化。包括设置默认的刻度密度、长短刻度长度和留白空间:
EdgeScaleDrawer::EdgeScaleDrawer(QWidget *parent)
: QWidget(parent), scaleDensity(50), longRatio(10), shortRatio(5), margin(40)
{
}
scaleDensity
:刻度间隔,默认为每 50 像素绘制一个刻度。longRatio
和shortRatio
:控制长短刻度线的长度。margin
:绘图区域的留白,用于绘制刻度数字和主轴线。
2. 设置背景图片
通过 setBackgroundImage
函数设置背景图片。调用 update()
刷新窗口,确保新图片立即生效:
void EdgeScaleDrawer::setBackgroundImage(const QPixmap &pixmap)
{
background = pixmap;
update();
}
3. 绘制事件
paintEvent
是整个绘图逻辑的核心,主要包括以下步骤:
3.1 绘制背景图像
通过 QPainter::drawPixmap
将背景图像绘制到坐标轴包围的区域:
QRect imageRect(margin, 0, width() - margin, height() - margin);
if (!background.isNull()) {
painter.drawPixmap(imageRect, background);
}
margin
保证图像内容紧贴刻度轴,留出足够的刻度绘制空间。
3.2 绘制主轴线
通过 QPainter::drawLine
绘制贯穿窗口的 X 和 Y 轴主轴线:
painter.drawLine(margin, height() - margin, width(), height() - margin); // X轴
painter.drawLine(margin, 0, margin, height() - margin); // Y轴
3.3 绘制刻度线和数字
对于 左侧刻度线,从左下角开始绘制,数字显示在刻度线外侧。代码逻辑如下:
for (int y = 0; y <= imgHeight; y += scaleDensity)
{
int length = (y % (scaleDensity * 5) == 0) ? longRatio : shortRatio;
// 转换图像坐标到窗口坐标
int yPos = height() - margin - (y * windowHeight / imgHeight);
if (yPos >= margin && yPos <= height() - margin)
{
// 绘制刻度线
painter.drawLine(margin - length, yPos, margin, yPos);
// 绘制刻度数字
if (y % (scaleDensity * 5) == 0)
{
QString text = QString::number(y);
// 计算文字区域
QFontMetrics metrics(painter.font());
int textWidth = metrics.horizontalAdvance("0000");
QRect textRect(margin - length - textWidth, yPos - 10, textWidth, 20);
// 文字右对齐显示
painter.drawText(textRect, Qt::AlignRight | Qt::AlignVCenter, text);
}
}
}
底部刻度线的绘制逻辑类似,但绘制方向为水平,刻度数字显示在刻度线下方。
如何使用
1. 引入类文件
将 EdgeScaleDrawer.h
和 EdgeScaleDrawer.cpp
文件添加到您的项目中,并在需要的地方包含头文件:
#include "EdgeScaleDrawer.h"
2. 创建窗口实例
在主函数中创建 EdgeScaleDrawer
实例,并设置相关参数:
#include <QApplication>
#include "EdgeScaleDrawer.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 创建刻度绘制窗口
EdgeScaleDrawer drawer;
drawer.setBackgroundImage(QPixmap(":/images/background.jpg")); // 替换为实际图片路径
drawer.setScaleDensity(50); // 刻度间隔
drawer.setScaleRatios(10, 5); // 长短刻度长度
drawer.resize(800, 600); // 窗口大小
drawer.show();
return app.exec();
}
工程源码
头文件 (EdgeScaleDrawer.h)
#ifndef EDGESCALEDRAWER_H
#define EDGESCALEDRAWER_H
#include <QWidget>
#include <QPixmap>
/**
* @brief The EdgeScaleDrawer class
* 图像刻度轴绘制器
*
* 用于在窗口中显示带刻度的图像内容,支持 X 轴和 Y 轴的刻度线和数字绘制。
*/
class EdgeScaleDrawer : public QWidget
{
Q_OBJECT
public:
/**
* @brief 构造函数
* @param parent 父级窗口
*/
explicit EdgeScaleDrawer(QWidget *parent = nullptr);
/**
* @brief 设置背景图像
* @param pixmap 要显示的背景图像
*/
void setBackgroundImage(const QPixmap &pixmap);
/**
* @brief 设置刻度线间隔
* @param density 刻度线间隔,以像素为单位
*/
void setScaleDensity(int density);
/**
* @brief 设置长短刻度线的长度
* @param longRatio 长刻度线的长度
* @param shortRatio 短刻度线的长度
*/
void setScaleRatios(int longRatio, int shortRatio);
protected:
/**
* @brief 重写绘制事件,用于绘制背景图像、刻度线、轴线和刻度数字
* @param event 绘制事件
*/
void paintEvent(QPaintEvent *event) override;
private:
QPixmap background; // 背景图片
int scaleDensity; // 刻度线间隔(以像素为单位)
int longRatio; // 长刻度线的长度
int shortRatio; // 短刻度线的长度
int margin; // 留白,用于绘制轴线和刻度数字的空间
};
#endif // EDGESCALEDRAWER_H
实现文件 (EdgeScaleDrawer.cpp)
#include "EdgeScaleDrawer.h"
#include <QPainter>
#include <QPaintEvent>
EdgeScaleDrawer::EdgeScaleDrawer(QWidget *parent)
: QWidget(parent), scaleDensity(50), longRatio(10), shortRatio(5), margin(40)
{
}
void EdgeScaleDrawer::setBackgroundImage(const QPixmap &pixmap)
{
background = pixmap;
update();
}
void EdgeScaleDrawer::setScaleDensity(int density)
{
if (density > 0) {
scaleDensity = density;
update();
}
}
void EdgeScaleDrawer::setScaleRatios(int longRatio, int shortRatio)
{
if (longRatio > 0 && shortRatio > 0) {
this->longRatio = longRatio;
this->shortRatio = shortRatio;
update();
}
}
void EdgeScaleDrawer::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
QRect imageRect(margin, 0, width() - margin, height() - margin);
if (!background.isNull()) {
painter.drawPixmap(imageRect, background);
}
if (background.isNull()) {
return;
}
int imgWidth = background.width();
int imgHeight = background.height();
int windowWidth = width() - margin;
int windowHeight = height() - margin;
QPen pen(Qt::black, 1);
painter.setPen(pen);
QFont font = painter.font();
font.setPointSize(8);
painter.setFont(font);
painter.drawLine(margin, height() - margin, width(), height() - margin);
painter.drawLine(margin, 0, margin, height() - margin);
for (int y = 0; y <= imgHeight; y += scaleDensity)
{
int length = (y % (scaleDensity * 5) == 0) ? longRatio : shortRatio;
int yPos = height() - margin - (y * windowHeight / imgHeight);
if (yPos >= margin && yPos <= height() - margin)
{
painter.drawLine(margin - length, yPos, margin, yPos);
if (y % (scaleDensity * 5) == 0)
{
QString text = QString::number(y);
QFontMetrics metrics(painter.font());
int textWidth = metrics.horizontalAdvance("0000");
QRect textRect(margin - length - textWidth, yPos - 10, textWidth, 20);
painter.drawText(textRect, Qt::AlignRight | Qt::AlignVCenter, text);
}
}
}
for (int x = 0; x <= imgWidth; x += scaleDensity) {
int length = (x % (scaleDensity * 5) == 0) ? longRatio : shortRatio;
int xPos = margin + (x * windowWidth / imgWidth);
if (xPos >= margin && xPos <= width() - margin) {
painter.drawLine(xPos, height() - margin, xPos, height() - margin + length);
if (x % (scaleDensity * 5) == 0) {
painter.drawText(xPos - 10, height() - margin + length + 15, QString::number(x));
}
}
}
}
使用说明
- 添加头文件和实现文件:将上述
.h
和.cpp
文件添加到项目中。 - 创建并显示窗口:
在主函数中创建EdgeScaleDrawer
的实例,并调用相关接口设置背景图像、刻度密度和刻度线长度。
本文由mdnice多平台发布