-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathgraphwindow.cpp
323 lines (297 loc) · 11.5 KB
/
graphwindow.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#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);
//绘制标记线
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);
}