große Liniengrafiken: QPainter / QGraphicsView?

Alles rund um die Programmierung mit Qt
Antworten
gk_17
Beiträge: 37
Registriert: 4. Oktober 2009 19:20

große Liniengrafiken: QPainter / QGraphicsView?

Beitrag von gk_17 »

Moin,

ich möchte wieder einmal um einen Tipp bitten, der mir hoffentlich tagelanges Ausprobieren erspart.

Ich will eine technische Zeichnung darstellen, die aus sehr vielen Linien besteht. Daneben gibt es eine Tabelle, deren Einträge Positionen auf der Zeichnung darstellen. Bei Selektion eines Tabelleneintrages muss diese Position in der Zeichnung dargestellt werden (kleines Kästchen oder so).

Ich habe es implementiert mittels paintEvent auf einem QFrame. Die paint()-Methode zeichnet alle Linien, und wenn ein Tabellenelement selektiert wurde, auch dieses. Ich war erstaunt, wie schnell das geht, aber leider nicht schnell genug. Beim scrollen mit Pfeiltasten durch die Tabelle bremst das wiederholte Zeichnen aller Daten sehr aus.

Nun habe ich angefangen, das Gleiche mittels QGraphicsView zu implementieren. Die zu markierenden Positionen füge ich der scene hinzu und lösche sie anschließend wieder. Das ist auf jeden Fall schnell genug, lässt aber so viele Fragen/Probleme offen, dass ich nicht recht weiter weiß.

Dazu brauche ich einen Tipp: wie implementiert man die beschriebene Funktionsweise am besten? Kann man die erstere, für mich einfachere Methode beschleunigen?

Oder soll ich versuchen, meine Probleme mit QGraphicsView zu lösen:
- die Skalierung der scene ändert sich, wenn eine der temporär dargestellten Positionen weit neben der scene liegt
- ich muss die temporären Positionen als items der scene hinzufügen, obwohl sie eigentlich unabhängig von dieser immer die gleiche Größe (in Pixeln) haben sollen
- ich habe noch nicht die geringste Ahnung, wie ich ein mit der Maus verschiebbares Fadenkreuz implementieren soll

Freue mich über eine Anregung,
Grüße,
gk_17
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

QGraficsView
warum verschiebst du nicht einfach ein "dasIstMeineSelektierteZelleMarkerItem" auf dem View herum wenn du nur eins darstellen willst. Wenn du es nicht brauchst : item->hide(); wenn dus wieder brauchst: item->show(); Es gibt beim Graphicsitem ein property das bestimmt ob das ding mitscaliert oder nicht --> API lesen. Mauscurser gibts vorgefertigte ... Fadenkreuz ist ja fast Standard also auch API lesen ;)


Bei Mausklick kann man Scrollen so einstellen das die geklickte Position im Zentrum liegt ... vielleicht kannst du eine Mausklick an der Stelle simulieren die mit dem Item der Tabelle übereinstimmt?
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
Uwe
Beiträge: 176
Registriert: 9. Oktober 2005 13:37
Wohnort: München

Beitrag von Uwe »

