QPaint Probleme mit Widget

Alles rund um die Programmierung mit Qt
Antworten
Qloroplast
Beiträge: 16
Registriert: 23. März 2010 12:15

QPaint Probleme mit Widget

Beitrag von Qloroplast »

Wie schreibt man ein Signal Viewer, das wie folgt aussieht ?
Bild



Man malt in ein Widget 2 Werte in Form einer Linie die von einem paintEvent() aufgerufen werden. Das Problem daran ist das ich beim naechsten paintEvent das komplette Bild ueberschreibe. Wie behalte ich die alten Werte im Widget und male die neuen drueber ?

Code: Alles auswählen

void Oszi::paintEvent(QPaintEvent * event )
{
    //////////////Initial Bild macher 
    if (this->zeigFenster==true)
    {
        QPainter background(this);      
        background.setRenderHint(QPainter::Antialiasing,true);
        background.setPen(QPen(Qt::blue, 1, Qt::DashDotLine, Qt::RoundCap));
        background.drawLine(0,this->size().height()/2,this->size().width(),this->size().height()/2);
        background.drawText(10,10,(this->text));       
        // Malt das Bild aus dem der eraser spaeter das Bild holen soll um zu loeschen
        this->zeigFenster = false;
    }
    //////////////Loescher soll Bild einsetzen um das alte sauber zu ueberschreiben 
    QPainter eraser(this);
    eraser.setPen(QPen(Qt::cyan, 1, Qt::DashDotLine, Qt::RoundCap));
    eraser.drawRect(this->index,10,10,this->size().height());
    this->index++;
    if (this->index>this->size().width())
    {
        this->index = 0;
    }
    //////////////Hier werden die Punkte gemalt 
    QPainter Werte(this);
    Werte.setPen(Qt::green);
    QPoint neu(index,this->neuer_wert);
    Werte.drawLine(this->alter_wert,neu);
    this->alter_wert = neu;
Das eigentlich Problem liegt das ich die alten Werte nicht behalte, genauer gesagt das ich mit dem neuen paintEvent() meine Alten uebermale.

Wie kann ich das verhindern, ohne das ich alle Werte neu malen muss ?
Ich steh so was von auf dem Schlauch :-(
Zuletzt geändert von Qloroplast am 22. Juli 2010 17:09, insgesamt 1-mal geändert.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

So wie du malen willst funktioniert das nicht. Wenn du einen Bereich malst, musst du immer ALLES malen, ein Übermalen von altem Inhalt (alos aus einem früheren paintEvent) geht nicht. Funktionieren täte das z.B. mit QGraphicsView, da kannst du einfach einzelne Items malen, das Zeug darunter bleibt (wenn du es nicht löschst) immer sichtbar.

Alternativ kannst du mal qwt anschauen, die haben schon einiges an Diagramm-Klassen dabei!
Qloroplast
Beiträge: 16
Registriert: 23. März 2010 12:15

Beitrag von Qloroplast »

so kleines Update:
Bild
ich erzeuge ein Hintergrundbild, ein Vordergrundbild
ich schneide aus dem Hintergrundbild ein Bereich aus -> fuege den im Vordergrundbild ein loesche damit den alten Bereich -> male den neuen Wert ins Bild mit drawLine -> fuege diese Bild in das Widget ein und fertig ist das Oszi
das passiert bei jedem Wert den man hinzufuegt !
funktioniert rudimentaer und verbraucht wenig resourcen :-)

Code: Alles auswählen

/*###############################################################################################################################*/
void Oszi::SLOT_generate_Pics()
{     

    this->Area.clear();
    //QPixmap Ausschnitt(QSize(Weite,this->size().height()));
    //Ausschnitt = this->Hintergrund.copy(this->xKoordinate,0,Weite ,this->size().height());
    QPainter foreground;
    foreground.begin(&visualDisplay);
    // kopier anzahl Weite Pixel vom Hintergrund  --> fuege sie mit index ein
    if(this->xKoordinate+Weite>this->size().width())
    {       // FAENGT DAS ENDE AB 
            QRect Ende(this->xKoordinate,0,this->size().width()-this->xKoordinate,this->size().height());
            QPixmap clip_ende(1,1);
            clip_ende = this->background.copy(Ende);
            foreground.drawPixmap(Ende,clip_ende);
            this->Area.push_back(Ende);
            // FAENGT DEN ANFANG AB 
            QRect Anfang(0,0,Weite-(this->size().width()-this->xKoordinate),this->size().height());
            QPixmap clip_anfang(1,1);
            clip_anfang = this->background.copy(Anfang);
            foreground.drawPixmap(Anfang,clip_anfang);
            this->Area.push_back(Anfang);
    }
    else
    {   // FAENGT NORMAL AB UND MALT ! 
        QRect Einfach(this->xKoordinate,0,Weite,this->size().height());
        QPixmap clip_Einfach(1,1);
        clip_Einfach = this->background.copy(Einfach);
        foreground.drawPixmap(Einfach,clip_Einfach);
        this->Area.push_back(Einfach);
    }
    //vordergrund.drawPixmap(this->xKoordinate,0,Weite,this->size().height(),Ausschnitt);

    foreground.setPen(QPen(Qt::green, 2, Qt::SolidLine));
    QPoint neu( this->xKoordinate ,this->neuer_wert );
    if(this->xKoordinate >= this->size().width())
    {// hier ist Problem: Ende zum Anfang abgedeckt
        neu = QPoint(0,this->neuer_wert);
    }
    else
    {// Wenn ein normaler draw ist
        foreground.drawLine(this->alter_wert,neu);
    }
    this->alter_wert = neu;

    foreground.end();
    // <-------------------------------------->
    if (this->xKoordinate >= this->size().width())
    {// die X-Koordinate wieder auf NULL wenn Widget->size->width erreicht ist 
        this->xKoordinate = 0;

    }
    qDebug()<<"X-Koordinate = "<<this->xKoordinate;
    foreach (QRect UPDATEAREA,this->Area)
    { // Qt wird angehalten die gesetze Bereiche zu updaten 
        this->update(UPDATEAREA);
    }

    this->xKoordinate++;
}
/*###############################################################################################################################*/
void Oszi::paintEvent(QPaintEvent * event )
{
    QPainter  draw_Pic(this);
    // Malt nur den ausgewaehlten Bereich ! 
   draw_Pic.drawPixmap(event->rect(),this->visualDisplay,event->rect());
}
/*###############################################################################################################################*/
void Oszi::SLOT_update_value(double value)
{ 
    /* - ANPASSEN an die Skala !
    if (value > this->size().height())
    {
        value = this->size().height();
        // emit Problem
    }
    if (value < 0)
    {
        value = 0;
        // emit Problem
    }*/
    this->neuer_wert = value;
    this->SLOT_generate_Pics();
    //
}
/*###############################################################################################################################*/
void Oszi::SLOT_Resize(QSize * Wert)
{
    //qDebug()<<"Hoehe"<<Wert->height()<<"Laenge"<<Wert->width();
    this->resize(Wert->width(),Wert->height());   
    this->background = QPixmap(this->size());
    this->visualDisplay = QPixmap(this->size());
    this->visualDisplay.fill(QColor(Qt::white));
    QLinearGradient linearGradient(0, 0, this->size().height()/2,this->size().width()/2);
    linearGradient.setColorAt(0.0, Qt::white);
    linearGradient.setColorAt(0.6, Qt::black);
    linearGradient.setColorAt(0.8, Qt::white);
    QPainter backpainter(&this->background);
    backpainter.fillRect(0,0,this->size().width(),this->size().height(),linearGradient);
    this->SLOT_generate_Pics();
    }
Zuletzt geändert von Qloroplast am 22. Juli 2010 14:46, insgesamt 1-mal geändert.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Code: Alles auswählen

void Oszi::paintEvent(QPaintEvent * event )
{
    QPainter  Oszi(this);
    // Malt nur den ausgewaehlten Bereich !
    Oszi.drawPixmap(event->rect(),this->visualDisplay,event->rect());
} 
Nenn bitte den QPainter anders, der heißt jetzt so wie die Klasse, das kann Verwirrung stiften (unter den Lesern und Compilern ;)).
Und die ständigen this->Dereferenzierungen kannst du dir sparen.

