QPainter, Größe der Zeichnung bestimmen
-
Hallo,
ich habe mit QPainter eine Grafik erstellt (aus Linien, Kreisbögen, Rechtecken etc.) und kann die anzeigen und als SVG exportieren. Funktioniert alles recht gut. Zoomen und Verschieben auf dem Bildschirm habe ich auch geschafft. Im Moment scheitere ich an einer eigentlich (vermeintlich?) einfachen Aufgabe: ich möchte auf die gesamte Grafik zoomen. Dazu fehlt mir schlicht die Info über die minimalen und maximalen x- und y-Koordinaten, also von wo bis wo sich die Grafik erstreckt. clipBoundingRect() liefert mir die Größe des Fensters, nicht die Größe der Grafik.
Kann mir jemand bitte einen Hinweis geben? Ich hoffe ich muß das nicht alles von Hand nachführen.
Vielen Dank,
Michael -
Danke für den Hinweis.
Das liefert mir leider nur die Maße des Viewports zurück, den ich aber gerade anhand der aktuellen Zeichnungsmaße setzen will. Die Min- und Max-Koordinaten kann ich natürlich selber mitziehen, aber das ist nicht immer trivial. Bei einem Rechteck ist das einfach, aber schon bei einem Kreisbogen muß ich genaugenommen den Bogen selber nochmal berechnen, weil ich ja nur das umrandende Rechteck angebe.
Naja, dann krempel ich mal die Ärmel hoch und mach's selber. Trotzdem meine ich, daß diese Info irgendwo im QPainter verfügbar sein muß. -
@Michael58 said in QPainter, Größe der Zeichnung bestimmen:
Trotzdem meine ich, daß diese Info irgendwo im QPainter verfügbar sein muß.
Dann schau selbst nach
@Michael58 said in QPainter, Größe der Zeichnung bestimmen:
ich habe mit QPainter eine Grafik erstellt
Worauf malst du denn überhaupt?
Wenn du ein Widget zeichnest, kriegst du die Größe darüber...
Bei Pixmap kannst du auch die Größe ermitteln, da die Größe des Pixmaps/Bildes dann die Fläche ist...
Wenn du ein 100x100 PixMap erstellst, aber nur bei 42x42 einen blauen Punkt zeichnest, dann ist das PixMap trotzdem 100x100 groß und nicht 1x1 bzw nur der Punkt.
Falls du diese Größe meinst, musst du es selbst machen.Wie groß etwas in real ist, was du mit
QPainter
zechnest, hängt ja von mehreren Faktoren ab.
Ich denke nicht, dass du nur aus den vomQPainter
erstellten Linien selbst ermitteln kannst wie groß das "Gesamtwerk" auf der bemalten Fläche ist.Außerdem in welcher Einheit möchtest du die Größe bestimmen? Pixel? Zentimeter? Inch/Zoll?
Über das "Gerät"
device()
des Painters kriegst du die Größe der Fläche...
Und die meisten Objekte die durch ihren gemalten Inhalt definiert sind, haben ja auch dessen Größe (bzw. ein boundingRect, welches standardmäßig genau den Inhalt umschließt) -
Ich denke wir reden aneinander vorbei. Mir geht es nicht um die Größe des Widgets / der "Leinwand" sondern um die Größe der (Vektor-) Zeichnung. Durch Zoomen soll die entweder komplett oder als Ausschnitt auf dieser Leinwand dargestellt werden. Alternativ wird die Vektorgrafik dann auch als SVG exportiert. Nur dann kommen Längeneinheiten ins Spiel und dann transformiere ich entsprechend (auf 96 DPI, was wohl für SVG ein Standard ist).
Die Zeichnung erstelle ich tatsächlich in Millimeter. Wenn ich ein Rechteck von beispielsweise 100 mm x 200 mm zeichne, dann muß ich diese Größe und dessen Position wissen, um korrekt auf das Widget zu skalieren oder eben auch nur einen Ausschnitt davon darzustellen.
Ich denke das einfachste ist, ein paar Zeilen Code zu zeigen (von irgendwo kopiert):void Display::paintEvent(QPaintEvent * /* event */)
{
QPaintDevice *device ;
QPainter painter;
painter.begin(this);
device = painter.device() ;
vp_width = device->width() ;
vp_height = device->height() ;
painter.setRenderHint(QPainter::Antialiasing);
painter.setClipRect(QRect(0, 0, vp_width, vp_height));
painter.fillRect(QRect(0, 0, vp_width, vp_height), QColorConstants::Svg::lemonchiffon);
painter.setWindow(QRect(0, 0, (int) (vp_width/scale), (int) (vp_height/scale)));
painter.setViewport(x_min, y_min, vp_width, vp_height);
paint(painter);
painter.end();
}Das eigentliche Zeichnen der Vektorgrafik passiert in paint(). Da werden Linien, Rechtecke, Kreisbögen und Ellipsen gezeichnet. x_min und y_min wird durch Ziehen mit gedrückter rechter Maustaste verändert und damit kann ich die Grafik verschieben. Mit dem Mausrad ändere ich scale. Das klappt alles bestens. Jetzt will ich "einfach nur" mit einem Mausklick auf die komplette Grafik zoomen Dazu fehlen mir die kleinsten und die größten x- und y-Koordinaten meiner Vektorgrafik.
Ja klar, ich kann das auch selber nachführen und werde das wohl müssen. Wie schon erwähnt, ist das aber in Einzelfällen nicht ganz trivial, insbesondere wenn man's genau haben will. Ich werd's angehen.
Dennoch, vielen Dank für die Hilfe. -
@Michael58 said in QPainter, Größe der Zeichnung bestimmen:
Ich denke wir reden aneinander vorbei. Mir geht es nicht um die Größe des Widgets / der "Leinwand" sondern um die Größe der (Vektor-) Zeichnung
Nee ich hab das schon verstanden.
Aber es macht meiner Meinung nach keinen Sinn bzw. ist nicht möglich, da ein "painter" nur eine Größe bzw. Abmessung in Kombination mit einem "device" und einer Canvas (Leinwand) besitzt... anders lässt sich die Größe nicht bestimmen.
Wenn ich ein Rechteck von beispielsweise 100 mm x 200 mm zeichne, dann muß ich diese Größe und dessen Position wissen, um korrekt auf das Widget zu skalieren oder eben auch nur einen Ausschnitt davon darzustellen.
Wenn du ein Rechteckt mit 100x200 zeichnest, hast du eine Größe von 100x200... Problem gelöst.
Wenn du innerhalb dieses Rechtecks irgendwelche Formen zeichnest, weißt du beim Zeichnen ja auch deren Größe, sonst könntest du sie ja nicht zeichnen...
Wenn du das große Ganze transformierst oder skalierst, musst du von der Ursprungsgröße und der entsprechenden Transformation ausgehen und die zurückrechnen (ein 2x2 Rechteck bei 100%, wäre vereinfacht gesagt 4x4 bei 200%)
Die Zeichnung erstelle ich tatsächlich in Millimeter. Wenn ich ein Rechteck von beispielsweise 100 mm x 200 mm zeichne, dann muß ich diese Größe und dessen Position wissen, um korrekt auf das Widget zu skalieren oder eben auch nur einen Ausschnitt davon darzustellen.
Auf das Widget skalieren ist easy, weil du mit
boundingRect()
,height()
,width()
und/oder demviewport()
die Informationen über den aktuellen Zustand des Widgets (Größe und Position) holen kannst.Ich denke das einfachste ist, ein paar Zeilen Code zu zeigen (von irgendwo kopiert)
Wie "von irgendwo kopiert"?!
Ist es jetzt dein Code den du nutzt oder nicht?paint(painter);
Wo hast du diese Funktion her?!
Weder inQWidget
noch inQPainter
oderQPaintDevice
gibt es eine Funktion diepaint
heißt.
Daher lässt sich das nicht reproduzieren. -
Wir drehen uns im Kreis, deswegen werde ich jetzt tatsächlich meine eigenen Funktionen schreiben und die Koordinaten mitführen. Statt „painter.fillRect(rect);“ werde ich dann halt MyfillRect(rect) aufrufen und mir dort die min- und max-Koordinaten merken. Wie gesagt ist das ja auch bei einem Rechteck trivial, bei einer Ellipse aber schon nicht mehr, weil die gegebenen Eckpunkte ja nicht die Eckpunkte der Zeichnung sein müssen.
Ich will dennoch (für’s Archiv) deine Fragen beantworten:
@Pl45m4 said in QPainter, Größe der Zeichnung bestimmen:
Wenn du ein Rechteckt mit 100x200 zeichnest, hast du eine Größe von 100x200... Problem gelöst.
Es geht um dutzende Linien, Rechtecke und Ellipsen. Wie oben schon gesagt, ist das gerade bei Ellipsen nicht trival.
@Pl45m4 said in QPainter, Größe der Zeichnung bestimmen:
Auf das Widget skalieren ist easy
Ja, das macht ja schon mein Beispielcode. Es geht aber um die Zeichnung, nicht um die Leinwand. Ich muß die Größe der Zeichnung wissen um auf die Leinwand zu skalieren.
@Pl45m4 said in QPainter, Größe der Zeichnung bestimmen:
Wie "von irgendwo kopiert"?!
Ich hab’s nochmal rausgesucht, der Beispielcode ist von hier: https://doc.qt.io/qt-5/qtsvg-svggenerator-example.html. Der Rest, also die Funktion paint(), ist natürlich von mir geschrieben. Was darin passiert, ist aber für meine Frage völlig unerheblich. Es sind viele Aufrufe der QPainter-Funktionen (https://doc.qt.io/qt-6/qpainter.html).
-
@Michael58 said in QPainter, Größe der Zeichnung bestimmen:
Ich hab’s nochmal rausgesucht, der Beispielcode ist von hier: https://doc.qt.io/qt-5/qtsvg-svggenerator-example.html.
Hätte man auch eher erwähnen können dass du kein widget sondern in einer
QGraphicsView
paintest ;-)
Ja dann ist das mit derpaint()
Funktion auch klar, weil die dort implementiert ist und aus dem Beispiel ist. Also keine Qt Funktion ist.Aber trotzdem:
Dann wäre es ja wirklich recht simple.
DasQGraphicsSvgItem
ist einQGraphicsObject
und die haben alle einboundingRect
, welches den gesamten Inhalt umschließt... d.h. es sind die äußeren Abmessungen deines "Items".Egal wie "unförmig" dein Item und das was du zeichnet ist, das boundingRect muss alles umschließen damit es vernünftig mit anderen Items und/oder der Szene interagieren kann.
D.h. wenn das vernünftig implementiert ist, hast du direkt die richtige Größe bzw die echten Abmessungen deiner Zeichnung (des Items) und kannst auf dessen Position und Größe fokussieren. -
Danke nochmal, ich muß das jetzt erst mal sortieren, dazu komme ich aber frühestens am Wochenende. Nur nochmal eins: ich habe zwei unabhängige Ausgabewege für meine Grafik (steht schon im ersten Satz): den Bildschirm (ein Widget? Ich weiß es nicht) und das SVG-File. Zoomen will ich natürlich nur den Bildschirm, nicht das SVG-File. Eigentlich passiert alles auf dem Bildschirm und erst am Ende, wenn alles stimmt, wird die Grafik als SVG exportiert. Vielleicht kann ich das aber trotzdem nutzen, um die Größe festzustellen. Laß mich mal weiter experimentieren, ich krieg das schon irgendwie hin. Ich hatte es mir halt einfacher vorgestellt. Das Problem müsste doch jeder haben oder nicht?
Vielleicht hilft's auch noch zum Verständnis: das SVG-File lese ich entweder mit ESTLCAM ein und erzeuge ein CAM-File zum Fräsen oder ich lese es mit FreeCAD ein, extrudiere es und erzeuge ein 3mf-File für den 3D-Drucker. -
-
@Michael58 said in QPainter, Größe der Zeichnung bestimmen:
jeweils die Eckpunkte meiner Grafik mitziehen. Auch wenn ich das mehr als "workaround" denn als "Lösung" sehe
Aber wäre das nicht genau die "Größe" bzw. das Rect vom
DisplayWidget
(um beim Beispiel zu bleiben)?
Außer du meinst mit "Zeichnung" dass du z.B. von dem "Haus" welches in der Grafik zu sehen ist, redest...
Da müsstest du dann, wie du sagst, selbst, zum Zeitpunkt des Zeichnens die Koordinaten bzw. Abmessungen abspeichern, weil es ja innerhalb der gesamten gemalten Fläche ist und du später den Zugriff auf die Einzel-"Striche" und "Formen" des Painters verlierst :)Aber gut, dass es geklappt hat.
Eine andere Möglichkeit wäre eben noch deine "innere" Zeichnung als eigenes Widget zu behandeln, welches dann immer die maximale Größe besitzt... wenn du dann dein "Zeichnung" die du als SVG exportieren willst auf einen Hintergrund malst (wie im Beispiel das
Window
, dann hast du mit der Widgetsize()
gleichzeitig die Abmessungen deiner Zeichnung (vorausgesetzt der Painter des gemalten Widgets zeichnet immer ohne "background" bzw. Rand.
(aber das bestimmst du ja selbst und den Rand müsstest du dann wieder herausrechnen)
Im Beispiel wird ja erst der blaue Hintergrund gezeichnet und dann das Haus und z.B. der Mond darüber.