Seite 1 von 1
[gelöst] Private ftp Klasse vtable Fehler
Verfasst: 24. Dezember 2009 12:36
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
Hat jemand einen Tip?
Verfasst: 24. Dezember 2009 16:53
von Burgpflanze
In der Klassendefinition fehlt Q_OBJECT.
Re: Private ftp Klasse vtable Fehler
Verfasst: 24. Dezember 2009 17:00
von franzf
Code: Alles auswählen
class UpdateAdler : public QFtp
{
[...]
QFtp *ftp;
[...]
};
Das ist das skurrilste Klassendesign das ich bisher gesehen habe

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.
Verfasst: 26. Dezember 2009 19:26
von 24dan
Okay dank.
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?

Verfasst: 26. Dezember 2009 20:31
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...
Verfasst: 26. Dezember 2009 20:41
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...
Verfasst: 26. Dezember 2009 21:07
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()));

Verfasst: 26. Dezember 2009 21:30
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"?
Verfasst: 26. Dezember 2009 21:47
von 24dan
HAAAAAAAHHHHH
...es ist doch sofort tod!!!
Was soll ich den machen?
Als :
in die Header von MainWindow?
und dann mit
h = new UpdateSW;
im MainWindow::MainWindow() initalisieren?
Ich habe es wohl noch nicht verstanden!

Verfasst: 26. Dezember 2009 21:55
von 24dan
Verfasst: 26. Dezember 2009 22:02
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!)
Verfasst: 26. Dezember 2009 22:30
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?

Verfasst: 26. Dezember 2009 22:36
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!
}
Verfasst: 26. Dezember 2009 22:58
von 24dan