Je développe actuellement un petit programme en Qt. Pour montrer un tracé, vous pouvez utiliser qwt ou qcustomplot ou qpainterevent ou QChart. Mais je suis intéressé par une solution pour un tracé dynamique qui est écrit avec le QGraphicsView.

Mes préférences - la largeur de mon graphique doit être constante - le traçage en temps réel - le premier échantillon doit être supprimé ou écrasé si la fin du graphique est atteinte, il s'agit donc d'un graphique dynamique et fluide

Mon exemple ci-dessous est capable d'être dynamique et fluide ... mais juste pour le nombre, qui est dans ma clause if. Je ne comprends pas pourquoi.

L'idée est de supprimer le premier élément de la ligne, donc j'ai constamment 99 éléments. Si je supprime un élément, je veux donner à l'élément suivant la position de l'élément précédent. Donc x = 99 sera x = 98 ...... x = 1 sera x = 0;

Est-ce que j'ai une erreur dans mon idée? J'ai aussi eu plusieurs idées, mais c'est probablement la meilleure.

Merci d'avance Konrad

    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;

        }
    }
}
2
K.Friend 4 mai 2017 à 18:59

3 réponses

Meilleure réponse

ATTENTION !! Ces solutions ne sont pas les plus rapides. Utilisez QPainterPath au lieu de QLineF, c'est comme si vous preniez un stylo, tracez une ligne, rangez le stylo, et cela 1000 fois. Mieux vaut sécuriser tous les QPoints dans un QPainterPath et prendre le stylo une fois pour dessiner. Cela augmente les performances du traçage en temps réel avec une tendance de 4 minutes et plus sans problème.

0
K.Friend 23 août 2017 à 18:41

Jusqu'à présent, c'est la meilleure réponse, faites attention que si vous utilisez 100Hz comme échantillonnage, mes performances sont juste stables avec 50 samplesInView. Vous pouvez diminuer la fréquence d'échantillonnage et augmenter samplesInView pour avoir plus de valeurs dans le tracé.

Important: xDatashort est un QVector<double> qui inclut toutes les valeurs x yDatashort est un QVector<double> qui inclut toutes les valeurs y les deux sont remplis de valeurs dans la classe programm, cette classe émet le signal vers la connexion qui démarre le slot drawGraph().

Vous pouvez également simplement utiliser un QVector<QPoint> qui le rend plus facile à manipuler, mais ce n'est pas ce que je veux dans mon cas.

lineVector est un QVector<QGraphicsLineItem> qui inclut toutes les lignes de la vue

xScale est utilisé pour étendre le tracé, yScale également.

width est la largeur du système de coordonnées xAxisMark est la distance de pixels entre les marques de distance marksVector est un QVector<double> qui inclut les marques de distance de l'axe x, qui doit être dynamique

iCurrentVectorPoint est une variable d'exécution, ce qui m'aide à ajouter les lignes.

!! Ce code est bon à utiliser pour le traçage en temps réel, mais il n'a pas les meilleures performances, donc si quelqu'un a des idées pour libérer le potentiel, n'hésitez pas à obtenir la meilleure réponse :) !!

Pour d'autres questions, commentez et j'essaierai de vous aider à obtenir une belle parcelle faite à la main sur votre appareil.

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
K.Friend 10 mai 2017 à 08:50

Mise à jour:

Code stable pendant plus de 50 min avec 800 échantillons en vue, avec une fréquence d'échantillonnage de 100 Hz et une fréquence d'images de 20 Hz. Utilisation d'un fil pour les simulatordata. N'hésitez pas à me poser presque tout sur ce sujet, j'y ai travaillé pendant près de 2 mois: 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);

//    }

}
0
K.Friend 14 juin 2017 à 09:11