Generelle Verständnisfragen zu QGraphicsView & Co.

Alles rund um die Programmierung mit Qt
Antworten
Psychomax
Beiträge: 52
Registriert: 29. Dezember 2008 13:28

Generelle Verständnisfragen zu QGraphicsView & Co.

Beitrag von Psychomax »

Gute Abend oder Nacht zusammen! ;-)

a) Erstmal was ich Umsetzen will
Ist im Prinzip ganz einfach. Ich hab ein 480x272 großes Fenster. Auf der rechten Seite sollen 4 Buttons sein die ggf. animiert werden sollen. Aber das Wichtigste ist, dass ich die Buttons von rechts nach links in einen bestimmten Bereich droppen kann. :)

b) So erstmal der Code

Code: Alles auswählen

#ifndef DRAGDROPDEMO_H
#define DRAGDROPDEMO_H

#include <QtGui/QWidget>
#include <QMessageBox>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>

namespace Ui
{
    class DragDropDemo;
}

class DragDropDemo : public QWidget
{
    Q_OBJECT

public:
    DragDropDemo(QWidget *parent = 0);
    ~DragDropDemo();

private:
    Ui::DragDropDemo *ui;
};

#endif // DRAGDROPDEMO_H

Code: Alles auswählen

#include "dragdropdemo.h"
#include "ui_dragdropdemo.h"

DragDropDemo::DragDropDemo(QWidget *parent)
    : QWidget(parent), ui(new Ui::DragDropDemo)
{
    ui->setupUi(this);
    QGraphicsView *view =new QGraphicsView(this);
    view->setStyleSheet("background-color: #EAEAEA; border: 1px");
    QGraphicsScene *scene = new QGraphicsScene();
    scene->setSceneRect(0,0,480,272);

    /* Leiste hinzufügen */
    QGraphicsPixmapItem *leistenItem = new QGraphicsPixmapItem();
    leistenItem->setPixmap(QPixmap ("../images/leiste.png"));
    leistenItem->setPos(402,0);
    scene->addItem(leistenItem);

    /* Buttons */
    QGraphicsPixmapItem *b1Item = new QGraphicsPixmapItem();
    b1Item->setPixmap(QPixmap ("../images/b1.png"));
    b1Item->setPos(420,12);
    scene->addItem(b1Item);

    QGraphicsPixmapItem *b2Item = new QGraphicsPixmapItem();
    b2Item->setPixmap(QPixmap ("../images/b2.png"));
    b2Item->setPos(420,77);
    scene->addItem(b2Item);

    QGraphicsPixmapItem *b3Item = new QGraphicsPixmapItem();
    b3Item->setPixmap(QPixmap ("../images/b3.png"));
    b3Item->setPos(420,142);
    scene->addItem(b3Item);

    QGraphicsPixmapItem *b4Item = new QGraphicsPixmapItem();
    b4Item->setPixmap(QPixmap ("../images/b4.png"));
    b4Item->setPos(420,207);
    scene->addItem(b4Item);


    view->setScene(scene);
    view->show();
}

DragDropDemo::~DragDropDemo()
{
    delete ui;
}

Erstmal vor weg. Die Ui nutze ich nicht. ;-)

1.) Führt dieser Ansatz zu meinem Ziel? Denn jetzt fände ich es schon schwer die Buttons zu draggen. Bekommt jeder Button eine eigene Scene?! Oder ist das schon richtig, dass ich alle Buttons in einer Scene habe?!

2.) Wie kann ich die Scene ordentlich positionieren? Ich hab es mit setSceneRect(); versucht. Allerdings nur mit mässigen Erfolg. Die Scene fühlt nämlich das komplette Fenster. (Die Leiste ist 78x272)
Ich dachte erst das man die Scene so einstellt

scene->setSceneRect(402,0,72,272);

Allerdings klebt sie nach wie vor ohne Änderung auf der linken Seite. Bei

scene->setSceneRect(0,0,480,272);

