Seite 1 von 1

Qtimer mit einfacher Konsolenanwendung

Verfasst: 17. März 2009 10:55
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?

Re: Qtimer mit einfacher Konsolenanwendung

Verfasst: 17. März 2009 10:58
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.

Verfasst: 17. März 2009 11:37
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.

Verfasst: 17. März 2009 11:43
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? ;)

Verfasst: 17. März 2009 12:03
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)

Verfasst: 17. März 2009 13:59
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...

Verfasst: 17. März 2009 14:10
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 ;).

Verfasst: 17. März 2009 14:48
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.

Verfasst: 17. März 2009 15:07
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.

Verfasst: 17. März 2009 15:27
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.

Verfasst: 17. März 2009 15:29
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.

Verfasst: 17. März 2009 15:31
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.

Verfasst: 17. März 2009 15:57
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.

Verfasst: 17. März 2009 19:14
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?