Qtimer mit einfacher Konsolenanwendung

Alles rund um die Programmierung mit Qt
Antworten
webglider
Beiträge: 21
Registriert: 22. Februar 2009 13:32

Qtimer mit einfacher Konsolenanwendung

Beitrag von webglider »

Hallo.

Ich versuche einen QTimer in einer einfachen Test-Konsolenanwendung zu verwenden:

Code: Alles auswählen

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <iostream>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QTimer *timer = new QTimer(0);
    timer->connect(timer, SIGNAL(timeout()), &app, SLOT(doOutput()));
    timer->start(1000);

    return app.exec();
}

void doOutput()
{
    std::cout << "timer..." << std::endl;

    return;
}
Klappt aber leider nicht, ich erhalte in der Konsole nur folgende Meldung:

Object::connect: No such slot QCoreApplication::doOutput()

Mir scheint, da läuft was falsch mit dem slot. Was bedeutet diese Meldung?
Michael
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Re: Qtimer mit einfacher Konsolenanwendung

Beitrag von pfid »

webglider hat geschrieben: Klappt aber leider nicht, ich erhalte in der Konsole nur folgende Meldung:

Object::connect: No such slot QCoreApplication::doOutput()

Mir scheint, da läuft was falsch mit dem slot. Was bedeutet diese Meldung?
Die Meldung besagt, dass die Klasse QCoreApplication keinen Slot "doOutput" hat.
CLRS530
Beiträge: 155
Registriert: 8. Oktober 2007 18:00

Beitrag von CLRS530 »

Ihr dazuzusagen, dass er anstatt "app" - "this" nehmen soll hätte den Braten doch auch nicht zu fett gemacht ;).
Signal und Slot ist am Anfang immer schwer.
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Beitrag von pfid »

CLRS530 hat geschrieben:Ihr dazuzusagen, dass er anstatt "app" - "this" nehmen soll hätte den Braten doch auch nicht zu fett gemacht ;).
Signal und Slot ist am Anfang immer schwer.
Welches this? ;)
CLRS530
Beiträge: 155
Registriert: 8. Oktober 2007 18:00

Beitrag von CLRS530 »

Ja stimmt :-D. Macht der Gewohnheit.

Da wüsste ich jetzt ehrlich gesagt auch gar nichts. Aber in der main braucht man eh keine Slots ... eigentlich...

EDIT:
Erstell dir eine kleine Klasse, in der du den Timer steckst. Dann hat das Connect auch keine Probleme mehr (mit einem this :-P)
webglider
Beiträge: 21
Registriert: 22. Februar 2009 13:32

Beitrag von webglider »

Ich habe das Ganze mal neu geschrieben.

Vielleicht ist das in C++ Grundlagen besser aufgehoben...

Code: Alles auswählen

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <iostream>

class TestKonsole
{
    public slots:
    void checkTimer();
};

int main(int argc, char *argv[])
{
    TestKonsole myKonsole;

    QTimer *timer = new QTimer(this);
    timer->connect(timer, SIGNAL(timeout()), this, SLOT(checkTimer()));
    timer->start(1000);
}

void TestKonsole::checkTimer()
{
    std::cout << "timer..." << std::endl;
}
Kann mir das mal jemand auseinander nehmen? Ich bin ziemlicher Neuling in OOP und habe versucht mir eine einfache Test-Klasse zu schreiben. Nun erhalte bei diesem Code folgenden Compile-Fehler:

invalid use of `this' in non-member function

Ziemliche Anfänger-Frage, ich möchts allerdings endlich mal richtig verstehen. Vielleicht erbarmt sich jemand...
Michael
CLRS530
Beiträge: 155
Registriert: 8. Oktober 2007 18:00

Beitrag von CLRS530 »

Entweder du schiebst den timer mit in TestKonsole, dann mit this oder du machst folgendes.

Code: Alles auswählen

#include <QtCore/QCoreApplication> 
#include <QTimer> 
#include <iostream> 

class TestKonsole : public QObject
{ 
Q_OBJECT
    public slots: 
         void checkTimer(); 
}; 

int main(int argc, char *argv[]) 
{ 
    TestKonsole myKonsole; 

    QTimer *timer = new QTimer(this); 
    connect(timer, SIGNAL(timeout()), &myKonsole, SLOT(checkTimer())); 
    timer->start(1000); 
} 

void TestKonsole::checkTimer() 
{ 
    std::cout << "timer..." << std::endl; 
}
Du befindest dich dort doch außerhalb der Klasse. Da macht ein this Zeiger auf die Klasse wenig Sinn.
Beachte außerdem das Q_OBJECT, welches benötigt wird, wenn du Slots benutzen möchtest. Dafür musst du dann auch von irgendeiner Klasse abgeleitet haben, die von QObject abstammt. Wenn das nicht vorliegt, dann eben von QObject selber.

Da ich gerade dem Editierwahn verfallen bin und mir ständig bessere Ideen kommen, würde es in diesem Fall Sinn machen, von QTimer abzuleiten und dort deinen Slot einzubauen.

Code: Alles auswählen

#include <QtCore/QCoreApplication> 
#include <QTimer> 
#include <iostream> 

class TestTimerKonsole : public QTimer
{ 
Q_OBJECT
    public slots: 
         void checkTimer(); 
}; 

int main(int argc, char *argv[]) 
{ 
    TestTimerKonsole myKonsole; 
    connect(&myKonsole, SIGNAL(timeout()), &myKonsole, SLOT(checkTimer())); 
    myKonsole.start(1000); 
} 

void TestTimerKonsole::checkTimer() 
{ 
    std::cout << "timer..." << std::endl; 
}
Das connect würde auch besser im Konstruktor der Klasse passen. Aber ich erspare mir das aufgrund der Schreibarbeit hier.

Ich hoffe das ist dir genug Auseinandergenommen und du verstehst das Thema nun ;).
webglider
Beiträge: 21
Registriert: 22. Februar 2009 13:32

Beitrag von webglider »

hmm. haut nicht ganz hin.

Code: Alles auswählen

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <iostream>

class TestKonsole : public QTimer
{
    Q_OBJECT

    public slots:
    void checkTimer();
};

int main(int argc, char *argv[])
{
    TestKonsole myKonsole;

    connect(&myKonsole, SIGNAL(timeout()), &myKonsole, SLOT(checkTimer()));
    myKonsole.start(1000);
}

void TestKonsole::checkTimer()
{
    std::cout << "timer..." << std::endl;
}
Fehler: connect was not declared in this scope.

Also geändert in:

Code: Alles auswählen

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <iostream>

class TestKonsole : public QTimer
{
    Q_OBJECT

    public slots:
    void checkTimer();
};

int main(int argc, char *argv[])
{
    TestKonsole myKonsole;

    myKonsole.connect(&myKonsole, SIGNAL(timeout()), &myKonsole, SLOT(checkTimer()));
    myKonsole.start(1000);
}

void TestKonsole::checkTimer()
{
    std::cout << "timer..." << std::endl;
}
Fehler: undefined reference to `vtable for TestKonsole'

Steige ich noch immer nicht durch. Danke, dass du dir die Mühe machst mir diese Grundlagen zu erklären.
Michael
CLRS530
Beiträge: 155
Registriert: 8. Oktober 2007 18:00

Beitrag von CLRS530 »

Lösche mal alle makefiles und sonstige "unnütze Dateien" und mache ein vollständigen recompile, dann wird das auch gehen.

OK liegt daran, dass die Klasse nicht in ihrer eigenen Datei gespeichert ist. Also:

#testkonsole.h

Code: Alles auswählen

#ifndef TESTKONSOLE_H
#define TESTKONSOLE_H

#include <QTimer>

class TestKonsole : public QTimer
{
 Q_OBJECT
    public:
    TestKonsole();
    public slots:
    void checkTimer();
};

#endif // TESTKONSOLE_H
#testkonsole.cpp

Code: Alles auswählen

#include "testkonsole.h"
#include <iostream>

TestKonsole::TestKonsole() : QTimer()
{

}

void TestKonsole::checkTimer()
{
    std::cout << "timer..." << std::endl;
}
#main.cpp