So ist die Scene zwar über die komplette Fensterbreite, aber ich kann die Grafiken wenigstens gewünscht ausrichten. Was mach ich falsch?!

LG Max[/code]
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Muss es denn für das Drag/Drop unbedingt eine GraphicsView sein?
Das klingt für mich eigentlich eher nach DockWidgets... Pack doch deine Buttons in eine rein, dann kannst die leicht von rechts nach links dragpen.
Oder brauchst du das GraphicsView nachher für andere spezielle Sachen? Kannst ja mal genauer beschreiben WAS du eigentlich willst und nicht wie :)

Ansonsten solltest du die View positionieren, und nicht die scene! Die View ist dein Widget!
Außerdem hoffe ich, dass das momentan noch im Experimentierstadion ist, denn das ui kannst du dir so echt schenken :P Und das MainWindow auch.
Psychomax
Beiträge: 52
Registriert: 29. Dezember 2008 13:28

Beitrag von Psychomax »

Hallo! :)

Jo erstmal zu Beruhigung. Ich hab vorher immer mit Eclipse gearbeitet jetzt versuch ich mich am Qt Creator. Gestern war ich einfach nur zu faul ui etc. rauszunehmen. :-) ALso alles Experimentieren.

Zur Aufgabe:

Also geschrieben wird die Software für ein embedded System mit einem 140 Mhz Prozessor. Ich hab einen 4 Zoll Display der eine Auflösung von 480x272 bei 24 Bit schafft. (Sind noch andere Displays geplant) Jetzt muss ich ausloten, was ich nun alles machen kann und wie schnell das dann ist und wie ich wie in dem Fall bestimmte Sachen angehe.
Als bessere Vorstellung hab ich einfach mal zwei Videos aus youtube genommen. Nicht genau so, aber das geht in etwa in die Richtung.

http://www.youtube.com/watch?v=NjxfEud_ ... re=related
http://www.youtube.com/watch?v=9ni_6qTw ... re=related

Es wäre natürlich super, wenn man sowas mit einem 140 Mhz bzw. übertaktet 200 Mhz Prozessor erschlagen könnte. Allerdings hab ich testershalber mal den Calculator kompiliert. Der ruckelt sich zu tode, wenn man das Fenster nimmt. Was eigentlich auch klar ist, wenn man mal berechnet, wieviel Pixel der Prozessor bzw. interne LCD Controller rumschuppsen muss.

Das wäre so erstmal die Aufgabe. Ich hab halt bisher Windowsprogrammer mehr oder weniger geschrieben. Also weniger Grafikmenüs und so gemacht. Jetzt halt meine Frage. Wie baut man sowas ordentlich auf. Nimmt man dennoch als Basis ein Mainwindow, oder geht mal direkt auf QGraphicsWidget (Hab ich per Zufall gefunden) bzw. baut alles auf Widgets auf?!

GraphicsView muss also nicht sein. Ich dachte nur, dass das so sein sollte bzw. ein guter Style ist, besonders wenn man das Buttons animieren will...

Nun ja, dass ist es im grobe. Ich hoffe ihr könnt mir ein paar Tips geben wie ich jetzt einsteige... Ist prinzipiell alles vorhanden! :-)
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Die beiden geposteten Videos verwenden denke ich QGraphicsView (kde ja sicher ;)). Und wenn du das genau so haben willst, ist das auch die beste Lösung. Experimentier einfach mal bissl weiter. Am besten ohne der Beschränkung auf die fixe Größe.
Einfach ein GraphicsView + scene füllen, Items in nem QGraphicsLayout platzieren, wie man dann Drag&Drop implementiert, Animationen (QGraphicsItemAnimation, und such auch mal nach "Qt4 Kinetic" :)) usw.
Dass du ein Gefühl bekommst, wie man bestimmte Sachen am besten erledigt. Z.B. auch, dass Items nicht aus einem vorgegebenen Bereich "rausrutschen".
Psychomax
Beiträge: 52
Registriert: 29. Dezember 2008 13:28

Beitrag von Psychomax »

