目前市面上有很多曲线绘制软件,但其交互功能较差。比如,想要实现数据的交互,同步联动等,都需要大量繁琐的人工操作。所以讲想开发一款轻量级的曲线绘制交互软件。下面就以此为案例,记录一下基于Qt4的开发过程。
目录
1 需求
- 1 通过打开csv文件的方式导入数据。
- 2 右键单击数据列,可添加曲线,还可指定横轴。
- 3 能同步联动表格和曲线,完成修改工作。
- 4 能识别修改状态,修改后能保存。
- 5 可实现数据平移。
- 6 可实现点和线两类绘图方式,可指定颜色。
2 技术路线
有了之前的开发经验,这个开发就很得心应手了。首先就是用tableview实现表格,用qcustomplot来绘图就行。关键是把文件读入进来。
3 开发流程
1 框架搭建
首先新建main window工程,并引入QCustomPlot.
用UI设计器设计界面,这个界面要简洁,只有表格和绘图区。没有多余的交互控件。
2 菜单
文件菜单有打开,保存即可。无需新建。其中,读写csv是相对独立的模块,可单独写为函数。
// 打开
void MainWindow::on_actionOpen_triggered()
{
QString tmpName = QFileDialog::getOpenFileName(this,"Open","","*.csv");
if(tmpName.isEmpty())
return;
fileName = tmpName;
if(!readcsv(fileName))
QMessageBox::information(this,"Error","file read fail.");
setWindowTitle(winName+" - "+fileName);
}
// 保存
void MainWindow::on_actionSave_triggered()
{
if(!windowTitle().contains("*") && fileName.isEmpty())
return;
QString tmpName = QFileDialog::getSaveFileName(this,"Save",fileName,"*.csv");
if(tmpName.isEmpty())
return;
if(!writecsv(tmpName))
return;
fileName = tmpName;
setWindowTitle(winName+" - "+fileName);
}
3 数据改动和右键菜单
在保存数据时,要求必须是修改状态。此外,对表头进行操作来进行列绘图。需要对表格信号和槽函数进行关联。
// 设置表头右键菜单
menuHorizontalHeader = new QMenu(this);
menuHorizontalHeader->addAction("Plot", this, SLOT(slotPlotY()));
menuHorizontalHeader->addAction("Plot with x axis", this, SLOT(slotPlotXY()));
ui->view->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
// 表头右键菜单回调
connect(ui->view->horizontalHeader(),SIGNAL(customContextMenuRequested(QPoint)),
this,SLOT(slotHorizontalHeaderMenu(QPoint)));
// 表格修改回调
connect(model,SIGNAL(dataChanged(QModelIndex,QModelIndex)),
this,SLOT(slotDataChanged(QModelIndex,QModelIndex)));
这样就设计好了互动机制,之后把相应的槽函数写好。
/* 表头右键菜单 */
void MainWindow::slotHorizontalHeaderMenu(QPoint)
{
menuHorizontalHeader->exec(QCursor::pos());
}
/* 绘制曲线 */
void MainWindow::slotPlotY()
{
int rowCount = model->rowCount();
int col = ui->view->currentIndex().column();
QVector<double> x,y;
for(int i = 0; i<rowCount; i++)
{
x<<double(i);
y<<model->data(model->index(i,col)).toDouble();
}
if(!plot(x,y))
ui->statusBar->showMessage("Error");
}
/* 绘制功能实现 */
bool MainWindow::plot(QVector<double> x, QVector<double> y)
{
ui->plot->clearGraphs();
ui->plot->addGraph();
ui->plot->graph()->setData(x,y);
ui->plot->xAxis->rescale();
ui->plot->yAxis->rescale();
ui->plot->replot();
return true;
}
/* 数据改动回调 */
void MainWindow::slotDataCha