先看几张效果图:
- 可以任意拖动时间轨道
- 可以任意缩放时间轨道,缩放级别20级
- 拖动树形节点到时间进度条上,并且可以自由添加时间的长短
- 拖动时间的位置
部分类图
普通轨道类:
#pragma once
#include <QGraphicsItem>
//基础Item,可以绘制背景色统一宽度等
class PlanItem : public QGraphicsItem {
public:
PlanItem(QGraphicsItem* parent = nullptr);
~PlanItem();
int&getStartX() {
return _startX;
}
int&getStartY() {
return _startY;
}
int&getViewWidth() {
return _viewWidht;
}
int&getViewHeight() {
return _viewHeight;
}
int&getItemWidth() {
return _itemWidth;
}
int&getItemHeight() {
return _itemHeight;
}
virtual void viewSize(int vw, int vh);
virtual void setStartOffset(int x, int y);
virtual void setTimeOnCenter(double time);//设置时间在中点
virtual void zoomIn(QPointF mouseMovePt, double mouseMoveTime);
virtual void zoomOut(QPointF mouseMovePt, double mouseMoveTime);
void setItemBorder(bool b) {
_isDrawBorder = b;
}
void setSelected(bool b) {
_isClickSelect = b;
}
bool&getSelected() {
return _isClickSelect;
}
protected:
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR) override;
void drawBg(QPainter *painter);
void zoomPos(QPointF mouseMovePt, double mouseMoveTime);
protected:
int _viewWidht = 0; //视图宽度
int _viewHeight = 0; //视图高度
int _itemWidth = 0; //当前图元的宽度
int _itemHeight = 50; //当前图元的高度
int _space = 2; //图元距离边界的距离
int _startX = 0; //开始的X
int _startY = 0; //开始的Y
QColor _bgColorStart = QColor(9, 41, 72);
QColor _bgColorEnd = QColor(15, 35, 53);
bool _isDrawBorder = false; //是否绘制边框
bool _isClickSelect = false; //是否点击选中
};
#include <QPainter>
#include <QDebug>
#include "PlanItem.h"
#include "TimeTickManager.h"
PlanItem::PlanItem(QGraphicsItem* parent)
:QGraphicsItem(parent){
}
PlanItem::~PlanItem() {
}
void PlanItem::viewSize(int vw, int vh) {
_viewWidht = vw;
_viewHeight = vh;
_startX = -_viewWidht / 2 + _space ;
_startY = -_viewHeight / 2 + _space ;
_itemWidth = _viewWidht;
setPos(_startX, _startY);
//保存起始位置X
TimeTickMgr()->setTimeTickStartX(_startX);
update();
}
void PlanItem::setStartOffset(int x, int y) {
_startX += x;
_startY += y;
//不允许Item向右拖动,只能向左拖动
if (_startX >= -_viewWidht / 2 + _space) {
_startX = -_viewWidht / 2 + _space;
}
//可显示的Item的宽度就是开始位置的绝对值+1/2的视图的宽度
_itemWidth = abs(_startX) + _viewWidht / 2;
//保存起始位置X
TimeTickMgr()->setTimeTickStartX(_startX);
setPos(_startX, _startY);
update();
}
void PlanItem::setTimeOnCenter(double time) {
_startX = - time / TimeTickMgr()->getPixelEachSecond();
//可显示的Item的宽度就是开始位置的绝对值+1/2的视图的宽度
_itemWidth = abs(_startX) + _viewWidht / 2;
TimeTickMgr()->setTimeTickStartX(_startX);
setPos(_startX, _startY);
update();
}
//放大
void PlanItem::zoomIn(QPointF mouseMovePt, double mouseMoveTime) {
zoomPos(mouseMovePt, mouseMoveTime);
}
//缩小
void PlanItem::zoomOut(QPointF mouseMovePt, double mouseMoveTime) {
zoomPos(mouseMovePt, mouseMoveTime);
}
QRectF PlanItem::boundingRect() const {
return QRectF(0, 0, INT_MAX, INT_MAX);
}
void PlanItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget /*= Q_NULLPTR*/) {
drawBg(painter);
}
void PlanItem::drawBg(QPainter *painter) {
painter->save();
painter->setPen(Qt::NoPen);
QLinearGradient bgGradient(QPointF(0, 0), QPointF(0, _itemHeight));
bgGradient.setColorAt(0.0, _bgColorStart);
bgGradient.setColorAt(1.0, _bgColorEnd);
painter->setBrush(bgGradient);
painter->drawRect(_space, _space, _itemWidth, _itemHeight);
if (_isDrawBorder){//高亮显示边框
QPen pen;
pen.setColor(Qt::yellow);
pen.setStyle(Qt::DashLine);
pen.setWidth(2);
painter->setPen(pen);
painter->drawRect(_space, _space, _itemWidth, _itemHeight);
}
if (_isClickSelect){//选中后,高亮显示边框
QPen pen;
pen.setColor(Qt::yellow);
pen.setStyle(Qt::SolidLine);
pen.setWidth(2);
painter->setPen(pen);
painter->setBrush(QBrush(QColor(128, 128, 128, 100)));
painter->drawRect(_space, _space, _itemWidth, _itemHeight);
}
painter->restore();
}
void PlanItem::zoomPos(QPointF mouseMovePt, double mouseMoveTime) {
_startX = mouseMovePt.x() - mouseMoveTime / TimeTickMgr()->getPixelEachSecond();
//可显示的Item的宽度就是开始位置的绝对值+1/2的视图的宽度
_itemWidth = abs(_startX) + _viewWidht / 2;
TimeTickMgr()->setTimeTickStartX(_startX);
setPos(_startX, _startY);
update();
}
场景类:
#pragma once
#include <QGraphicsScene>
#include "interface/ISceneToPlanTime.h"
//信号规划的场景
class TimeTickPaint2;
class PlanItemBean;
class WorkModeItem;
class FragmentDataPack;
class SignalPlanScene
: public QGraphicsScene
, public ISceneToPlanTime {
Q_OBJECT
public:
SignalPlanScene(QObject *parent = Q_NULLPTR);
~SignalPlanScene();
void initScene();
void wheelEvent(int detal);
void mousePressEvent(QGraphicsSceneMouseEvent *event)override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event)override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)override;
void dragEnterEvent(QGraphicsSceneDragDropEvent *event)override;
void dragMoveEvent(QGraphicsSceneDragDropEvent *event)override;
void dropEvent(QGraphicsSceneDragDropEvent *event)override;
private:
void addPlanTime(PlanItemBean* sigSrcNean)override;
void deletePlanTime()override;
void selectFragDataSide(QPointF mouseMovePt);
private:
TimeTickPaint2* _timeTickMarkItem = nullptr;
bool _leftBtnDown = false;
QPointF _leftBtnDownPos;//鼠标按下时的坐标
QPointF _mouseMovePt;//鼠标滑动时的坐标
double _mouseMoveTime = 0.0;//鼠标滑动时的时间
WorkModeItem* _dragRadarSignalItem = nullptr;//拖动选中的平台
FragmentDataPack* _selectFragDataPack = nullptr;
};
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneDragDropEvent>
#include <QGraphicsView>
#include "SignalPlanScene.h"
#include "PlanItem/TimeTickPaint2.h"
#include "PlanItem/TimeTickManager.h"
#include "PlanItem/PlanItemManager.h"
#include "PlanItem/WorkModeItem.h"
#include "Bean/PlanItemBean.h"
#include "Interface/ScrollChangeManager.h"
#include "ModeTree/WorkModeMimeData.h"
#include "Bean/FragmentData.h"
#include "Bean/FragmentDataPack.h"
#include "interface/SceneToPlanTimeManage.h"
SignalPlanScene::SignalPlanScene(QObject *parent)
: QGraphicsScene(parent) {
SceneMgr()->setSceneToPlanTime(this);
}
SignalPlanScene::~SignalPlanScene() {
}
void SignalPlanScene::initScene() {
//时间刻度条
_timeTickMarkItem = new TimeTickPaint2;
addItem(_timeTickMarkItem);
_timeTickMarkItem->setZValue(1);//设置Item置于顶层
PlanItemMgr()->addPlanItem(_timeTickMarkItem);
#if 1//绘制中心原点
QGraphicsEllipseItem* ellipseItem = new QGraphicsEllipseItem;
ellipseItem->setRect(-5, -5, 10, 10);
this->addItem(ellipseItem);
#endif
update();
}
void SignalPlanScene::wheelEvent(int detal) {
if (detal > 0) {
TimeTickMgr()->zoomOutPixelEachSecond();
PlanItemMgr()->zoomOut(_mouseMovePt, _mouseMoveTime);
} else {
TimeTickMgr()->zoomInPixelEachSecond();
PlanItemMgr()->zoomIn(_mouseMovePt, _mouseMoveTime);
}
update();
}
void SignalPlanScene::mousePressEvent(QGraphicsSceneMouseEvent *event) {
if (event->button() & Qt::LeftButton) {
_leftBtnDown = true;
QPointF point = event->scenePos();
_leftBtnDownPos = event->lastScenePos();
if (_selectFragDataPack != nullptr) {//选中实体
_selectFragDataPack->setLBtnDownPos(event->scenePos());
}
//鼠标所在的Item,点击一直高亮显示
if (_dragRadarSignalItem != nullptr) {
_dragRadarSignalItem->setSelected(!_dragRadarSignalItem->getSelected());
}
update();
}
QGraphicsScene::mousePressEvent(event);
}
void SignalPlanScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
_mouseMovePt = event->scenePos();
_mouseMoveTime = (_mouseMovePt.x() - TimeTickMgr()->getTimeTickStartX())*TimeTickMgr()->getPixelEachSecond();
if (_leftBtnDown) {//左键按下
if (_selectFragDataPack == nullptr) {//没有选中数据,拖动全部
QPointF mouseDelta = _mouseMovePt - _leftBtnDownPos;
PlanItemMgr()->setStartOffset(mouseDelta.x(), 0);
_leftBtnDownPos = _mouseMovePt;
} else {//选中数据,只拖动数据
_selectFragDataPack->resizePos(_mouseMovePt);
}
update();
} else {//不按下左键
selectFragDataSide(_mouseMovePt);
}
QGraphicsScene::mouseMoveEvent(event);
}
void SignalPlanScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
if (event->button() & Qt::LeftButton) {
_leftBtnDown = false;
_selectFragDataPack = nullptr;
}
QGraphicsScene::mouseReleaseEvent(event);
}
void SignalPlanScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event) {
if (event->mimeData()->hasFormat("RadarWorkMode/Sig")) {
event->acceptProposedAction();
}
}
void SignalPlanScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event) {
QPointF dragMovePos = event->scenePos();
std::vector<PlanItem*>&itemList = PlanItemMgr()->getItemList();
int num = itemList.size();
for (int i = 0; i < num; i++) {
WorkModeItem* radarSignalItem = dynamic_cast<WorkModeItem*>(itemList.at(i));
if (radarSignalItem != nullptr) {
int idx = radarSignalItem->mousePtInItem(dragMovePos);
if (idx != -1) {
radarSignalItem->setItemBorder(true);
_dragRadarSignalItem = radarSignalItem;
} else {
radarSignalItem->setItemBorder(false);
}
}
}
event->accept();
update();
}
void SignalPlanScene::dropEvent(QGraphicsSceneDragDropEvent *event) {
if (event->mimeData()->hasFormat("RadarWorkMode/Sig")) {
QPointF dropPos = event->scenePos();
if (_dragRadarSignalItem == nullptr) {
return;
}
//拖动的设备节点
WorkModeMimeData *pMimeData = (WorkModeMimeData *)(event->mimeData());
FragmentData* fragData = new FragmentData;
fragData->setWorkModeBean(pMimeData->getWorkModeBean());
//添加数据内容
FragmentDataPack*packData = _dragRadarSignalItem->addOneFragmentData(fragData);
//鼠标当前所在位置的时间
double time = (dropPos.x() - TimeTickMgr()->getTimeTickStartX())*TimeTickMgr()->getPixelEachSecond();
//向前移动50个像素确定开始时间
double fromTime = time - 50 * TimeTickMgr()->getPixelEachSecond();
fragData->setFromTime(fromTime);
//向后移动50个像素确定结束时间
double toTime = time + 50 * TimeTickMgr()->getPixelEachSecond();
fragData->setToTime(toTime);
//设置显示树形
_dragRadarSignalItem->setItemBorder(false);
_dragRadarSignalItem = nullptr;
event->acceptProposedAction();
update();
}
}
void SignalPlanScene::addPlanTime(PlanItemBean* sigSrcNean) {
WorkModeItem* planTimeItem = new WorkModeItem;
planTimeItem->setPlanItemBean(sigSrcNean);
addItem(planTimeItem);
planTimeItem->setItemIndex(_timeTickMarkItem->getItemHeight()
, PlanItemMgr()->totalItem() - 1
, _timeTickMarkItem->getViewWidth()
, _timeTickMarkItem->getViewHeight());
PlanItemMgr()->addPlanItem(planTimeItem);
ScrollChangeMgr()->addScrollChange(planTimeItem);
update();
}
void SignalPlanScene::deletePlanTime() {
std::vector<PlanItem*>&planItemList = PlanItemMgr()->getItemList();
int num = planItemList.size();
for (int i = 0; i < planItemList.size(); i++) {
PlanItem* oneItem = planItemList.at(i);
WorkModeItem* radarSignalItem = dynamic_cast<WorkModeItem*>(oneItem);
if (radarSignalItem == nullptr) {
continue;
}
if (radarSignalItem->getSelected()){
planItemList.erase(planItemList.begin() + i);
removeItem(oneItem);
i--;
}
}
update();
}
void SignalPlanScene::selectFragDataSide(QPointF mouseMovePt) {
std::vector<PlanItem*>&itemList = PlanItemMgr()->getItemList();
int num = itemList.size();
for (int i = 0; i < num; i++) {
WorkModeItem* radarSignalItem = dynamic_cast<WorkModeItem*>(itemList.at(i));
if (radarSignalItem != nullptr) {
int idx = radarSignalItem->mousePtInItem(mouseMovePt);
int sideX = -1, side = -1;
if (_selectFragDataPack != nullptr) {//取消高亮显示
_selectFragDataPack->setDeviceHighLightBK(false);
}
_selectFragDataPack = radarSignalItem->getSideX(QPoint(mouseMovePt.x(), mouseMovePt.y()), sideX, side);
if (side == 0) {//左
views().at(0)->setCursor(Qt::SizeHorCursor);
if (_selectFragDataPack != nullptr) {
_selectFragDataPack->setDeviceHighLightBK(true);
}
break;
} else if (side == 2) {//右
views().at(0)->setCursor(Qt::SizeHorCursor);
if (_selectFragDataPack != nullptr) {
_selectFragDataPack->setDeviceHighLightBK(true);
}
break;
} else if (side == 1) {//中
views().at(0)->setCursor(Qt::SizeAllCursor);
if (_selectFragDataPack != nullptr) {
_selectFragDataPack->setDeviceHighLightBK(true);
}
break;
} else {
views().at(0)->setCursor(Qt::ArrowCursor);
}
//高亮显示鼠标所在的Item
if (idx != -1) {
radarSignalItem->setItemBorder(true);
_dragRadarSignalItem = radarSignalItem;
} else {
radarSignalItem->setItemBorder(false);
}
}
}
update();
}
视图类:
#pragma once
#include <QGraphicsView>
class SignalPlanView : public QGraphicsView {
Q_OBJECT
public:
SignalPlanView(QWidget *parent = Q_NULLPTR);
~SignalPlanView();
private:
void resizeEvent(QResizeEvent *event)override;
void wheelEvent(QWheelEvent *event)override;
};
#include <QResizeEvent>
#include "SignalPlanView.h"
#include <QSize>
#include "PlanItem/PlanItemManager.h"
#include "SignalPlanScene.h"
SignalPlanView::SignalPlanView(QWidget *parent)
: QGraphicsView(parent) {
setMouseTracking(true);
}
SignalPlanView::~SignalPlanView() {
}
void SignalPlanView::resizeEvent(QResizeEvent *event) {
//保证视图的中点在(0,0)位置
centerOn(0, 0);
QSize size = event->size();
PlanItemMgr()->viewSize(size.width(), size.height());
}
void SignalPlanView::wheelEvent(QWheelEvent *event) {
SignalPlanScene* planScene = dynamic_cast<SignalPlanScene*>(scene());
if (planScene != nullptr) {
planScene->wheelEvent(event->delta());
}
}
若需要源,私信我
aaa