Also sollte ich in der Tat nicht auf einem normalen Widget aufbauen, sondern auf einem QGraphicWidget?! Dort kann man ja dann ähnlich mit Layouts arbeiten.

Ist denn so ein Button ein seperater Thread in dem genau ein Graphicview und genau eine Graphicscene integriert wird!? Ich frage deshalb, weil dann kann man ja eine Klasse bzw. ein Template machen, die man auf Objecte anwendet.

Inwieweit deckt denn das QAnimationFramework meine Bedürfnisse ab?! Kann ich das eingentlich in das QT Creator implementieren?!
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Psychomax hat geschrieben:Also sollte ich in der Tat nicht auf einem normalen Widget aufbauen, sondern auf einem QGraphicWidget?! Dort kann man ja dann ähnlich mit Layouts arbeiten.
GRRGRRR! :P
Hast du dir schonmal die Doku genauer angeschaut? QGraphicsWidget brauchst du eigentlich nur, um in deine GraphcisView ein normales QWidget (z.B. einen QPushButton) einzubetten. Für normale Items nimmst du bitte QGraphicsItem als Basis. Und warum gibt es QGraphicsLayout? Genau, um in einer QGraphicsScene normale QGraphicsItems anzuordnen. In eine QGraphicsScene ein QGraphicsWidget einbetten, um darin alles zu machen... da kannst du dir den "Umweg" über das GraphicsView-Framework sparen.
Ist denn so ein Button ein seperater Thread in dem genau ein Graphicview und genau eine Graphicscene integriert wird!? Ich frage deshalb, weil dann kann man ja eine Klasse bzw. ein Template machen, die man auf Objecte anwendet.
Vogelwild :D
Ein separater "Thread" kann es nicht sein, Qt erlaubt (zum Glück) Zeichnen nur im Hauptthread. Und wie du drauf kommst, dass ein Button ein GraphicsView ist, ist mir Schleierhaft. Ein Button ist ein Button ist ein QWidget, aber kein QGraphicsView...
Und ein Template ist eine recht allgemeine Technik, die man überall anwenden kann, egal ob QObject, QGraphicsScene oder ganz was anderes.

BITTE schau mal in die Doku, lies dich ein. Für Beispiel schau dir mal in den Examples und Demos, die mit Qt kommen, alles an was dich interessiert (qt4-src/examples/graphicsview z.B.). Dann mach erst mal deine ersten Schritte, bevor du dich total verrennst...
Inwieweit deckt denn das QAnimationFramework meine Bedürfnisse ab?! Kann ich das eingentlich in das QT Creator implementieren?!
Du kannst GraphicsItems animieren, was du ja scheinbar willst :) Experimentier damit.
Und Qt Creator ist nur ein etwas aufgebohrter Editor (IDE halt...). Du kannst damit alles machen was du willst. Keine AHnung in wie weit der Automatisierungen unterstützt, aber im Prinzip musst du nur deine Header includen und in den Projectsettings was hinzufügen, damit Includes und Libs des Frameworks gefunden werden (aber vllt. installiert sich das eh in den Qt-Tree...)

Ciaoi
Psychomax
Beiträge: 52
Registriert: 29. Dezember 2008 13:28

Beitrag von Psychomax »

Psychomax hat Folgendes geschrieben:
Also sollte ich in der Tat nicht auf einem normalen Widget aufbauen, sondern auf einem QGraphicWidget?! Dort kann man ja dann ähnlich mit Layouts arbeiten.

GRRGRRR! Razz
Hast du dir schonmal die Doku genauer angeschaut? QGraphicsWidget brauchst du eigentlich nur, um in deine GraphcisView ein normales QWidget (z.B. einen QPushButton) einzubetten. Für normale Items nimmst du bitte QGraphicsItem als Basis. Und warum gibt es QGraphicsLayout? Genau, um in einer QGraphicsScene normale QGraphicsItems anzuordnen. In eine QGraphicsScene ein QGraphicsWidget einbetten, um darin alles zu machen... da kannst du dir den "Umweg" über das GraphicsView-Framework sparen.
Sprich die "Hauptkomponenten" mit den ich was spielen sollte sind QGraphicsLayout, QGraphicsscene und QGraphicsItem!? Sprich ich brauch das Viewframework gar net?! Zu mindest in meinem Fall?

