[gelöst] Private ftp Klasse vtable Fehler

Alles rund um die Programmierung mit Qt
Antworten
24dan
Beiträge: 274
Registriert: 26. Juni 2006 14:15
Wohnort: Hamburg

[gelöst] Private ftp Klasse vtable Fehler

Beitrag von 24dan »

Hi,

Habe mir eine ganz einfache ftp Klasse gebaut:

Kann die Fkt auch in meinem MainWindow aufrufen.
Es wird jedoch nichts heruntergeladen.

Zugriff im MainWindow

Code: Alles auswählen

stuff..
    UpdateAdler update;
    update.download();
stuff...
Mein header

Code: Alles auswählen

QT_BEGIN_NAMESPACE
class QFile;
class QFtp;
QT_END_NAMESPACE

class UpdateAdler : public QFtp
{

public:
    UpdateAdler();
    void download();

    QFtp *ftp;
    QFile *file;

private slots:
    void commandFTP(int,bool);

};
und meine cpp

Code: Alles auswählen

#include <QtGui>
#include <QtNetwork>
#include <QtGui/QApplication>
#include "updateAdler.h"

UpdateAdler::UpdateAdler(): ftp(0)
{
}

void UpdateAdler::download()
{
    ftp = new QFtp(this);
    connect(ftp,SIGNAL(commandFinished(int,bool)),this,SLOT(commandFTP(int,bool)));
    ftp->connectToHost("server.net", 21);

}

void UpdateAdler::commandFTP(int reg, bool error)
{
    if(!error)
    {
       if (ftp->currentCommand() == QFtp::ConnectToHost)
           ftp->login("user","password");
       if (ftp->currentCommand() == QFtp::Login)
            file->setFileName("test.txt");
            file->open(QIODevice::WriteOnly);
            ftp->get("test.txt", file);
        }
       if (ftp->currentCommand() == QFtp::Get)
            ftp->close();
    }
}

Fehlermeldung nach dem Ausführen lautet:

Code: Alles auswählen

Object::connect: No such slot QFtp::commandFTP(int,bool) in updateAdler.cpp:19
??? ist doch da?
Wenn ich Q_OBJECT Macro mit einbinde bekomme ich folgende Fehlermeldung (siehe Anhang)

Der zeigt auf

Code: Alles auswählen

UpdateAdler::UpdateAdler(): ftp(0)
Hat jemand einen Tip?
Dateianhänge
err.JPG
err.JPG (23.64 KiB) 8688 mal betrachtet
Zuletzt geändert von 24dan am 26. Dezember 2009 21:55, insgesamt 1-mal geändert.
"Der erste Trunk aus dem Becher der Naturwissenschaften macht atheistisch, aber auf dem Grund des Bechers wartet Gott."
(W. Heisenberg)
Burgpflanze
Beiträge: 89
Registriert: 24. Februar 2006 16:41
Wohnort: Dresden

Beitrag von Burgpflanze »

In der Klassendefinition fehlt Q_OBJECT.
Gruß, Peter
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: Private ftp Klasse vtable Fehler

Beitrag von franzf »

Code: Alles auswählen

class UpdateAdler : public QFtp
{
[...]
    QFtp *ftp;
[...]
};
Das ist das skurrilste Klassendesign das ich bisher gesehen habe :D
Entweder IST UpdateAdler ein QFtp oder es HAT ein QFtp, aber beides?

Zum Problem: Einfach nochmal qmake ausführen, nachdem du das Q_OBJECT in den Header geschrieben hast. Sollte das noch nicht helfen, lösch das Makefile und führ nochmal qmake aus.
In jedem Fall ist das Q_OBJECT unbedingt notwendig, da QObject einige virtuelle Funktionen deklariert, die in der Abgeleiteten Klasse zwingend implementiert werden müssen dafür braucht es das Q_OBJECT und moc.
24dan
Beiträge: 274
Registriert: 26. Juni 2006 14:15
Wohnort: Hamburg

Beitrag von 24dan »

Okay dank. :oops: :oops: :oops: :oops: :oops: :oops: :oops: :oops:

Meine NEUE eigene ftp Klasse:
Problem: commandFinished(int,bool) wird wohl nicht ausgeführt.
Header

Code: Alles auswählen

#ifndef UPDATE_H
#define UPDATE_H

#include <QtNetwork>
#include <QObject>

QT_BEGIN_NAMESPACE
class QFile;
class QFtp;
QT_END_NAMESPACE

