Qt |使用QGraphicsView,QGraphics Scene创建动态图表/图表实时数据

时间:2017-05-04 15:59:41

标签: qt plot real-time qgraphicsview qgraphicsscene

我目前正在开发一个Qt的小程序。要显示图表,您可以使用qwt或qcustomplot或qpainterevent或QChart。但我正在为一个用QGraphicsView写的动态情节解决方案。

我的偏好 我的图表的宽度应该是不变的 - 实时绘图 - 如果到达图表的末尾,应删除或覆盖第一个样本,因此这是一个动态和流畅的图表

我的下面的例子可以是动态的和流利的......但仅仅是数字,这是在我的if子句中。我不明白为什么。

想法是删除第一个lineitem,所以我经常有99个项目。如果我删除了一个项目,我想给下一个项目提供之前项目的位置。 所以 x = 99将是x = 98 ...... x = 1将是x = 0;

我的想法有误吗? 我也有过几个想法,但这可能是最好的。

提前致谢 康拉德

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        scene = new QGraphicsScene(this);
        ui->graphicsView->setScene(scene);
        vectorPoint = new QVector<QPoint>;
        line = new QVector<QGraphicsLineItem*>;

    yDatai = 0;
    xDatai = 0;
    Grenzenlaufvariable = 0;

    timer = new QTimer(this);
    timer->start(10);
    connect (timer, SIGNAL(timeout()),this,SLOT(newData()));
    connect(this,SIGNAL(newPaint()),this,SLOT(paint()));
}

MainWindow::~MainWindow()
{
    delete ui;
    delete scene;
    delete vectorPoint;
    delete line;
    }

    void MainWindow::newData()
    {

    if (yDatai == 100 || yDatai == -100)                
    {
        Grenzenlaufvariable++;
    }
    if (Grenzenlaufvariable%2==0)
    {
        yDatai+=1;
    }
    else
    {
        yDatai-=1;
    }
    xDatai++;

    point = {xDatai,yDatai};                            
    vectorPoint->append(point);

    if(vectorPoint->size()>1)
    {
        item = scene->addLine(QLineF(vectorPoint->at(ix-1),vectorPoint->at(ix)));
        line->append(item);
    }
       ix++;
    emit newPaint();                                    
}

void MainWindow::paint()
{
    if(line->size()==99)
    {

        scene->removeItem(line->at(0));
        line->removeAt(0);
        qDebug()<<line->size();
        for (int ip= 0;ip <line->size();ip++)
        {
            oldx = line->at(ip)->x();
            line->at(ip)->setX(oldx-1);
            qDebug()<<ip;

        }
    }
}

3 个答案:

答案 0 :(得分:1)

到目前为止,这是最好的答案,请注意,如果你使用100Hz作为样本率,我的表现只有50 samplesInView稳定。 您可以降低采样率并增加samplesInView以在绘图中包含更多值。

重要的: xDatashortQVector<double>,其中包含所有x值 yDatashortQVector<double>,其中包含所有y值 两者都填充了programm类中的值,此类将信号发送到启动插槽drawGraph()的连接。

你也可以使用QVector<QPoint>使其更容易处理,但这不是我想要的。

lineVectorQVector<QGraphicsLineItem>,其中包含视图中的所有行

xScale用于扩展情节,yScale

width是Coordinationsystem的宽度 xAxisMark是距离标记之间的像素距离 marksVectorQVector<double>,其中包含x轴的距离标记,应该是动态的

iCurrentVectorPoint是一个运行时变量,可以帮助我添加行。

!!这段代码很适合用于实时绘图,但它没有最佳性能,所以如果有人有想法释放潜力,请随时获得最佳答案:) !!

如需进一步的问题,请发表评论,我会尽力帮助您在设备上获得精美的手工制作。

