[gelöst] paintEvent löscht Widgethintergrund???
[gelöst] paintEvent löscht Widgethintergrund???
Moinmoin,
ich bastel gerade an einem Widget, das einen Balken ausgeben soll, dessen Höhe proportional zu einem Wert ist.
Nun dachte ich, man könnte einfach die paintEvent-Methode überschreiben.
Da das Zeichnen den Prozessor allerdings nicht so sehr auslasten soll, wollte ich das so lösen, dass nur der Bereich des Bildes neu gezeichnet wird, der sich verändert hat.
Das geht anscheinend aber nicht so einfach, da immer das komplette Bild neu gezeichnet wird, sprich, wenn im painEvent nichts gemacht wird, dann verschwindet auch der alte Balken!!!??
Gibts da eine elegante Lösung für?
ich bastel gerade an einem Widget, das einen Balken ausgeben soll, dessen Höhe proportional zu einem Wert ist.
Nun dachte ich, man könnte einfach die paintEvent-Methode überschreiben.
Da das Zeichnen den Prozessor allerdings nicht so sehr auslasten soll, wollte ich das so lösen, dass nur der Bereich des Bildes neu gezeichnet wird, der sich verändert hat.
Das geht anscheinend aber nicht so einfach, da immer das komplette Bild neu gezeichnet wird, sprich, wenn im painEvent nichts gemacht wird, dann verschwindet auch der alte Balken!!!??
Gibts da eine elegante Lösung für?
Zuletzt geändert von qtnub am 30. September 2007 17:44, insgesamt 1-mal geändert.
-
CaptnChaos
- Beiträge: 605
- Registriert: 28. Juni 2007 15:01
- Kontaktdaten:
Okay, in meinem Testcode sollte es erstmal so sein, dass sich der Balken nur erhöhen kann.
Allerdings wird der Balken gelöscht, wenn sich der Wert nicht erhöht. die paintEvent-Methode wird immer aufgerufen, wenn sich value geändert hat.
Allerdings wird der Balken gelöscht, wenn sich der Wert nicht erhöht. die paintEvent-Methode wird immer aufgerufen, wenn sich value geändert hat.
Code: Alles auswählen
void Anzeige::paintEvent(QPaintEvent *) {
if (value > oldValue) {
QPainter painter(this);
int yNeu = back.height() - value;
int height = value - oldValue;
painter.drawPixmap(0, yNeu, back.width(), height, (*imgLevel), 0, yNeu, back.width(), height);
oldValue = value;
painter.end();
}
}
-
CaptnChaos
- Beiträge: 605
- Registriert: 28. Juni 2007 15:01
- Kontaktdaten:
ok, der Header sieht so aus:
peak spielt erstmal keine Rolle, es geht erstmal nur darum, diesen Balken zum Laufen zu bekommen.
Das mit den 30 msec muss schon sein, da das ganze so ein Audiomixerprogramm werden soll. In einem alten Windowsprogramm läuft das auch mit 3 mal so vielen Elementen deutlich flüssiger.
Code: Alles auswählen
#ifndef ANZEIGE_H
#define ANZEIGE_H
#include <QWidget>
#include <QtGui>
class Anzeige : public QWidget
{
Q_OBJECT
public:
Anzeige(QPixmap *imgBackground, QPixmap *imgLevel, QPixmap *imgPeak, QRect back, QWidget *parent, QPoint offset = QPoint(0, 0));
~Anzeige();
void setValue(float v);
void update(int value, int peak);
void setImage(QPixmap *imgBackground, QPixmap *imgLevel, QPixmap *imgPeak);
private:
QPixmap *imgBackground;
QPixmap *imgLevel;
QPixmap *imgPeak;
int balkenX;
int balkenY;
float peakY;
QRect back;
int value;
int peak;
int oldValue;
int oldPeak;
protected:
void paintEvent(QPaintEvent *);
};
#endifCode: Alles auswählen
#include "Anzeige.h"
#include <iostream>
Anzeige::Anzeige(QPixmap *imgBackground, QPixmap *imgLevel, QPixmap *imgPeak, QRect back, QWidget *parent, QPoint offset) {
this->imgBackground = imgBackground;
this->imgPeak = imgPeak;
this->imgLevel = imgLevel;
this->back = QRect(back.x() + offset.x(), back.y() + offset.y(), back.width(), back.height());
setGeometry(this->back);
setParent(parent);
//this->setAutoFillBackground(false);
//this->setAttribute(Qt::WA_OpaquePaintEvent, false);
//this->setAttribute(Qt::WA_NoBackground, false);
peakY = 30;
value = 0;
peak = 0;
oldValue = 0;
}
Anzeige::~Anzeige() {
}
void Anzeige::setValue(float v) {
}
void Anzeige::paintEvent(QPaintEvent *) {
if (value > oldValue) {
QPainter painter(this);
int yNeu = back.height() - value;
int height = value - oldValue;
painter.drawPixmap(0, yNeu, back.width(), height, (*imgLevel), 0, yNeu, back.width(), height);
oldValue = value;
painter.end();
}
}
void Anzeige::update(int value, int peak) {
if ((value != this->value) || (peak != this->peak)) {
this->value = value;
//repaint();
int yNeu = back.height() - value;
int height = value;//value - oldValue;
this->repaint(0, yNeu, back.width(), height);
}
}
void Anzeige::setImage(QPixmap *imgBackground, QPixmap *imgLevel, QPixmap *imgPeak) {
if ((this->imgBackground != imgBackground) || (this->imgLevel != imgLevel) || (this->imgPeak != imgPeak)){
this->imgBackground = imgBackground;
this->imgLevel = imgLevel;
this->imgPeak = imgPeak;
}
}
Nach langem Stöbern in der Qt-Doku hab ich nun endlich einen eventuellen Lösungsansatz gefunden, der eventuell nicht der eleganteste ist, aber funktionieren müsste.
Mit den Zeilen:
kann man das Doublebuffering deaktivieren und außerdem die Einstellung, dass der Hintergrund des Widgets gelöscht wird, bevor das paintEvent aufgerufen wird. 
Mit den Zeilen:
Code: Alles auswählen
this->setAttribute(Qt::WA_NoSystemBackground, true);
this->setAttribute(Qt::WA_PaintOnScreen, true);
-
CaptnChaos
- Beiträge: 605
- Registriert: 28. Juni 2007 15:01
- Kontaktdaten:
ARGH!
Sry, aber was bitteschön soll ich mit den Dateien anfangen? Wenn das mehr als Klasse ist, die zu deinem Widget gehören und sogar noch Pixmaps eingebunden sind, solltest du enweder ein minimal lauffähiges Widget mit den Funktionen deiner Anwendung posten oder du lädst dein Projekt hoch.
Und worunter Programmierst du? Windows? Dann wird dir das :
nicht viel bringen. Lies ma nach was in der Doku steht. Und WA_NoSystemBackground wird auch nicht viel bringen. Versuch es mit den Standart WinApi Paint Funktionen, das geht wesentlich schneller als die PaintEngine von Qt, ist aber nich so schön. Um mit WinApi zu zeichnen brauchst du ein Handle auf den DC deines Widgets. Such mal schön in der Doku, unter QWidget, da wirst du dann was finden.
Sry, aber was bitteschön soll ich mit den Dateien anfangen? Wenn das mehr als Klasse ist, die zu deinem Widget gehören und sogar noch Pixmaps eingebunden sind, solltest du enweder ein minimal lauffähiges Widget mit den Funktionen deiner Anwendung posten oder du lädst dein Projekt hoch.
Und worunter Programmierst du? Windows? Dann wird dir das :
Code: Alles auswählen
this->setAttribute(Qt::WA_PaintOnScreen, true); Danke für die Mühe, es ja eigentlich darum, auszustellen, dass der Hintergrund des Widgets resetet wird, bevor das paintEvent ausgelöst wird.
Das ganze ist wohl nicht so einfach. Einfach auf Windows-Funktionen zurückgreifen, wäre eine Lösung, dann müsste ich aber ähnliches für alle anderen Systeme seperat machen, da das Prog am Ende auf allen Systemen lauffähig sein soll.
Ich werde mal weiterprobieren.
Warum WA_NoSystemBackground nicht so richtig funzt, weiß ich allerdings nicht.
Ich werde nochmal weiterprobieren, schließlich muss es irgendeine Lösung geben, sonst wäre Qt für umfangreiche, selbstdesignte Fenster ja kaum zu gebrauchen
.
Vielleicht könnte man die repaint-Methode überschreiben?
Das ganze ist wohl nicht so einfach. Einfach auf Windows-Funktionen zurückgreifen, wäre eine Lösung, dann müsste ich aber ähnliches für alle anderen Systeme seperat machen, da das Prog am Ende auf allen Systemen lauffähig sein soll.
Ich werde mal weiterprobieren.
Warum WA_NoSystemBackground nicht so richtig funzt, weiß ich allerdings nicht.
Ich werde nochmal weiterprobieren, schließlich muss es irgendeine Lösung geben, sonst wäre Qt für umfangreiche, selbstdesignte Fenster ja kaum zu gebrauchen
Vielleicht könnte man die repaint-Methode überschreiben?
-
CaptnChaos
- Beiträge: 605
- Registriert: 28. Juni 2007 15:01
- Kontaktdaten:
-
CaptnChaos
- Beiträge: 605
- Registriert: 28. Juni 2007 15:01
- Kontaktdaten:
schick mir mal den quellcode:
markus.kuenkler@gmx.de
markus.kuenkler@gmx.de
sry, ich war zwischenzeitlich im Urlaub, habe danach nochmal ein bisschen selbst herumprobiert und das Problem gelöst.
1) Also das Doublebuffering kann man deaktivieren, indem man im hintersten Widget(das Widget ohne parent) WA_NoSystemBackground aktiviert.
2)Außerdem bringt es enorme Performancevorteile, wenn man nur ein Widget hat, das sehr oft den paintEvent aufruft, anstelle von vielen kleinen.
-> Lösung: alle Balken in ein Widget zeichnen, Doublebuffering deaktiveren und beim Zeichnen des ganzen Widgets erstmal in einen Buffer zeichnen.
1) Also das Doublebuffering kann man deaktivieren, indem man im hintersten Widget(das Widget ohne parent) WA_NoSystemBackground aktiviert.
2)Außerdem bringt es enorme Performancevorteile, wenn man nur ein Widget hat, das sehr oft den paintEvent aufruft, anstelle von vielen kleinen.
-> Lösung: alle Balken in ein Widget zeichnen, Doublebuffering deaktiveren und beim Zeichnen des ganzen Widgets erstmal in einen Buffer zeichnen.