Seite 1 von 2

onclick Ereignis bei "normalen" Widgets!!!

Verfasst: 19. Oktober 2005 19:29
von fedderle
habe da ein kleines Problem.

Teste noch ein wenig in QT herum! Ich brauche später ein Polygon, was mit einer Farbe gefüllt ist und was man wenn man es anklickt dann seine Farbe ändert!

Dachte mir, dass ich das dann mit QObject::connect mache!

nur brauch ich dann ja das SIGNAL(clicked()) welches aber nur bei Buttons existiert und nicht bei einem Polygon oder ähnlichem!

Jetzt sie Frage: Wie kann ich so ein clicked() SIGNAL schreiben???? Also wie erkennt man denn das auf das Objekt geklickt wurde?

Verfasst: 19. Oktober 2005 19:38
von ArneStocker
in einer eigenen abgeleisteten Klasse (z.B. MyPolygonClass)

Code: Alles auswählen

class MyPolygonClass  : public QObject
{
    Q_OBJECT
    ...
    signals:
        void clicked();
    ...
}
um das signal zu senden rufst Du innerhalb von MyPolygonClass

Code: Alles auswählen

emit clicked();
auf. Das connect natürlich nicht vergessen.

Gruss Arne

Verfasst: 19. Oktober 2005 19:59
von fedderle
Danke!
Das oben ist klar!

Aber: Das mit dem

Code: Alles auswählen

emit clicked()
versteh ich irgendwie nicht so ganz! Wenn ich das richtig verstehe muss ich genau das ja schreiben nachdem ich festgestellt habe, das auf das Polygon geklickt wurde! Jetzt ist nur die Sache dass ich das genau ja nicht weiß!

Oder versteh ich hier gerade etwas total falsch?

Hier der aktuelle Code von meinem Programm! Arbeite da zur Zeit zwar nicth mit einem Polygon, aber das dürfte ja keinen Unterschied machen.

Code: Alles auswählen

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QLinearGradient>
#include <QObject>
#include <QPushButton>

class MyWidget : public QWidget
{
    Q_OBJECT
    public:
        // Funktion PaintEvent muss ueberladen werden
        MyWidget(QWidget *parent = 0);
        void paintEvent(QPaintEvent *);
        
    signals:
        void clicked();
};

MyWidget::MyWidget(QWidget *parent):QWidget(parent)
{}

void MyWidget::paintEvent(QPaintEvent *)
{
    // Zeichenstift auf dieses Widget
    QPainter painter(this);
    
    
    QLinearGradient gradient(0, 0, 150, 150);
    gradient.setColorAt(0, Qt::red);
    gradient.setColorAt(0.5, Qt::green);
    gradient.setColorAt(1, Qt::blue);
    painter.setBrush(gradient);
    painter.drawRect(0, 0, 150, 150);
}

int main(int argc, char* * argv)
{
    // Anwendung
    QApplication app(argc, argv);
    
    MyWidget zeichenbrett;
    zeichenbrett.resize(150,300);
    
    QPushButton button("quit", &zeichenbrett);
    button.setGeometry(0, 150, 100, 30);
    
    QObject::connect(&button, SIGNAL(clicked()), &app, SLOT(quit()));
    
    // wenn man auf das Brett klcikt schliesst sich das Programm
    QObject::connect(&zeichenbrett, SIGNAL(clicked()), &app, SLOT(quit()));
    
    QPainter painter;
    
    zeichenbrett.show();
    button.show();
    
    return app.exec();
}

fedderle!!!

Verfasst: 20. Oktober 2005 09:58
von Goos
Du musst halt ueber QMouseEvent deiner Klasse die Mausklicks abfangen und ueberprüfen, ob sich der Mauszeiger derzeit in deinem Rechteck befindet.

Goos

Verfasst: 20. Oktober 2005 10:40
von fedderle
Jetzt bin ich irgendwie total verwirrt!

Also! Was brauche ich denn jetzt alles um erkennen zu koennen, ob auf das Objekt geklickt wurde!

nur dieses ...

Code: Alles auswählen

class MyPolygon : public QPolygonF, public QObject
{
     Q_OBJECT
     ...
  signals:
     void clicked();
};
und dann irgendwo dieses emit!
Wobei ich hier nicht ganz verstehe wie dass dann gehen soll, weil egal wo ich dieses