padreigh hat geschrieben: Mauscurser gibts vorgefertigte ... Fadenkreuz ist ja fast Standard also auch API lesen ;)
Schau Dir mal das Qwt Projekt ( http://qwt.sourceforge.net/ ) an. Da gibt es eine Klasse QwtPicker, die ein Fadenkreuz ( und diverse andere Gummibänder ) als Widget Overlay implementiert. Im bode Beispiel kannst Du sehen wie man die benutzt.

QwtPicker hat keine wirklichen Abhängigkeiten zu den anderen Qwt Klassen. D.h. Du kannst die Qwt Abhängigkeiten recht einfach entsorgen und den Code bei Dir integrieren. Nimm eine Version von Qwt 6 - da sind dann auch keine Qt3 Kompatibilitäts Klassen mehr dabei.

Vielleicht ein paar Hinweise zur Performance: Qt rendert bevor es clippt - das ist eine ganz katastrophale Performancebremse bei gezoomten Darstellungen. D.h. Du kannst eventuell viel erreichen, wenn Du das Clipping selber in die Hand nimmst. Auch hier findest Du im Qwt Projekt Hilfe: QwtClipper bietet eine Implementierung vom Sutherland-Hodgeman Algorithmus.

Für die Entscheidung QGraphicsView vs. QPainter solltest Du bedenken, dass QGraphicsView nur ein Aufsatz auf QPainter ist und nichts grundlegend Anderes implementiert. D.h. wenn Du QGV verwenden willst, sollte in dieser Schicht auch etwas dabei sein, was Dir das Leben einfacher macht. Ansonsten bleibt nur eine Limitierung bei der Kontrolle über den Zeichenvorgang übrig.

Uwe
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag von padreigh »

achja hier gabs vor kurzen noch eine Frage zu Schnell + QGraphisc - wenn es sehr viele Linien gibt (und die sich nicht laufend ändern) mag es lohnen alle Linien als Items ins QGraficsView zu packen, dir dann ein QPixmap davon zu machen, dann alle bisherigen Items zu verstecken und dann nur ein QGraficViewPixmapItem mit dem "Photo" aller Linien darzustellen - Vorteil: Statt 1000 Linien "zeichnet" er nur ein Bild. Weniger Klipping = vieeeel performanter. Wenn du auch Linien ein/ausblenden willst musst du halt das Pixmap jedes Mal neu erzeugen...

Guckstdu hier: http://www.qtforum.de/forum/viewtopic.php?p=66032#66032
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
Uwe
Beiträge: 176
Registriert: 9. Oktober 2005 13:37
Wohnort: München

Beitrag von Uwe »

padreigh hat geschrieben:achja hier gabs vor kurzen noch eine Frage zu Schnell + QGraphisc - wenn es sehr viele Linien gibt (und die sich nicht laufend ändern) mag es lohnen ...
Der entscheidende Punkt ist selber zu verstehen was was kostet und entsprechend der individuellen Situation die richtige Implementierung zu wählen. In keinem Fall sollte man glauben, daß QGraphicsView einem das abnimmt.

In Verbindung mit Zoomen/Scrollen ( nehme an dass das hier eine Rolle spielt ) ist die Lösung mit dem Pixmap eher untauglich. Zum einen wird das Bild natürlich viel zu gross, wenn man tiefer rein zoomt und es muß jeweils neu berechnet werden, wenn man die Skalierung ändert.

Um eine wirklich Erfolg versprechende Empfehlung geben zu können müssten wir aber mehr über die Details der Aufgabenstellung wissen, aber als grundsätzliche Faustregel gilt: soviel wie möglich vor dem eigentllichen Zeichenvorgang aussortieren - und so viel wie möglich vorab ( Resize/Rescale Operationen - nicht im Paint Event ) berechnen und zwischen speichern.

Uwe
nhs
Beiträge: 6
Registriert: 27. Februar 2011 20:49
Wohnort: Hessen
Kontaktdaten:

Beitrag von nhs »

@gk_17: Auf welchen Platform läuft deine Application ?
Qt bietet verschiedene Paint-Engine. Wenn du nicht explizit angibt wird "native" Paint-Engine genommen. Auf X11 ist das Zeichnen von Lines vielschneller wenn du die "raster" - Paint-Engine nimmst. Das ist die Pure Software Paint Engine von Qt. Das kannst Du mit der static Methode QApplication::setGrapgicssystem("raster") (WICHTIG: DAS SOLL VOR DER INSTANZIERUNG VON QApplication AUFGERUFEN WERDEN).
Ansonst unter Linux kannst Du auch dein Programm mit der commandline Option "-graphicssystem=raster" probieren.
Recht haben bedeutet nicht, auch Recht zu bekommen
nhs
Beiträge: 6
Registriert: 27. Februar 2011 20:49
Wohnort: Hessen
Kontaktdaten:

Beitrag von nhs »

Ich habe noch was vergessen. Wenn Du wenig Text zeichnen musst, kannst Du auch mit "opengl" Engine probieren. Das geht auch mit der Option "-graphicssystem=opengl"
Recht haben bedeutet nicht, auch Recht zu bekommen
Uwe
Beiträge: 176
Registriert: 9. Oktober 2005 13:37
Wohnort: München

Beitrag von Uwe »

nhs hat geschrieben:Auf X11 ist das Zeichnen von Lines vielschneller wenn du die "raster" - Paint-Engine nimmst. Das ist die Pure Software Paint Engine von Qt.
Also in Software rendern ist mit Sicherheit kein guter Rat zur Beschleunigung. Eine hardwarebeschleunigte 2D Graphik über X11 ( sofern mit vernünftigen Treibern unterstützt ) ist dann doch sowas von vorzuziehen.

Uwe
nhs
Beiträge: 6
Registriert: 27. Februar 2011 20:49
Wohnort: Hessen
Kontaktdaten:

Beitrag von nhs »

Uwe hat geschrieben:
nhs hat geschrieben:Auf X11 ist das Zeichnen von Lines vielschneller wenn du die "raster" - Paint-Engine nimmst. Das ist die Pure Software Paint Engine von Qt.
Also in Software rendern ist mit Sicherheit kein guter Rat zur Beschleunigung. Eine hardwarebeschleunigte 2D Graphik über X11 ( sofern mit vernünftigen Treibern unterstützt ) ist dann doch sowas von vorzuziehen.

Uwe
@Uwe, Du hast Recht. Das kann man wie vom obigen Vorschlag von mir mit -graphicssystem="opengl" Engine erreichen. Für einfache Linienzeichnung mit Qt unter X11 ist es aber nicht immer die beste Wahl. Man muss ausprobieren halt.

// edit franzf: Für den Beitrag bbcode aktiviert ;)
Recht haben bedeutet nicht, auch Recht zu bekommen
Antworten