QWidget + QPainter und zoom

Alles rund um die Programmierung mit Qt
Antworten
fabiS
Beiträge: 9
Registriert: 6. Oktober 2010 08:46

QWidget + QPainter und zoom

Beitrag von fabiS »

Hi,

ich habe hier ein kleines Problem mit einem QWidget.
Ich parse hier eine Datei die Informationen zu Zeichungselementen(Kreise, Polylinen, Kreisbögen, etc.) enthält.
Diese Informationen verarbeitete ich dann mit einem QPainter, der die Elemente auf ein QWidget zeichnet.

Das Zeichnen wird mit der Methode

Code: Alles auswählen

void drawWidget::paintEvent(QPaintEvent *event)
gestartet.

Das was gezeichnet wird, ist von der Qualität eigentlich sehr gut.
Jetzt gibt es nur einige Probleme, wie kann ich verhindern das bei jedem vergrößern bzw. verkleinern die komplette Zeichung neu geszeichnet wird?

Desweiteren würde ich gerne wissen wie ich einen effizienten Zoom implementieren kann, ohne das Bild mit einem veränderten scale im QPainter neu zeichnen zu müssen.

Ich habe mir auch schon überleget das ganze mit einem QGLWidget umzusetzen, leider schien das Widget immer abzustürzen, sobald ich eine große Menge an Daten darauf zeichnen wollte.

Vielen Dank für eure Hilfe,

lg,
Fabi
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Wenn du die Größe des Widgets verändert, muss der Inhalt des Widgets neu gezeichnet werden, wenn der Inhalt auch skaliert werden soll. Das Widget bekommt hier ein resizeEvent. Beachte:
The widget will be erased and receive a paint event immediately after processing the resize event. No drawing need be (or should be) done inside this handler.
Ich nehme an das QPaintEvent::rect() ist dann gleich deinem Widget::rect, kannst es dir ja mal ausgeben lassen.

Aber eine andere Frage: Liest du im paintEvent die Datei ein? Das wäre eine extreme Performancebremse, Festplattenzugriffe sind laaaangsaaaam. Entweder du speicherst dir das was du liest in einem eigenen Format, oder du zeichnest einmal beim Einlesen der Datei in ein QPicture, welches du dir als Member deiner Klasse hältst, und zeichnest im paintEvent via QPicture::play(). Wenn dein Content dynamisch ist (Elemente veschieben, hinzufügen, Grafik-Effekte, ...) kannst du auch mal Richtung Qt Graphics View schauen.
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
fabiS
Beiträge: 9
Registriert: 6. Oktober 2010 08:46

Beitrag von fabiS »

Ersteinmal vielen Dank für die Hilfe.

Es wäre echt wichtig das Bild nicht physisch auf der Platte zwischen zu speichern.
Ich habe den Ansatz mit dem QPicture jetzt mal versucht. Wenn ich nur einen Testzeichung (einen Text mit Hallo Welt) mache, dann Funktioniert das ganze so wie du es beschrieben hast, wenn ich allderdings meine Zeichung in das QPicture lade, passiert garnichts. Könnte das an der Datenmenge liegen.

QPicture::isNull() sagt das das Bild einen Inhalt hat.



Könnte ich die zoomerei auch mit einem QGLWidget realisieren?
Hat da vielleicht jemand ein Beipsiel oder eine Idee?

Vielen Dank für eure Hilfe....

lg,
Fabi
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Natürlich kannst die Zoomerei auch mit einem QGLWidget machen. Aber noch wichtiger wäre, wenn du mal Code posten könntest. Denn wenn du versuchst, dein eigenes Format in ein QPicture zu laden, geht das natürlich nicht! SVG als Zwischenformat geht auch, ich weiß halt nicht wg. Performance, ob svg oder QPicture schneller ist (->testen). Ansonsten eben Qt GraphicsView Framework versuchen.

Und wenn etwas nicht geht postet man konkrete Fehlermeldungen (QPicture::load() hat einen return, auf der Konsole findest du auch interassante Meldungen, wenn etwas abstürzt schaust du dir das Problem mit einem Debugger an).
fabiS
Beiträge: 9
Registriert: 6. Oktober 2010 08:46

Beitrag von fabiS »

@franzf:

vielen dank erstmal, das mit dem Code werde ich nacholen.

ich habe mich jetzt für die Variante mit SVG entscheiden.
Ich nutze als PaintDevice den QSvgGenerator.
Das klappt bis jetzt auch wunderbar, jetzt hätte ich nur noch eine Frage, kann ich einem QSvgRenderer auch einen QSvgGenerator übergeben, damit ich das SVG nicht auf die Platte zwischenspeichern muss.

Vielleicht das SVG iwie in ein QByteArray schreiben....

Wenn das gehen würde wäre die Lösung wirklich optimal.

lg,
Fabi
fabiS
Beiträge: 9
Registriert: 6. Oktober 2010 08:46

Beitrag von fabiS »

So, dass mit dem Byte Array hat funktioniert.

Jetzt habe ich aber wieder ein Problem.
Gibt es eine Effiziente Möglichkeit für einen Zoom, ohne das das SVG jedesmal neu auf mein AnzeigeWidget gezeichnet wird.

Ich habe mich bei meinem Programm sehr stark an dem Beispiel hier:
http://doc.qt.nokia.com/4.1/painting-svgviewer.html
orientiert.

Meine Zoomfunktion sieht folgendermaßen aus:

Code: Alles auswählen

const double d_zoomFac = 0.1;
	
	/*Aktuelle größe auslesen und in ein QSize Objekt speichern*/
	QSize size = MyRenderer->defaultSize();
	
	/*Aktuelle größe zwischenspeichern*/
	int i_width = size.width();
	int i_height = size.height();
	
	/*Auslesen ob das Mausrad nach vorne oder nach hinten gedreht wurde.*/
	if(event->delta() > 0)
	{
		/*Mausrad nach vorne*/
		i_width = int( this->width() + (this->width() * d_zoomFac) );
		i_height = int( this->height() + (this->height() * d_zoomFac) );
	}
	else
	{
		/*Mausrad nach hinten*/
		i_width = int( this->width() - (this->width() * d_zoomFac) );
		i_height = int( this->height() - (this->height() * d_zoomFac) );
	}
	
	/*Größe des Widget verändern*/
	resize(i_width, i_height);		
Jetzt wird ja aber bei jedem Resize das paintEvent des QWidget ausgelöst und bei sehr großen Dateien (> 3 MB) dauert der Zoom dann ewig.
Das ganze ist dann nicht mehr perfomant genug.
Bei kleinen Dateien (300 KB) geht das ganze echt super flott.

Könnte man was mit dem Zoom machen wenn ich gleich ein QSvgWidget verwende?

Hoffe ihr könnt mir helfen.

Vielen Dank.

lg,
Fabi
Antworten