---

Ne mit Button meine ich meine Grafikbutton! ;-) Die die Buttons aus QWidget! ;-) War vielleicht was missverständlich ausgedrückt... ;-)

---

Jut ich experimentiere einfach mal was... :)
Psychomax
Beiträge: 52
Registriert: 29. Dezember 2008 13:28

Beitrag von Psychomax »

Ich komm hier doch nicht ganz klar. Ich möchte einen einfache png Grafik in mein Qt Programm bringen. Ich dachte da an QPixmap. Aber QGraphicsItem unterstützt dies nicht.

Also habe ich es so gelöst. Genau so wie oben halt.

Code: Alles auswählen

    QGraphicsScene *scene = new QGraphicsScene();
    scene->setSceneRect(402,0,72,272);

    /* Leiste hinzufügen */
    QGraphicsPixmapItem *leistenItem = new QGraphicsPixmapItem();
    leistenItem->setPixmap(QPixmap ("../images/leiste.png"));
    leistenItem->setPos(402,0);
    scene->addItem(leistenItem);

    QGraphicsGridLayout *layout = new QGraphicsGridLayout();
Wie bringe ich das Pixmap bzw. die Scene und GridLayout zusammen?!
Psychomax
Beiträge: 52
Registriert: 29. Dezember 2008 13:28

Beitrag von Psychomax »

Wie funktioniert die itemAt in der QGraphicsScene. Obwohl an der Stelle eine Grafik ist gibt er dennoch 0 zurück. Versuche gerade das Drag und Drop zu lösen. Die Positionierung hab ich hinbekommen. Ein Feedback, ob das so sauber ist würde sehr nice sein! :)

Code: Alles auswählen

#include "dragdropdemo.h"
#include "ui_dragdropdemo.h"

DragDropDemo::DragDropDemo(QWidget *parent)
    : QWidget(parent), ui(new Ui::DragDropDemo)
{
    ui->setupUi(this);
    this->setStyleSheet("background-color:#EAEAEA, border: 1px solid black");
    scene = new QGraphicsScene();

    /* Buttons hinzufügen */
    QGraphicsPixmapItem *b1Item = new QGraphicsPixmapItem();
    b1Item->setPixmap(QPixmap (":/images/b1.png"));
    b1Item->setZValue(10);
    b1Item->setOffset(17,10);

    QGraphicsPixmapItem *b2Item = new QGraphicsPixmapItem();
    b2Item->setPixmap(QPixmap (":/images/b2.png"));
    b2Item->setOffset(17,75);

    QGraphicsPixmapItem *b3Item = new QGraphicsPixmapItem();
    b3Item->setPixmap(QPixmap (":/images/b3.png"));
    b3Item->setOffset(17,140);

    QGraphicsPixmapItem *b4Item = new QGraphicsPixmapItem();
    b4Item->setPixmap(QPixmap (":/images/b4.png"));
    b4Item->setOffset(17,205);



    scene->addItem(b1Item);
    scene->addItem(b2Item);
    scene->addItem(b3Item);
    scene->addItem(b4Item);

    QGraphicsView *view = new QGraphicsView(this);
    view->setStyleSheet("background:transparent;border:0px");
    view->setBackgroundBrush(QPixmap (":/images/leiste.png"));
    view->setScene(scene);
    view->setSceneRect(0,0,78,272);
    view->setGeometry(402,0,78,272);
    view->show();
}

DragDropDemo::~DragDropDemo()
{
    delete ui;
}