class UpdateSW : public QObject {

    Q_OBJECT

public:
      UpdateSW();

signals:
      void meldungsDienst(int,QString);
public slots:
      void download();
      void ftpFinished(int, bool);

private: 
    QFtp ftp;

};

#endif // UPDATE_H
Source Code:

Code: Alles auswählen

#include <QtGui>
#include <QtNetwork>
#include "update.h"

UpdateSW::UpdateSW() : QObject()
{
}

void UpdateSW::download()
{  connect(&ftp,SIGNAL(commandFinished(int,bool)),this,SLOT(ftpFinished(int,bool)));
    ftp.connectToHost("server.net");
    emit meldungsDienst(1, "status1");
}

void UpdateSW::ftpFinished(int id, bool error)
{
    emit meldungsDienst(1, "status2");
    if (!error){
        if (ftp.currentCommand() == QFtp::ConnectToHost){
            emit meldungsDienst(1, "status3");
        }
    }
}
Ich vermute das Problem liegt beim Objekt ftp der Klasse QFtp das entweder garnicht zum Zeitpunkt existiert oder noch nicht geschaffen wurde. Ich dachte wenn ich es im Header einmal drin habe kann ich es gleich nutzen? :oops:
"Der erste Trunk aus dem Becher der Naturwissenschaften macht atheistisch, aber auf dem Grund des Bechers wartet Gott."
(W. Heisenberg)
honda71
Beiträge: 49
Registriert: 12. Juli 2006 16:16

Beitrag von honda71 »

Wird Dein Signal meldungsDienst(1, "status1") ausgeführt?
Oder fehlt nur das Signal mit status2 und status3?
Wenn alle fehlen, dann tippe ich auf ein fehlenden Eventloop...
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Code: Alles auswählen

#include <QtNetwork>

QT_BEGIN_NAMESPACE
class QFtp;
QT_END_NAMESPACE 
und warum das? QFtp kommt mit dem QtNetwork-include. Da brauchst du die forward-declaration nicht wirklich... Lass die einfach weg.

Ansonsten kannst du versuchen, ob andere SIGNALS ankommen. Falls nicht hast du auch wirklich ne laufende Eventloop?
Falls alles in Ordnung ist fehlen die entscheidenden Stücke Code...
24dan
Beiträge: 274
Registriert: 26. Juni 2006 14:15
Wohnort: Hamburg

Beitrag von 24dan »

Also es kommt nur status1 an 2 und 3 fehlen.

class QFtp habe ich rausgenommen.

Eventloop?

Das ganze wird in meiner:

Code: Alles auswählen

void MainWindow::runa()
{
    UpdateSW h;
    connect(&h,SIGNAL(meldungsDienst(int,QString)) ,this,SLOT(status(int,QString)));
    h.download();
}
im Hauptprogramm ausgeführt (hier an einen Menüeintrag gebunden)

Code: Alles auswählen

connect(ui->action_ftp, SIGNAL(triggered()), this, SLOT(runa()));

:cry:
"Der erste Trunk aus dem Becher der Naturwissenschaften macht atheistisch, aber auf dem Grund des Bechers wartet Gott."
(W. Heisenberg)
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

connecte doch auch mal auf stateChanged(), damit du siehst wo es evtl. hängt.
Es gibt auch den errorString().

Dass du dein Signal emittest und dieses ankommt heißt gar nix. denn connectToHost() geht sofort wieder zum Aufrufer zurück und arbeitet den Rest asynchron ab.

OH GOTT, jetzt fällts mir auf...

Code: Alles auswählen

void MainWindow::runa()
{
    UpdateSW h;
    connect(&h,SIGNAL(meldungsDienst(int,QString)) ,this,SLOT(status(int,QString)));
    h.download();
} 
Nochmal, wie lange lebt "h"?
24dan
Beiträge: 274
Registriert: 26. Juni 2006 14:15
Wohnort: Hamburg

Beitrag von 24dan »

HAAAAAAAHHHHH

...es ist doch sofort tod!!!

Was soll ich den machen?

Als :

Code: Alles auswählen

private:
UpdateSW *h;
in die Header von MainWindow?
und dann mit
h = new UpdateSW;
im MainWindow::MainWindow() initalisieren?