void Plot::drawGraph()
{
    if(programm->xDatashort.size()>1)
        {
            if(lineVector->size()==programm->samplesInView)
            {
                for (int ip =0;ip<programm->samplesInView;ip++)
                {
                    lineVector->at(ip)->setLine((ip)*xScale,(programm->yDatashort.at(ip))*yScale*(-1),(ip+1)*xScale,(programm->yDatashort.at(ip+1))*yScale*(-1));
                }
                for (int iy=1 ; iy<(width/xAxisMarks)+1 ; iy++)
                {
                    int oldx = marksVector->at(iy)->x();
                    oldx-=1;
                    if(oldx%xAxisMarks==0 || oldx==0)
                    {
                   marksVector->at(iy)->setX(oldx+xAxisMarks);
                    }
                    else
                    {
                    marksVector->at(iy)->setX(oldx);
                    }
                }
            }
            else
           {
                item = scene->addLine(QLineF(programm->xDatashort.at(iCurrentVectorPoint-1)*xScale,  programm->yDatashort.at(iCurrentVectorPoint-1)*yScale*(-1),   programm->xDatashort.at(iCurrentVectorPoint)*xScale, programm->yDatashort.at(iCurrentVectorPoint)*yScale*(-1)));
                lineVector->append(item);
            }

       }
        iCurrentVectorPoint++;

}

答案 1 :(得分:0)

更新

代码稳定超过50分钟,800个样本,100 Hz采样率和20 Hz帧速率。使用线程为simulatordata。随意问我关于这个主题的几乎所有内容,我已经完成了近两个月的工作:D

void MainWindow::drawChart()
{
//To check the framerate I implemented a framecounter
    framerunner++;
    ui->Framerate->setText(QString::number(int(framerunner/double(DurationTimer->elapsed()/1000))));

//Using to stay focused on the scene, not neccesary if you define the x values from [startview-endview]
    QRect a;
    if(Samplevector.size()!=0)
    {
        a.setRect(Samplevector.at(Samplevector.size()-1).getX()-850,0,900,200);
        qDebug()<<Samplevector.at(Samplevector.size()-1).getX();
    ui->LinegraphView->setSceneRect(a);
    }
//delete everything in the scene and redraw it again
scene->clear();
if(Samplevector.size()>1)
{
    for(int i=1;i<Samplevector.size();i++)
    scene->addLine(QLineF(Samplevector.at(i-1).getX(),Samplevector.at(i-1).getY(),Samplevector.at(i).getX(),Samplevector.at(i).getY()));
}

}
void MainWindow::start()
{
    framerate->start(50);
    DurationTimer->start();
    hegsimulator->moveToThread(thread);
    thread->start();
   qDebug()<<"Request "<<this->QObject::thread()->currentThreadId();
}
void MainWindow::stop()
{
    framerate->stop();
    hegsimulator->stopDevice();
}
void MainWindow::prepareGraph()
{
    samplerunner++;
    ui->Samplerate->setText(QString::number(int(samplerunner/double(DurationTimer->elapsed()/1000))));
    Samplevector.append(hegsimulator->getSample());
    if(Samplevector.size()>800)
    {
        //graphlinevector.first()->hide();
        //scene->removeItem(graphlinevector.first());
//        graphlinevector.removeFirst();
      Samplevector.removeFirst();
    }
//    if(Samplevector.size()>1)
//    {
//    item = scene->addLine(QLineF(Samplevector.at(Samplevector.size()-2).getX(),Samplevector.at(Samplevector.size()-2).getY(),Samplevector.at(Samplevector.size()-1).getX(),Samplevector.at(Samplevector.size()-1).getY()));
//    graphlinevector.append(item);

//    }

}

答案 2 :(得分:0)

<强>注意!! 这些解决方案并不是最快的。使用QPainterPath而不是QLineF,就像你拿笔,画线,把笔拿走,这1000次。 更好地保护QPainterPath中的所有QPoints并使用笔一次绘制。这样可以将实时绘图的性能提高4分钟,而且没有问题。