Code: Alles auswählen

#include <QApplication>
#include "testkonsole.h"
#include <iostream>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TestKonsole *myKonsole = new TestKonsole();

    QObject::connect(myKonsole, SIGNAL(timeout()), myKonsole, SLOT(checkTimer()));
    myKonsole->start(1000);
    a.exec();
}
Das dynamische allozieren von myKonsole ist notwendig, da das Objekt sonst sofort zerstört werden würde und das Signal gar nicht ausgelöst werden könnte.
Zuletzt geändert von CLRS530 am 17. März 2009 15:57, insgesamt 2-mal geändert.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Dann geht das sicherlich immer nocht nicht!
Denn der liebe moc parst nur header. Entweder du bringst dein Makefile dazu, dem moc *.cpp-Dateien unterzuschieben (-> Doku), oder du lagerst die Klasse in eine eigene Headerdatei aus, was die normale und einfache Herangehensweise ist.
CLRS530
Beiträge: 155
Registriert: 8. Oktober 2007 18:00

Beitrag von CLRS530 »

Ja das war mir vorher auch nicht bekannt, deswegen habe ich da auch vorher nichts geschrieben. Aber diese vtable Meldungen habe ich schon oft bekommen, wenn auf alte moc Dateien zugriffen wurden. Da müssen sie meines erachtens noch ein bisschen nachlegen oder zumindestens die Meldungen verbessern. Ich bin denen nun schon wegen 5 völlig verschiedenen Ursachen begegnet.
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

CLRS530 hat geschrieben:#main.cpp

Code: Alles auswählen

#include <QApplication>
#include "testkonsole.h"
#include <iostream>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TestKonsole *myKonsole = new TestKonsole();

    QObject::connect(myKonsole, SIGNAL(timeout()), myKonsole, SLOT(checkTimer()));
    myKonsole->start(1000);
}
Das dynamische allozieren von myKonsole ist notwendig, da das Objekt sonst sofort zerstört werden würde und das Signal gar nicht ausgelöst werden könnte.
Ähm, Ich glaub nicht dass das so funktioniert, denn du kommst nie in die EventLoop (a.exec(); vergessen?!?). Deshalb brauchst du das myKonsole auch nicht als Pointer, das Objekt existiert garantiert so lange, wie die main() nicht verlassen wird.
CLRS530
Beiträge: 155
Registriert: 8. Oktober 2007 18:00

Beitrag von CLRS530 »

Ja klar, du hast recht :).
Aber dann fehlt, wie du schon sagst lediglich das a.exec(); am Ende (habe es editiert).
Tut mir leid, ich sollte mich ein wenig mehr konzentrieren und vor allem, die Programme in der IDE schreiben/testen.
webglider
Beiträge: 21
Registriert: 22. Februar 2009 13:32

Beitrag von webglider »

Danke euch allen. Habs jetzt folgendermaßen umgesetzt:

testkonsole.h

Code: Alles auswählen

#ifndef TESTKONSOLE_H
#define TESTKONSOLE_H

#include <QTimer>

class TestKonsole : public QTimer
{
    Q_OBJECT

    public:
    TestKonsole();

    private slots:
    void checkTimer();
};

#endif // TESTKONSOLE_H
testkonsole.cpp

Code: Alles auswählen

#include "testkonsole.h"
#include <iostream>

TestKonsole::TestKonsole()
{

}

void TestKonsole::checkTimer()
{
    std::cout << "timer..." << std::endl;
}
main.cpp

Code: Alles auswählen

#include <QtCore/QCoreApplication>
#include "testkonsole.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    TestKonsole *myKonsole = new TestKonsole();

    QObject::connect(myKonsole, SIGNAL(timeout()), myKonsole, SLOT(checkTimer()));
    myKonsole->start(1000);

    a.exec();
}
Allerdings muss ich zugeben, dass mir die Aufteilung des Codes über die einzelnen Dateien noch nicht ganz klar ist. Hat jemand von euch dazu eine verständliche Erklärung? Warum z.B. eine separate main.cpp?
Michael
Antworten