Code: Alles auswählen

Oszi.drawPixmap( event->rect(), visualDisplay, event->rect() );
reicht vollkommen. Dadurch wird der Code übersichtlicher, weniger aufgebläht, stattdessen kannst du ein paar mehr Leerzeichen einfügen :)
Auch solltest du Kommentare auf ein Minimum beschränken. Eigentlich sollten Kommentare nur dahin, wo sie nötig sind, z.B. wenn du einen optimierten, unleserlichen Algorithmus hast, ist es nicht schlecht kurz hinzuschreiben, was passiert. Oder evtl. Nebeneffekte bei Funktionen. Aber Sachen wie

Code: Alles auswählen

if (this->xKoordinate >= this->size().width())
    {// die X-Koordinate wieder auf NULL wenn Widget->size->width erreicht ist
        this->xKoordinate = 0;

    }
sind unnötig;

Code: Alles auswählen

{// hier ist Problem: Ende zum Anfang abgedeckt
        neu = QPoint(0,this->neuer_wert);
    }
oder einfach unverständlich...

Und für die nächsten Code-Posts wäre es nicht schlecht, irgendwo im Code extra für uns dazu zu schreiben, welche Variable jetzt genau welchen Typ hat. So ist es verdammt anstrengend zu lesen.

Grüßle aus Titiwu
Qloroplast
Beiträge: 16
Registriert: 23. März 2010 12:15

