Seite 1 von 1
QPaint Probleme mit Widget
Verfasst: 16. Juli 2010 12:37
von Qloroplast
Wie schreibt man ein Signal Viewer, das wie folgt aussieht ?
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

Verfasst: 16. Juli 2010 14:13
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!
Verfasst: 20. Juli 2010 14:37
von Qloroplast
so kleines Update:

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();
}
Verfasst: 21. Juli 2010 13:05
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
Verfasst: 21. Juli 2010 14:18
von Qloroplast
ich suche noch eine Moeglichkeit die Werte am Eingang auf die Widget Groesse in die Y-Achse zu skalieren ?
Verfasst: 21. Juli 2010 14:28
von franzf
Speicher die max/min deiner Amplitude, und skaliere beim Zeichnen auf deine Widgetgröße.
Verfasst: 22. Juli 2010 13:40
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.
Verfasst: 22. Juli 2010 17:02
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
Verfasst: 22. Juli 2010 18:13
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.
Verfasst: 22. Juli 2010 18:35
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 .
Verfasst: 23. Juli 2010 12:25
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.