视频录像时间刻度尺实现

时间刻度尺需求

  • 显示时间轴标尺(0:00:00~23:59:59)
  • 显示柱状图表示改时间段有录像
  • 当前录像刻度线及显示刻度
  • 支持拖拽、缩放(限制在0:00:00~23:59:59,最小刻度为1秒)

效果图

实现方案

        由于完全自主实现工作量太大,目前使用QCustomPlot取巧实现

QCustomPlot环境

        官网:Qt Plotting Widget QCustomPlot - Introduction

        环境布置:将qcustomplot.h、qcustomplot.cpp包含进工程编译即可

代码实现

为了调用方便不直接继承QCustomPlot,而将QCustomPlot作为成员变量

  • 如何支持拖拽、缩放
void TimeBarPlot::setDragEnabled(bool enabled)
{
	m_customPlot->setInteraction(QCP::iRangeDrag, enabled);
	m_customPlot->axisRect()->setRangeDrag(Qt::Horizontal);
}

void TimeBarPlot::setZoomEnabled(bool enabled)
{
	m_customPlot->setInteraction(QCP::iRangeZoom, enabled);
	m_customPlot->axisRect()->setRangeZoom(Qt::Horizontal);
}
  • 如何限制拖拽、缩放的轴范围
connect(m_customPlot->xAxis, static_cast<void(QCPAxis::*)(const QCPRange & newRange, const QCPRange & oldRange)>(&QCPAxis::rangeChanged),
		this, &TimeBarPlot::setxAxisRange, Qt::UniqueConnection);
...

void TimeBarPlot::setxAxisRange(const QCPRange& newRange, const QCPRange& oldRange)
{
	if (newRange.size() < XAXIS_MIN_RANGE_LENGTH)
	{
		if (QCPRange::validRange(oldRange))
		{
			m_customPlot->xAxis->setRange(oldRange);
		}
	}
	else
	{
		m_customPlot->xAxis->setRange(qMax(XAXIS_RANGE_LOWER, newRange.lower), qMin(newRange.upper, XAXIS_RANGE_UPPER));
	}
}
  • 光标线实现

        使用QCPItemStraightLine实现光标线,QCPItemText显示内容

  • 核心代码预览

class QCPBars;
class QCPRange;
class QCPItemText;
class QCustomPlot;
class QCPItemStraightLine;
class HQUI_EXPORT TimeBarPlot  : public QWidget
{
	Q_OBJECT

public:
	TimeBarPlot(QWidget *parent = nullptr);
	~TimeBarPlot();

...
    //新增柱状图
	void addBars(double startTime, double endTime, double barHeight, const QColor& color);
	void clearBars();

    //显示光标刻度线
	void setCursorValue(double pos);
	void setCursorVisible(bool visible);

...

private Q_SLOTS:
	void setxAxisRange(const QCPRange& newRange, const QCPRange& oldRange);

	void handleMousePressEvent(QMouseEvent* event);
	void handleMouseReleaseEvent(QMouseEvent* event);
	void handleMouseMoveEvent(QMouseEvent* event);
...

private:
	QCustomPlot*			m_customPlot = nullptr;
	QCPItemStraightLine*	m_lineCursor = nullptr;    //当前刻度线
	
	QCPItemText*			m_tmpText = nullptr;      //光标刻度内容
	QCPItemStraightLine*	m_tmpCursor = nullptr;    //光标刻度线

	QVector<QCPBars*>		m_bars;
	bool					m_bPressed = false;

	double					m_lastPosX;
};

const double XAXIS_RANGE_LOWER = 0;
const double XAXIS_RANGE_UPPER = 60.0 * 60.0 * 24.0;

const double XAXIS_MIN_RANGE_LENGTH = 30.0;

TimeBarPlot::TimeBarPlot(QWidget *parent)
	: QWidget(parent)
	, m_customPlot(new QCustomPlot(parent))
{
	QGridLayout* lyout = new QGridLayout(this);
	this->setLayout(lyout);
	lyout->addWidget(m_customPlot);
	lyout->setMargin(0.0);


	initPlot();
	//游标
	initCursor();
}

TimeBarPlot::~TimeBarPlot()
{}

void TimeBarPlot::addBars(double startTime, double endTime, double barHeight, const QColor& color)
{
	QVector<double> xData = { endTime - startTime };
	QVector<double> yData = { barHeight };

	// 创建柱状图数据容器
	QCPBars* bars = new QCPBars(m_customPlot->yAxis, m_customPlot->xAxis);
	bars->setBaseValue(startTime);
	bars->setData(yData, xData);
	bars->setWidth(barHeight);
	bars->setPen(color);
	bars->setBrush(color);  // 设置柱状图颜色

	m_bars << bars;
}

void TimeBarPlot::clearBars()
{
	// 删除所有的QCPBars
	m_customPlot->clearPlottables();
	m_bars.clear();
}


void TimeBarPlot::setCursorValue(double pos)
{
	if (!m_bPressed)
	{
		m_lineCursor->point1->setCoords(pos, m_customPlot->yAxis->range().lower);//起点坐标
		m_lineCursor->point2->setCoords(pos, m_customPlot->yAxis->range().upper);//终点坐标
	}
}