Beitrag von Qloroplast »

ich suche noch eine Moeglichkeit die Werte am Eingang auf die Widget Groesse in die Y-Achse zu skalieren ?
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Speicher die max/min deiner Amplitude, und skaliere beim Zeichnen auf deine Widgetgröße.
Nash
Beiträge: 118
Registriert: 27. April 2007 14:49

Beitrag von Nash »

ich würde alle deine Y werte in einer Queue speichern.
http://doc.qt.nokia.com/4.6/qqueue.html

und dann alle deine Werte aufeinmal zeichnen.
Kommt ein neuer wert hinzu schmeißt du den ersten aus der Liste und zeichnest wieder neu. Dann kannst du dir auch das initialisieren im paint event sparen.
Qloroplast
Beiträge: 16
Registriert: 23. März 2010 12:15

Beitrag von Qloroplast »

Sinn & Zweck war es maximal CPU sparend zu arbeiten

neu zeichnen bei 10k Punkten kostet viel > mehr als ein "10 *height" Bildchen zubasteln und upzudaten

Nachteil: bei einem "resize_Event" muss das Komplette Bild neu gemalt werden
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Bei einer Kurve der obigen Form sind keine 10k-Punkte auf dem Bildschirm sondern max. 1.5k. Und wenn man das berücksichtigt ist man beim neuzeichnen verdammt schnell.
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

Ich will nen Bildschirm mit 10000 Pixeln horizontaler Auflösung :)))))) meiner hat nur 1680 :(((((

Die Natur der Kurve die du darstellen willst, verbietet zwei verschiedene Y-Werte am selben X-Wert (es wird eine Widerstandsänderung über die Zeit dargestellt und da die Zeit nicht Rückwärts springt, gibts nur einen Wert zu jeder Zeit ;). Folglich brauchste maximal #(Widgetdarstellungsbreite) Datenpunkte .
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
Qloroplast
Beiträge: 16
Registriert: 23. März 2010 12:15

Beitrag von Qloroplast »

ja sry, ich hab mich missverstaendlich ausgedrueckt. Ich hab 10 Kanaele und dann werden die 10k schon realistisch und knapp wird es dann bei groesseren Frequenzen.
Antworten