link-scope/graphwindow.cpp

324 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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,hei);
//绘制标记线
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);
}