link-scope/graphwindow.cpp

324 lines
12 KiB
C++
Raw Permalink Normal View History

2022-01-02 00:31:59 +08:00
#include "graphwindow.h"
#include "ui_graphwindow.h"
GraphWindow::GraphWindow(QWidget *parent) :
QDialog(parent),
ui(new Ui::GraphWindow)
{
ui->setupUi(this);
setWindowTitle("LinkScope - Graph");
ui->txt_graph->installEventFilter(this);
updateCursor();
//设定触发定时器
trigTimer=new QTimer(this);
trigTimer->setInterval(30); //30ms绘制一帧图像
trigTimer->start();
connect(trigTimer,SIGNAL(timeout()),this,SLOT(onTrig()));
}
GraphWindow::~GraphWindow()
{
delete trigTimer;
delete ui;
}
//绘图事件,进行图像重绘
void GraphWindow::paintGraph(QWidget *canvas)
{
//绘图部分在窗口上的位置
float offsetx=ui->txt_graph->pos().x(),offsety=ui->txt_graph->pos().y();
//绘图部分宽高
float hei=ui->txt_graph->height(),wid=ui->txt_graph->width();
float posx=0,posy=0;//绘图偏移
QPainter painter(canvas); //画笔
painter.setBrush(QBrush(QColor(Qt::white)));//填充背景
painter.drawRect(posx,posy,wid-1,hei-1);
2022-01-02 00:31:59 +08:00
//绘制标记线
painter.setPen(QPen(QColor(184,184,184),2,Qt::DotLine));
for(int i=1;i<VERT_DIV;i++)
{
float horiY=hei*i/VERT_DIV+posy;
painter.drawLine(posx,horiY,posx+wid,horiY);
}
for(int i=1;i<HORI_DIV;i++)
{
float vertX=wid*i/HORI_DIV+posx;
painter.drawLine(vertX,posy,vertX,posy+hei);
}
//计算采样点最大时间范围和需要显示的时间范围
double totalTime=0;
for(int varIndex=0;varIndex<varList->size();varIndex++)
if(varList->at(varIndex).samples.size()>0 && varList->at(varIndex).samples.last().timestamp>totalTime*1000000)
totalTime=varList->at(varIndex).samples.last().timestamp/1000000.0;
double timeRange=ui->sb_hori_rsv->value()*HORI_DIV;
if(dragging)//若正在拖拽则根据鼠标位移移动图像
{
double vertDist=(mousePos.y()-lastMousePos.y())*1.0/hei*ui->sb_vert_rsv->value()*VERT_DIV;
ui->sb_vert_offset->setValue(ui->sb_vert_offset->value()-vertDist);
double horiDist=(mousePos.x()-lastMousePos.x())*1.0/wid*timeRange*1000;
ui->bar_hori->setValue(ui->bar_hori->value()-horiDist);
lastMousePos=mousePos;
}
//设定水平拖动条范围
if(totalTime>timeRange)
ui->bar_hori->setMaximum(totalTime*1000-timeRange*1000);
else
ui->bar_hori->setMaximum(1);
//若勾选实时更新则设定拖动条到末端
if(ui->cb_update->checkState()==Qt::Checked)
ui->bar_hori->setValue(ui->bar_hori->maximum());
double startTime=ui->bar_hori->value()*1.0/ui->bar_hori->maximum()*(totalTime-timeRange);//需显示部分的开始时间
double endTime=startTime+timeRange;//需显示部分的结束时间
double valueRange=ui->sb_vert_rsv->value()*VERT_DIV;//界面能显示的值的范围
double minValue=-valueRange/2-ui->sb_vert_offset->value();//界面能显示的最小值
//依次绘制曲线
for(int varIndex=0;varIndex<varList->size();varIndex++)
{
VarInfo &var=(*varList)[varIndex];
if(!var.enableScope || var.samples.size()<2)//若不使能绘制或采样点太少则跳过
continue;
painter.setPen(QPen(var.lineColor,varIndex==chosenVarIndex?4:2,Qt::SolidLine));//设置笔刷(若是被选中的曲线则加粗)
SamplePoint lastSamp=var.samples.at(0);//用于记录线段的上一个点
for(int sampIndex=1;sampIndex<var.samples.size();sampIndex++)//依次连接采样点
{
SamplePoint thisSamp=var.samples.at(sampIndex);
double lastTime=lastSamp.timestamp/1000000.0;
double thisTime=thisSamp.timestamp/1000000.0;
if(lastTime>startTime&&lastTime<endTime && thisTime>startTime&&thisTime<endTime && thisTime-lastTime<0.5)
{
QPoint lastPoint((lastTime-startTime)/timeRange*wid+posx,hei-(lastSamp.value-minValue)/valueRange*hei+posy);
QPoint thisPoint((thisTime-startTime)/timeRange*wid+posx,hei-(thisSamp.value-minValue)/valueRange*hei+posy);
if(!( (lastPoint.y()<posy && thisPoint.y()<posy) || (lastPoint.y()>posy+hei && thisPoint.y()>posy+hei) ))
painter.drawLine(lastPoint,thisPoint);
}
lastSamp=thisSamp;
}
}
if(looking)//若正在查看变量则绘制查看线
{
painter.setPen(QPen(QColor(184,184,184),3,Qt::SolidLine));
painter.drawLine(mousePos.x()-offsetx,posy,mousePos.x()-offsetx,posy+hei);
}
//计算并显示选中变量的变量名、当前值、查看值
if(chosenVarIndex>=0 && chosenVarIndex<varList->size() && varList->at(chosenVarIndex).samples.size()>=2)
{
const VarInfo *chosenVar=&varList->at(chosenVarIndex);
ui->lab_name->setText("变量名:"+chosenVar->name);
ui->lab_curval->setText(QString("当前值:%1").arg(chosenVar->samples.last().value));
if(looking)//计算查看位置
{
double lookTime=(mousePos.x()-posx-offsetx)*1.0/wid*timeRange+startTime;
for(int sampIndex=0;sampIndex<chosenVar->samples.size()-1;sampIndex++)//依次检查采样点找到时间戳与查看位置最接近的点
{
if(chosenVar->samples.at(sampIndex).timestamp/1000000.0<=lookTime&&
chosenVar->samples.at(sampIndex+1).timestamp/1000000.0>=lookTime)
{
ui->lab_lookval->setText(QString("查看值:%1").arg(chosenVar->samples.at(sampIndex).value));
break;
}
if(sampIndex==chosenVar->samples.size()-2)
ui->lab_lookval->setText("");
}
}
else
{
ui->lab_lookval->setText("");
}
}
else
{
ui->lab_name->setText("");
ui->lab_curval->setText("");
ui->lab_lookval->setText("");
}
}
//重写事件过滤器用于触发绘图label的绘图事件
bool GraphWindow::eventFilter(QObject *watched, QEvent *event)
{
if(watched==ui->txt_graph && event->type()==QEvent::Paint)
{
paintGraph(ui->txt_graph);
return true;
}
return QDialog::eventFilter(watched,event);
}
//滚轮事件
void GraphWindow::wheelEvent(QWheelEvent *event)
{
if(shiftFlag) //shift按下则竖直缩放
{
float dist=ui->sb_vert_rsv->value()*0.01; //最大/最小值增减量
if(event->delta()>0)
{
ui->sb_vert_rsv->setValue(ui->sb_vert_rsv->value()-dist);
}
else if(event->delta()<0)
{
ui->sb_vert_rsv->setValue(ui->sb_vert_rsv->value()+dist);
}
}
if(ctrlFlag) //ctrl按下则水平伸缩
{
float dist=ui->sb_hori_rsv->value()*0.01; //横向分辨率增减量
int barDist=dist*1000*HORI_DIV/2;
if(event->delta()>0)
{
if(ui->sb_hori_rsv->value()>0.001)
{
ui->sb_hori_rsv->setValue(ui->sb_hori_rsv->value()-dist);
if(ui->bar_hori->value()<ui->bar_hori->maximum()-barDist)
ui->bar_hori->setValue(ui->bar_hori->value()+barDist);
}
}
if(event->delta()<0)
{
ui->sb_hori_rsv->setValue(ui->sb_hori_rsv->value()+dist);
if(ui->bar_hori->value()>ui->bar_hori->minimum()+barDist)
ui->bar_hori->setValue(ui->bar_hori->value()-barDist);
}
}
if(!ctrlFlag && !shiftFlag && !altFlag) //无任何组合键按下则时间轴左右滚动
{
float dist=ui->sb_hori_rsv->value()*100; //水平拖动条位置增减量
if(event->delta()>0 && ui->bar_hori->value()>0)
{
if(ui->bar_hori->value()>dist)
ui->bar_hori->setValue(ui->bar_hori->value()-dist);
else
ui->bar_hori->setValue(0);
}
else if(event->delta()<0 && ui->bar_hori->value()<ui->bar_hori->maximum())
{
if(ui->bar_hori->maximum()-ui->bar_hori->value()>dist)
ui->bar_hori->setValue(ui->bar_hori->value()+dist);
else
ui->bar_hori->setValue(ui->bar_hori->maximum());
}
}
}
//按键按下事件
void GraphWindow::keyPressEvent(QKeyEvent *event)
{
//三种组合键按下时对应标记置true
if(event->key()==Qt::Key_Control)
ctrlFlag=true;
else if(event->key()==Qt::Key_Shift)
shiftFlag=true;
else if(event->key()==Qt::Key_Alt)
altFlag=true;
updateCursor();
}
//按键松开事件
void GraphWindow::keyReleaseEvent(QKeyEvent *event)
{
//三种组合键松开时对应标记置false
if(event->key()==Qt::Key_Control)
ctrlFlag=false;
else if(event->key()==Qt::Key_Shift)
shiftFlag=false;
else if(event->key()==Qt::Key_Alt)
altFlag=false;
updateCursor();
}
//鼠标按下事件
void GraphWindow::mousePressEvent(QMouseEvent *event)
{
if(event->button()==Qt::LeftButton) //如果左键按下则开启查看ALT未按下或拖拽ALT按下
{
if(altFlag)
dragging=true;
else
looking=true;
mousePos.setX(event->x()); //记录鼠标坐标
mousePos.setY(event->y());
lastMousePos=mousePos;
}
}
//鼠标松开事件
void GraphWindow::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button()==Qt::LeftButton) //如果左键松开则关闭查看和拖拽
looking=dragging=false;
}
//鼠标移动事件(仅按下时触发)
void GraphWindow::mouseMoveEvent(QMouseEvent *event)
{
if(looking||dragging) //若在查看或拖拽状态则记录鼠标位置
{
mousePos.setX(event->x());
mousePos.setY(event->y());
}
}
//定时器槽函数,触发绘图
void GraphWindow::onTrig()
{
ui->txt_graph->update();
}
//用于外部设置变量列表
void GraphWindow::setVarList(QList<VarInfo> *list)
{
varList=list;
}
//用于外部设置选中的变量
void GraphWindow::setChosenIndex(int varIndex)
{
chosenVarIndex=varIndex;
}
//点击按钮时弹出说明界面
void GraphWindow::on_btn_help_clicked()
{
//弹出messagebox显示帮助信息
QString str="设置说明\n"
"水平分辨率:水平方向每两根标线间表示的秒数\n"
"竖直分辨率:竖直方向每两根标线间表示的范围\n"
"实时更新:始终显示时间轴末端,跟随采样值的更新而变化\n\n"
"快捷操作\n"
"1.无按键+滚轮:时间轴左右滚动\n"
"2.Ctrl+滚轮:图像水平缩放\n"
"3.Shift+滚轮:图像竖直缩放\n"
"4.Alt+左键拖拽:移动图像\n\n"
"查看操作\n"
"按住鼠标左键并拖动可以查看所选变量曲线的值(主界面单击变量名可选中变量)";
QMessageBox box;
box.setWindowTitle("绘图界面说明");
box.setText(str);
box.exec();
}
//根据各标志更新光标形状
void GraphWindow::updateCursor()
{
if(ctrlFlag&&shiftFlag)//ctrl和shift同时按下水平竖直方向同步缩放显示斜向缩放箭头
ui->txt_graph->setCursor(Qt::SizeFDiagCursor);
else if(ctrlFlag)//ctrl按下水平方向缩放显示横向箭头
ui->txt_graph->setCursor(Qt::SizeHorCursor);
else if(shiftFlag)//shift按下纵向缩放显示纵向箭头
ui->txt_graph->setCursor(Qt::SizeVerCursor);
else if(altFlag)//alt按下可以拖拽图像显示拖动光标
ui->txt_graph->setCursor(Qt::SizeAllCursor);
else //没有按键按下,显示十字光标
ui->txt_graph->setCursor(Qt::CrossCursor);
}