SVG "interaktiv" mit Qt verwenden
-
chrislo1976
- Beiträge: 105
- Registriert: 24. Februar 2008 09:45
SVG "interaktiv" mit Qt verwenden
Hallo zusammen!
Ich hätte heue eine Frage bezüglich der Verwendung von SVG mit Qt4.
Die verschiedenen SVG-Klassen von Qt hab ich mir schon angeschaut, ein paar Beispiele dazu auch.
Ich konnte daraus aber leider nicht ermitteln ob sich mein Vorhaben vollständig realisieren lässt.
Deshalb hab ich mir gedacht, frag ich hier mal nach ob jemand sowas schon realisiert hat oder überhaupt angegangen ist:
Ich möchte ein SVG-Bild zeichnen (eher einfach, nur ein paar einfache Objekte) und dies in Qt in ein Fenster laden. Was gehen sollte, ist dieses Bild dann dynamisch zu verändern bzw. in veränderter Form neu zu erstellen. Was ich dann vor allem benötigen würde, ist die Information auf welches Element der Bediener geklickt hat.
Es sollte im Idealfall so sein dass der Bediener ein gewisses Objekt anwählen kann und dann ggf. besondere Informationen dazu erhält. Dieses SVG-Objekt steht z.B. für eine Maschine in einer Anlage.
Ich hab das mousePressEvent schon abgefangen, und damit die Koordinaten ausgelesen, allerdings hab ich es nicht geschafft damit sicher zu prüfen ob sich diese Koordinaten innerhalb eines SVG-Objektes befinden. Denn wenn ich z.B. das Fenster in der Größe ändere, bleiben die Koordinaten die ich mit QSvgRenderer::boundingRect() auslesen kann immer gleich.
Kann mir da jemand einen leichten Stoß in die richtige Richtung geben?
Oder "HALT" schreien wenn das so sowieso nicht möglich ist???
DANKE!
Gruß,
Christian
Ich hätte heue eine Frage bezüglich der Verwendung von SVG mit Qt4.
Die verschiedenen SVG-Klassen von Qt hab ich mir schon angeschaut, ein paar Beispiele dazu auch.
Ich konnte daraus aber leider nicht ermitteln ob sich mein Vorhaben vollständig realisieren lässt.
Deshalb hab ich mir gedacht, frag ich hier mal nach ob jemand sowas schon realisiert hat oder überhaupt angegangen ist:
Ich möchte ein SVG-Bild zeichnen (eher einfach, nur ein paar einfache Objekte) und dies in Qt in ein Fenster laden. Was gehen sollte, ist dieses Bild dann dynamisch zu verändern bzw. in veränderter Form neu zu erstellen. Was ich dann vor allem benötigen würde, ist die Information auf welches Element der Bediener geklickt hat.
Es sollte im Idealfall so sein dass der Bediener ein gewisses Objekt anwählen kann und dann ggf. besondere Informationen dazu erhält. Dieses SVG-Objekt steht z.B. für eine Maschine in einer Anlage.
Ich hab das mousePressEvent schon abgefangen, und damit die Koordinaten ausgelesen, allerdings hab ich es nicht geschafft damit sicher zu prüfen ob sich diese Koordinaten innerhalb eines SVG-Objektes befinden. Denn wenn ich z.B. das Fenster in der Größe ändere, bleiben die Koordinaten die ich mit QSvgRenderer::boundingRect() auslesen kann immer gleich.
Kann mir da jemand einen leichten Stoß in die richtige Richtung geben?
Oder "HALT" schreien wenn das so sowieso nicht möglich ist???
DANKE!
Gruß,
Christian
-
chrislo1976
- Beiträge: 105
- Registriert: 24. Februar 2008 09:45
Danke für den Tipp!
Hab in der Zwischenzeit von einem Kollegen das Qt Jambi Beispielprogramm SVG Card Deck bekommen.
Dort wird mehr oder weniger genau das gemacht was ich brauchen würde, eben auch mit dem von dir erwähnten Graphics-View-System.
Werd mal versuchen das auf C++ umzusetzen.
Gruß,
Christian
Hab in der Zwischenzeit von einem Kollegen das Qt Jambi Beispielprogramm SVG Card Deck bekommen.
Dort wird mehr oder weniger genau das gemacht was ich brauchen würde, eben auch mit dem von dir erwähnten Graphics-View-System.
Werd mal versuchen das auf C++ umzusetzen.
Gruß,
Christian
-
chrislo1976
- Beiträge: 105
- Registriert: 24. Februar 2008 09:45
Hallo zusammen!
Hab inzwischen das QtJambi-Programm mehr oder weniger (zumindest vom Prinzip her) auf C++ portiert:
mainwindow.cpp:
svgobject.h :
svgobject.cpp :
In dem SVG-File das geladen wird sind einfach nur 3 Rechtecke enthalten die ROT, GELB und GRUEN heissen.
Mit diesem Code schaffe ich es Events für die verschiedenen SVG-Objekte abzufangen, z.B. mousePressEvent, hoverEnterEvent und hoverLeaveEvent. So weit, so gut!
Allerdings habe ich damit das Problem dass mir so alle Objekte in den Mittelpunkt der Anzeige verschoben werden, und nicht dort angezeigt werden wie es in der original SVG-Datei gezeichnet war.
Mit dem
stelle ich nur sicher dass die Objekte nebeneinander liegen (zum Test).
Hab dann versucht das File so zu laden:
So werden die Objekte zwar an der richtigen Position angezeigt, aber ich bekomme keine Events mehr für die Objekte...
Hat jemand eine Idee was ich anders machen könnte um mein Ziel zu erreichen?
Gruß,
Christian
Hab inzwischen das QtJambi-Programm mehr oder weniger (zumindest vom Prinzip her) auf C++ portiert:
mainwindow.cpp:
Code: Alles auswählen
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "svgobject.h"
#include <QSvgRenderer>
#include <QGraphicsSvgItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsSvgItem>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindowClass)
{
ui->setupUi(this);
QStringList list;
list << "ROT" << "GELB" << "GRUEN";
QGraphicsScene* scene = new QGraphicsScene();
QGraphicsView* view = new QGraphicsView();
view->setScene(scene);
QSvgRenderer* renderer = new QSvgRenderer(QString("D:\\Projekte\\Qt_Projekte\\svgtest\\pic.svg"), parent);
QList<SvgObject>* objects = new QList<SvgObject>;
for (int i = 0; i < list.count(); ++i)
{
SvgObject* item = new SvgObject(list.at(i), renderer);
scene->addItem(item);
item->translate(150.0 * (i-1), 0);
}
this->setCentralWidget(view);
}
MainWindow::~MainWindow()
{
delete ui;
}
Code: Alles auswählen
#ifndef SVGOBJECT_H
#define SVGOBJECT_H
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSvgItem>
class SvgObject : public QGraphicsSvgItem
{
public:
SvgObject::SvgObject(QString id, QSvgRenderer* renderer, QWidget* parent = 0);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=0);
private:
double opacity;
protected:
void hoverEnterEvent(QGraphicsSceneHoverEvent* event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent* event);
void mousePressEvent(QGraphicsSceneMouseEvent* event);
};
#endif // SVGOBJECT_H
Code: Alles auswählen
#include "svgobject.h"
SvgObject::SvgObject(QString id, QSvgRenderer* renderer, QWidget* parent)
{
setElementId(id);
setSharedRenderer(renderer);
setAcceptHoverEvents(true);
opacity = 1.0;
}
void SvgObject::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
{
opacity = 0.5;
update();
}
void SvgObject::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
{
opacity = 1.0;
update();
}
void SvgObject::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
rotate(30.0);
update();
}
void SvgObject::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setOpacity(opacity);
QGraphicsSvgItem::paint(painter, option, widget);
}
Mit diesem Code schaffe ich es Events für die verschiedenen SVG-Objekte abzufangen, z.B. mousePressEvent, hoverEnterEvent und hoverLeaveEvent. So weit, so gut!
Allerdings habe ich damit das Problem dass mir so alle Objekte in den Mittelpunkt der Anzeige verschoben werden, und nicht dort angezeigt werden wie es in der original SVG-Datei gezeichnet war.
Mit dem
Code: Alles auswählen
item->translate(150.0 * (i-1), 0);Hab dann versucht das File so zu laden:
Code: Alles auswählen
ui->setupUi(this);
QStringList list;
list << "ROT" << "GELB" << "GRUEN";
QGraphicsScene* scene = new QGraphicsScene();
QGraphicsView* view = new QGraphicsView();
view->setScene(scene);
QGraphicsSvgItem* gitem = new QGraphicsSvgItem(QString("D:\\Projekte\\Qt_Projekte\\svgtest\\pic.svg"));
scene->addItem(gitem);
// QSvgRenderer* renderer = new QSvgRenderer(QString("D:\\Projekte\\Qt_Projekte\\svgtest\\pic.svg"), parent);
QList<SvgObject>* objects = new QList<SvgObject>;
for (int i = 0; i < list.count(); ++i)
{
SvgObject* item = new SvgObject(list.at(i), gitem->renderer());
// scene->addItem(item);
// item->translate(150.0 * (i-1), 0);
}
this->setCentralWidget(view);
Hat jemand eine Idee was ich anders machen könnte um mein Ziel zu erreichen?
Gruß,
Christian
Zuletzt geändert von chrislo1976 am 24. Februar 2009 07:57, insgesamt 1-mal geändert.
Hallo Christian,
das selbe Problem hatte ich auch mal und hab es dadurch gelöst das ich das Scene-Rect gesetzet habe: QGraphicsScene#sceneRect-Property.
Jedoch weiß ich nicht ob das wirklich der angedachte Weg ist die Größe der "Zeichenfläche" so zu setzen. Mir wäre da auch eine Funktion lieber die sich an die Größe des Parent orientiert oder so(maybe: QGraphicsScene#fitSceneRectTo(QWidget)). Denn wenn Du ein sehr großes Rect definierst, größer als die größtmögliche darstellbare größe dann bekommt man Scrollbalken, was durchaus richtig ist da QGraphicsView wiederum eine QAbstractScrollArea ist.
Grad beim schreiben hatte ich eine Idee wie man das eventuell mit dem parent lösen könnte ... ich gugge
Gut Schuß
VuuRWerK (auch ein Christian)
das selbe Problem hatte ich auch mal und hab es dadurch gelöst das ich das Scene-Rect gesetzet habe: QGraphicsScene#sceneRect-Property.
Jedoch weiß ich nicht ob das wirklich der angedachte Weg ist die Größe der "Zeichenfläche" so zu setzen. Mir wäre da auch eine Funktion lieber die sich an die Größe des Parent orientiert oder so(maybe: QGraphicsScene#fitSceneRectTo(QWidget)). Denn wenn Du ein sehr großes Rect definierst, größer als die größtmögliche darstellbare größe dann bekommt man Scrollbalken, was durchaus richtig ist da QGraphicsView wiederum eine QAbstractScrollArea ist.
Grad beim schreiben hatte ich eine Idee wie man das eventuell mit dem parent lösen könnte ... ich gugge
Gut Schuß
VuuRWerK (auch ein Christian)
Es gibt nur 3 natürliche Feinde des Programmierers: Tageslicht, frische Luft und das unerträgliche Gebrüll der Vögel.
Oft ist die Ursache des schwarzsehens lediglich ein verrutschen des Bretts vorm Kopf =)
Oft ist die Ursache des schwarzsehens lediglich ein verrutschen des Bretts vorm Kopf =)
Also hier das automatische anpassen der Größe des Views, beachtet wird auch die Größe die die items einnehmen:
def:
impl:
Gut Schuß
VuuRWerK
def:
Code: Alles auswählen
class DerivedQGraphicsView : public QGraphicsView {
protected:
virtual void resizeEvent(QResizeEvent*);
};
Code: Alles auswählen
void DerivedQGraphicsView::resizeEvent(QResizeEvent *resizeEvent) {
QSize size = resizeEvent->size();
const QRectF rect = scene()->itemsBoundingRect();
if (rect.width() > size.width())
size.setWidth(rect.width());
if (rect.height() > size.height())
size.setHeight(rect.height());
setSceneRect(QRectF(0, 0, size.width(), size.height()));
}
VuuRWerK
Es gibt nur 3 natürliche Feinde des Programmierers: Tageslicht, frische Luft und das unerträgliche Gebrüll der Vögel.
Oft ist die Ursache des schwarzsehens lediglich ein verrutschen des Bretts vorm Kopf =)
Oft ist die Ursache des schwarzsehens lediglich ein verrutschen des Bretts vorm Kopf =)
-
chrislo1976
- Beiträge: 105
- Registriert: 24. Februar 2008 09:45
Die QtSvg-Sachen sind auch nicht gedacht, einen kompletten SVG-Editor zu schreiben.
Nicht umsonst entwickeln die KDE-Leute ihr eigenes KSVG (welches AFAIK auch ein Bestand von QtWebkit ist, sollte man vllt. mal anregen das für andere Applikationen zur Verfügung zu stellen...).
Also entweder das ganze SVG rendern, oder die einzelnen Objekte extrahieren und selber Positionieren. Wenn du die korrekte Position haben willst, schau dir mit dem Texteditor das SVG an (ist ja nur XML). Da gibt es zu jedem path immer ein Attribut "d", in dem die einzelnen Pfad-Knoten stecken. Kannst ja mal versuchen, das zu extrahieren...
Ansonsten hast du es schon mal mit einem sharedRenderer versucht?
Nicht umsonst entwickeln die KDE-Leute ihr eigenes KSVG (welches AFAIK auch ein Bestand von QtWebkit ist, sollte man vllt. mal anregen das für andere Applikationen zur Verfügung zu stellen...).
Also entweder das ganze SVG rendern, oder die einzelnen Objekte extrahieren und selber Positionieren. Wenn du die korrekte Position haben willst, schau dir mit dem Texteditor das SVG an (ist ja nur XML). Da gibt es zu jedem path immer ein Attribut "d", in dem die einzelnen Pfad-Knoten stecken. Kannst ja mal versuchen, das zu extrahieren...
Ansonsten hast du es schon mal mit einem sharedRenderer versucht?
-
chrislo1976
- Beiträge: 105
- Registriert: 24. Februar 2008 09:45
@franzf:
Ich habe wirklich nicht vor einen Editor zu machen, dafür gibts ja eh freie super-tolle Programme im Netz.
Mir gehts nur darum mit einem externen SVG-Editor eine mehr oder weniger komplexe "Scene" zeichnen zu können, diese in Qt anzuzeigen, aber zusätzlich noch darauf zu reagieren ob und welches Objekt der Bediener angeklickt (und andere Events) hat.
Meinen SvgObjects übergebe ich den SvgRenderer bereits mit...
Gruß,
Christian
Ich habe wirklich nicht vor einen Editor zu machen, dafür gibts ja eh freie super-tolle Programme im Netz.
Mir gehts nur darum mit einem externen SVG-Editor eine mehr oder weniger komplexe "Scene" zeichnen zu können, diese in Qt anzuzeigen, aber zusätzlich noch darauf zu reagieren ob und welches Objekt der Bediener angeklickt (und andere Events) hat.
Meinen SvgObjects übergebe ich den SvgRenderer bereits mit
Code: Alles auswählen
setSharedRenderer()Gruß,
Christian