void TimeBarPlot::setCursorVisible(bool visible)
{
	m_lineCursor->setVisible(visible);
}

void TimeBarPlot::handleMousePressEvent(QMouseEvent* event)
{
	m_bPressed = true;

	//当前鼠标位置(像素坐标)
	double x_pos = event->pos().x();
	m_lastPosX = x_pos;

	this->setCursor(Qt::ClosedHandCursor);

	m_tmpCursor->setVisible(false);
	m_tmpText->setVisible(false);
	QWidget::mousePressEvent(event);
}

void TimeBarPlot::handleMouseReleaseEvent(QMouseEvent* event)
{
	//当前鼠标位置(像素坐标)
	double x_pos = event->pos().x();
	if (qFabs(x_pos - m_lastPosX) < 1)
	{
		//像素坐标转成实际的x,y轴的坐标
		double x_val = m_customPlot->xAxis->pixelToCoord(x_pos);

		m_lineCursor->point1->setCoords(x_val, m_customPlot->yAxis->range().lower);
		m_lineCursor->point2->setCoords(x_val, m_customPlot->yAxis->range().upper);

		this->replot();
		emit sig_cursorValueChanged(getCursorValue());
	}

	m_bPressed = false;
	this->setCursor(Qt::ArrowCursor);
	QWidget::mouseReleaseEvent(event);
}

void TimeBarPlot::handleMouseMoveEvent(QMouseEvent* event)
{
	if (!m_bPressed)
	{
		//当前鼠标位置(像素坐标)
		double x_pos = event->pos().x();

		//像素坐标转成实际的x,y轴的坐标
		double x_val = m_customPlot->xAxis->pixelToCoord(x_pos);

		m_tmpCursor->point1->setCoords(x_val, m_customPlot->yAxis->range().lower);
		m_tmpCursor->point2->setCoords(x_val, m_customPlot->yAxis->range().upper);
		m_tmpCursor->setVisible(true);

		m_tmpText->setText(QTime(0, 0, 0).addSecs(x_val).toString("hh:mm:ss"));
		m_tmpText->position->setCoords(x_val, m_customPlot->yAxis->range().center()); // 在plot中的位置
		m_tmpText->setVisible(true);

		this->replot();
	}

	QWidget::mouseMoveEvent(event);
}

void TimeBarPlot::initPlot()
{
	m_customPlot->addGraph(); // blue line

	QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime);
	timeTicker->setTimeFormat("%h:%m:%s");
	m_customPlot->xAxis->setTicker(timeTicker);
	m_customPlot->xAxis->setTickLength(30, 0);
	m_customPlot->xAxis->setSubTickLength(10, 0);
	m_customPlot->xAxis->ticker()->setTickCount(6);
	m_customPlot->xAxis->grid()->setPen(QPen(QColor(Qt::darkGray), 1, Qt::DotLine));
	m_customPlot->yAxis->setVisible(false);

	//X轴范围
	m_customPlot->xAxis->setRange(XAXIS_RANGE_LOWER, XAXIS_RANGE_UPPER);

	connect(m_customPlot->xAxis, static_cast<void(QCPAxis::*)(const QCPRange & newRange, const QCPRange & oldRange)>(&QCPAxis::rangeChanged),
		this, &TimeBarPlot::setxAxisRange, Qt::UniqueConnection);

	connect(m_customPlot, &QCustomPlot::mousePress, this, &TimeBarPlot::handleMousePressEvent, Qt::UniqueConnection);
	connect(m_customPlot, &QCustomPlot::mouseMove, this, &TimeBarPlot::handleMouseMoveEvent, Qt::UniqueConnection);
	connect(m_customPlot, &QCustomPlot::mouseRelease, this, &TimeBarPlot::handleMouseReleaseEvent, Qt::UniqueConnection);
}

void TimeBarPlot::initCursor()
{
	//游标
	QCPGraph* graph = m_customPlot->graph(0);
	QPen pen(Qt::red, 1.5, Qt::SolidLine); //颜色 、宽度、样式(直线)

	m_lineCursor = new QCPItemStraightLine(m_customPlot);
	Q_ASSERT(m_lineCursor);
	m_lineCursor->setLayer("overlay");
	m_lineCursor->setPen(pen);//设置游标线的样式
	m_lineCursor->setClipToAxisRect(true);//自适应范围

	QPen pen2(Qt::red, 1, Qt::DashDotDotLine); //颜色 、宽度、样式
	m_tmpCursor = new QCPItemStraightLine(m_customPlot);
	Q_ASSERT(m_tmpCursor);
	m_tmpCursor->setLayer("overlay");
	m_tmpCursor->setPen(pen2);//设置游标线的样式
	m_tmpCursor->setClipToAxisRect(true);//自适应范围
	m_tmpCursor->setVisible(false);

	m_tmpText = new QCPItemText(m_customPlot);
	Q_ASSERT(m_tmpText);
	m_tmpText->setLayer("overlay");
	m_tmpText->setFont(QFont(font().family(), 10));
	m_tmpText->setColor(Qt::red);
	m_tmpText->setPositionAlignment(Qt::AlignCenter);
	m_tmpText->setVisible(false);
}

其它

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值