Code: Alles auswählen

emit clicked()
innnerhalb der Klasse hinschreibe kommt folgende compiler fehlermeldung
undefined reference to 'MyPolygon::clicked()'
Oder muss ich beides machen also diese QMouseEvent ebenfalls mit reinmachen?????

feddderle

Verfasst: 20. Oktober 2005 19:02
von ArneStocker
Innerhalb Deiner Polygonklasse musst Du schon die events auslesen. SIGNAL und SLOT ist eigentlich als Kommunikation zwischen verschiedenen Objekten gedacht (also z.B. einem QButton Objekt und dem QDialog Objekt).

In der Standard - Implementation von QButton wird z.B. auf ein Klick reagiert (wie die das machen kann ich nur vermuten, nämlich über event) und dann das Signal clicked() gesendet.

Wenn Du innerhalb Deiner Polygonklasse auf ein Klickevent reagieren willst, musst Du die events abfangen. Um von Deiner Polygonklasse eine Nachricht an z.B. die Dialogklasse zu versenden nimmst du das emit clicked().

Nur zur Klarstellung : Polygon (Deine Klasse) versendet nicht automatisch ein clicked() event, wenn Du draufklickst (das macht aber z.B. QButton). Das Mausereigniss über deinem Objekt führt von sich aus nicht zum Versenden der Nachricht clicked. Umgekehrt kannst ein clicked() SIGNAL auch versenden, wenn gar nichts geklickt wurde. Das emit clicked() rufst Du also in der eventmethode der Polygon - Klasse auf (nämlich dann wenn auf Dein Objekt geklickt wurde).

Anschliessend werden alle Objekte, die Du mit connect verbunden hast, über ihren SLOT von dem SIGNAL benachrichtigt.

Alle Klarheiten beseitigt ? :-)

Gruss Arne

PS.: wegen des Compiler - Fehlers könnte es sein, dass Du (falls das nicht automatisch von qmake gemacht wird) den moc(Meta - objekt Compiler über Deine Klassendeklaration laufen lassen musst). Wenn Du nachträglich ein Q_OBJECT eingefügt hast, ist m.E. ein erneuter Aufruf von qmake fällig.

Verfasst: 23. Oktober 2005 19:13
von fedderle
So weit in der theorie klar!
Also ich hab noch mal von vorne angefangen! Ich versuche das ganze Vorhaben jetzt mal genau zu erklären! Insgesammt soll das ganze später ne Landkarte werden, wo man die einzelnen Länder anklicken kann und das aktuell angeklickte Land dann die Farbe ändert!

Ich hab mir dazu gedacht erstellt ein Widget, wo die ganzen einzelnen Länder (Polygone) drauf dargestellt werden! Klingt eigentlich in der Theorie verdammt einfach!

Ich probier jetzt nur schon seit Tagen hier rum! Dachte erst,das kann ja nicht so schwer sein, mach einfach mal ne neue Klasse und schreib die Methode woid paintEvent() um!

Und jetzt kommen wir wieder zu meinem alten Problem!

Habe folgenden Quelltext aktuell mit dem ich herumhantiere:

Code: Alles auswählen

#include <QApplication>
#include <QPushButton>
#include <QWidget>
#include <QPolygonF>
#include <QPainter>
#include <QObject>
#include <QPaintEvent>

class MyQWidget : public QWidget
{
    Q_OBJECT
            
    public:
        void paintEvent(QPaintEvent *);
        
    signals:
        void clicked();
};

void MyQWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    
    QPolygonF polygon;
    polygon << QPointF(20,50) << QPointF (40, 40) << QPointF(120, 100) << QPointF(55, 230);
    
    painter.setBrush(Qt::blue);
    painter.drawPolygon(polygon, Qt::OddEvenFill);
}

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    MyQWidget widget;
    widget.show();
    
    return app.exec();
}
Wie gesagt habe noch einmal von vorne angefangen! Treffe aber jetzt hier schon auf erste Probleme beim kompililieren!

Sobald ich oben in der eigenen Klasse das Stichwort Q_OBJECT eingebe und irgendwo ein Objekt der Klasse erzeugen (oben geschieht dies in der int main()) möchte, kommt diese Fehlermeldung:

src/testpolygone1.cpp:29: undefined reference to `vtable for MyQWidget'
Wenn ich kein Obejekt erstelle kommt die Meldung nicht! Wenn ich ein Obejkt erstelle aber das Q_OBJECT nicht hinschreibe kommt auch keine fehlermeldung! Aber ich brauch das Q_OBJECT ja!

Dazu noch! Ja ich nutze vor dem kompielieren das qmake!

Also meine eingaben sind da dann immer:
1. qmake -project
2. qmake
3. make


ist doch richtig so!!!!? Oder hab ich was vergessen?
Wäre echt dankbar, wenn mir da irgendjemand helfen könnte!

fedderle

Verfasst: 23. Oktober 2005 19:48
von lepsai
Es heisst :

Code: Alles auswählen

protected: 
        void paintEvent(QPaintEvent *);

Verfasst: 23. Oktober 2005 23:19
von ArneStocker
das protected ist m.E. nicht schuld. Es muss zulässig sein, eine Methode in einer anderen
Klasse mit anderen Berechtigungen zu implementieren

Aber paintEvent ist eine virtuelle Methode und wird zur Laufzeit gebunden. Es sollte daher heissen
virtual void paintEvent(QPaintEvent *pEvent);
Nur zum Verständnis: Dein Programm lässt sich doch übersetzen (sonst könntest Du kein Objekt erzeugen). Erhälst Du die Meldung während des Debuggens in der Konsole ?

Gruss Arne

Verfasst: 24. Oktober 2005 00:56
von lepsai
Nein, mein Lieber, genau das ist falsch. Eine Funktion bleibt in allen abgeleiteten Klassen virtuell. Also muss es nicht vitual void ... heissen. Dagegen ist es wichtig, dass die Funktion, die ich überlade, in der gleichen Access-Klasse bleibt. Das ist auch irgendwo der Sinn der objekt-orientierten Herangehensweise.

Verfasst: 24. Oktober 2005 15:59
von ArneStocker
ich hab's nochmal nachgelesen, Du hast recht.. ups ! Zum Glück hat das virtual vor den Methoden nicht geschadet :-)

Gruss Arne

Verfasst: 2. November 2005 16:28
von fedderle
Ok Leute hatte ein wenig gedauert!

Hatte immer noch Probleme, das ich nicht kompilieren konnte wenn ich Q_OBJECT in den Code einfüge! Bis ich irgendwann herausgefunden habe, dass das ja nur in headerdateien stehen darf nicht in cpp dateien!

Habe es jetzt folgendermaßen gemacht:

habe eine MyQwidget Klasse von QWidget abgeleitet!

Dort habe ich das siganl void clicked() definiert!

Jetzt nur noch mal um Nummer sicher zu gehen, damit iches auch wirklich richtig verstanden habe!

Jetzt muss ich ne Funktion schreiben/finden, die ermittlet, wann aufd den Button geklickt wurde! und dort das emit clicked() einbinden!!!!??

seh ich das richtig???

Gruß fedderle!

Verfasst: 2. November 2005 16:43
von FlorianBecker
Ja

Verfasst: 3. November 2005 17:03
von fedderle
OK! Danke! Dann wäre meine Frage beantwortet!

Verfasst: 1. Dezember 2005 21:47
von AngelD
Hi! Ich habe so ziemlich das selbe Problem, habe das auch so gemacht wie ihr es beschrieben hattet, nur irgendwie will es nicht funktionieren. :(

Code: Alles auswählen

class HPKarte : public QWidget
{
    Q_OBJECT
    
    protected:
        void mousePressEvent(QMouseEvent *event);
        
    signals: 
        void clicked(HPKarte *); // Signal das auf das Widget geklickt wurde 
        
    public slots:
        void cardClicked(HPKarte *);
}

void HPKarte::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
        emit clicked(this);
}
und in der main:

Code: Alles auswählen

HPKarte *muh = new HPKarte(HPKarte::Figur(1));
    QObject::connect(muh, SIGNAL(clicked(HPKarte *)), muh, SLOT(cardClicked(HPPolygon *)));
    muh->show();
Also es soll diese Karte angeklickt werden, und dann z.b. ein anderes Bild oder ähnliches geladen werden.

Dies ist auch fast der selbe Code den federle benutzt, nur das es bei ihm funktioniert und bei mir nicht.

Kann mir jemand sagen warum??

Gruß, AngelDust