void DragDropDemo::mousePressEvent(QMouseEvent *event)
{
    //QGraphicsItem *child = scene->itemAt(event->pos());
    if (!scene->itemAt(446,40))
    {
        QMessageBox::warning(this, "Hinweis",QString("X:%1;Y:%2").arg(event->x()).arg(event->y()),QMessageBox::Ok);
    }
    /*
    QPixmap pixmap = *child->pixmap();

    QByteArray itemData;
    QDataStream dataStream(&itemData, QIODevice::WriteOnly);
    dataStream << pixmap << QPoint(event->pos() - child->pos());

    QMimeData *mimeData = new QMimeData;
    mimeData->setData("application/x-dnditemdata", itemData);

    QDrag *drag = new QDrag(this);
    drag->setMimeData(mimeData);
    drag->setPixmap(pixmap);
    drag->setHotSpot(event->pos() - child->pos());

    QPixmap tempPixmap = pixmap;
    QPainter painter;
    painter.begin(&tempPixmap);
    painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127));
    painter.end();

    child->setPixmap(tempPixmap);

    if (drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction) == Qt::MoveAction)
        child->close();
    else {
        child->show();
        child->setPixmap(pixmap);
    }
    */
}
Psychomax
Beiträge: 52
Registriert: 29. Dezember 2008 13:28

Beitrag von Psychomax »

So ich hab mir mal den Roboter angeschaut und der macht ja genau das was ich eigentlich ungefährt haben will. Ich hab mir eine Klasse Button gemacht. Jetzt kommt allerdings folgender Fehler:

buttonicon.cpp:17: error: invalid use of undefined type `struct QPainter'

Code: Alles auswählen

#ifndef BUTTONICON_H
#define BUTTONICON_H

#include <QGraphicsItem>

class ButtonIcon : public QGraphicsItem
{
public:
    ButtonIcon(QPixmap *pixmap);
    ~ButtonIcon();
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    QRectF boundingRect() const;

protected:
    /* Variblen */
    QPixmap *pixmap;

    /* Methoden */
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
};

#endif // BUTTONICON_H

Code: Alles auswählen

#include "buttonicon.h"

ButtonIcon::ButtonIcon(QPixmap *pixmap)
{
    this->pixmap = pixmap;
}

ButtonIcon::~ButtonIcon()
{
}

void ButtonIcon::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);

    painter->drawPixmap(0,0,pixmap);
}

QRectF ButtonIcon::boundingRect() const
{
    return QRectF(this->pixmap->rect());
}

void ButtonIcon::mousePressEvent(QGraphicsSceneMouseEvent *event)
{

}
void ButtonIcon::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{

}
void ButtonIcon::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{

}
Psychomax
Beiträge: 52
Registriert: 29. Dezember 2008 13:28

Beitrag von Psychomax »

Ok hmm irgendwie jetzt doch gelöst... Hab einfach einen include von QPainter gemacht und drawPixmap war noch falsch.

Aber warum wurde bei dem Roboter die QPainter nicht explizit eingebunden?
Psychomax
Beiträge: 52
Registriert: 29. Dezember 2008 13:28

Beitrag von Psychomax »

So ich bin mittlerweile weiter gekommen. Leider bin ich jetzt an einem Punkt wo ich ggf. alles wieder umschmeißen muss.

So wie ich das verstanden habe kann man ja Bilder etc. draggen und droppen. Das funktioniert bei mir auch wunderbar. So in meinem Fall will ich aber nur nur das Bild an sich draggen, sondern das komplette Bildobjekt mit dessen Informationen.

Beispiel:

Ein Bild wenn man draufklickt startet eine bestimmte Applikation. Beimn draggen würde ich zwar das Bild draggen, aber die Information welche Applikation es starten soll geht bei mir momentan verloren.
z.B. da:
http://www.youtube.com/watch?v=NjxfEud_B6U

Wie kann man komplette Objekte von der einen QGraphicsScene zur anderen Droppen? Der Unterschied zur meiner Applikation zur der im oberen Video ist, dass bei jedem Drag eine Kopie vom Objekt erstellt wird und nicht das Original bewegt wird.

Ich dachte da als erstes an zwei QList <QGraphicsItem *>. Einmal für die drag Scene und einmal für die drop Scene. Würde das zum Erfolg führen?
Antworten