Ich habe es wohl noch nicht verstanden!
:roll:
"Der erste Trunk aus dem Becher der Naturwissenschaften macht atheistisch, aber auf dem Grund des Bechers wartet Gott."
(W. Heisenberg)
24dan
Beiträge: 274
Registriert: 26. Juni 2006 14:15
Wohnort: Hamburg

Beitrag von 24dan »

YEAHRRRRRRRRRRRrrrrrrrrrrrRrrrrrrRRrRRrRrrrrrrrrrRräääääähhhhrrrrrrr

:shock: :shock: :) :D :lol:

Und ich danke nochmals für die Geduld mit mich.
siehe Anhang
Dateianhänge
h_lebt.JPG
h_lebt.JPG (6.25 KiB) 8639 mal betrachtet
"Der erste Trunk aus dem Becher der Naturwissenschaften macht atheistisch, aber auf dem Grund des Bechers wartet Gott."
(W. Heisenberg)
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Ein Member objekt ist in Fällen solch enger Kooperation nie schlecht. Da das Updater-Objekt aber nur selten benötigt wird, machst du das als Pointer (der braucht nur wenig Platz) und Initialisierst es bei Bedarf und löschst es danach wieder brav.

Alternativ kannst du es ruhig in deiner Funktion lokal aber ebenfalls als Pointer belassen. Der Speicher wird nicht gelöscht, wenn die Funktion beendet ist. Einzig: Du kannst das Objekt nicht mehr aus MainWindow heraus löschen.
Da gibt es jetzt nen kleinen Trick:
Dein Updater weiß wann er fertig ist. Nämlich wenn das Update abgeschlossen ist ;) Das kriegst du ja wohl hoffentlich mit. Danach ein einfaches "this->deleteLater();" und im nächsten Durchgang der Eventloop wird das Objekt zerstört. Basta. (Kannste im Destruktor ne Meldung ausgeben, dass du siehst dass es wirklich klappt!)
24dan
Beiträge: 274
Registriert: 26. Juni 2006 14:15
Wohnort: Hamburg

Beitrag von 24dan »

Destruktor:

habe mir jetzt einen in meiner Klasse UpdateSW angelegt und rufe den jetzt mal testweise (eigentlich ja auch noch unter ftp-SIGNAL done()) in commandFinished() auf wenn ein Fehler bei der Kommunikation aufgetreten ist:

Code: Alles auswählen


//! Destruktor von UpdateSW
//! Loescht die Objekte der Klasse richtig!
//! Wird aufgerufen wenn Update beendet oder beim Fehler
UpdateSW::~UpdateSW()
{
    //! Objekt von Klasse UpdateSW wird am Ende von
    //! Software Update richtig gelöscht

    this->deleteLater();

}


//! Starten des downloads vom ftp server
void UpdateSW::download()
{
    connect(&ftp,SIGNAL(commandFinished(int,bool)),this,SLOT(ftpFinished(int,bool)));
    ftp.connectToHost("server.net");
    emit meldungsDienst(1, "status1");
}


//! Abfangen des commandFinished von ftp Aktionen
/*!
\param id int des aktuellen ftp Kommandos
\param error bool Fehler bei der ftp Kommunikation
*/
void UpdateSW::ftpFinished(int id, bool error)
{
    emit meldungsDienst(1, "status2");
    if (!error){
        if (ftp.currentCommand() == QFtp::ConnectToHost){
            emit meldungsDienst(1, "Connect");
            ftp.login("user","passwd");
        }
    }
    if (error)
        emit meldungsDienst(3,"Schlecht gelaufen");
        

        ~UpdateSW();


}
stuff...
Ist das so zu verstehen? :roll:
"Der erste Trunk aus dem Becher der Naturwissenschaften macht atheistisch, aber auf dem Grund des Bechers wartet Gott."
(W. Heisenberg)
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Nö...
Eher so:

Code: Alles auswählen

UpdateSW::~UpdateSW()
{
    qDebug() << "UdateSW wird zerstört...\n DIE DIE DIE!!!";
}

void UpdateSW::updateFinished()
{
    // irgendwas sonst irgendwiewowarum
    deleteLater();
    // ACHTUNG JETZT NICHT MEHR VERWENDEN! Nächste Runde bin ich tot!
}
24dan
Beiträge: 274
Registriert: 26. Juni 2006 14:15
Wohnort: Hamburg

Beitrag von 24dan »

:D
"Der erste Trunk aus dem Becher der Naturwissenschaften macht atheistisch, aber auf dem Grund des Bechers wartet Gott."
(W. Heisenberg)
Antworten