Seite 1 von 1
Slot erfolgreich connected, wird aber nicht ausgeführt
Verfasst: 9. Juni 2010 13:25
von dd0815
Hallo zusammen,
eigentlich will ich fürs Erste nur ein Log-Fenster haben, dass von mehreren Klassen Meldungen empfangen kann. Das QTextEdit ist in der Klasse "mainWindow". Alle anderen Klassen werden in dieser Klasse instanziiert:
(Konstruktor der Klasse mainWindow)
Code: Alles auswählen
komm k; // Klasse für die UDP-Kommunikation
connect(&k, SIGNAL(log(const QString&)), this, SLOT(writeLog(const QString&)));
k.emitLog();
Das funktioniert, die letzte Zeile ruft die "emitLog" Methode von "k" aus , die das Signal "log" abschickt, welches auch durch den Slot "writeLog" der Klasse "MainWindow" korrekt angezeigt wird.
Jetzt möchte ich aber auf Tastendruck (die Taste "lebt" in der Klasse "mainWindow") den Slot "broadcastDatagram" in der Klasse "k" aufrufen:
(immer noch im Konstruktor der Klasse mainWindow)
Code: Alles auswählen
bool check = connect(startButton, SIGNAL(clicked()), &k, SLOT(broadcastDatagram()));
if (!check) {textEdit->append("connect nicht erfolgreich");}
else {textEdit->append("connect erfolgreich");}
k.broadcastDatagram();
Das connect war erfolgreich, aber beim Tastendruck passiert nichts. Wenn ich jedoch wie in der letzten Codezeile zu sehen ist, den Slot bzw. die Methode direkt aufrufe wird diese korrekt durchlaufen. Und wenn ich die Taste an den Slot "close()" hänge, wird die Applikation auch geschlossen...
Das ich (noch) Verständnisprobleme und (noch) wenig Ahnung vom Software-Strukturierung habe ist klar, aber das sollte doch eigentlich funktionieren? Oder ist doch in der Reihenfolge etwas falsch?
Ist das nicht egal wo der connect-Befehl steht, ob nun beim Objekt 1 oder Objekt 2 oder darüber?

rgendwie beziehen sich alle gesichteten Beispiele immer auf dieselbe Klasse)
bis dann,
dd0815
Verfasst: 9. Juni 2010 13:42
von franzf
Dein "komm k;" überlebt den Konstruktor nicht. Das muss in den Freispeicher (mit "new").
Verfasst: 9. Juni 2010 13:58
von dd0815
Danke für die schnelle Antwort , jetzt gehts...
Speicherfreigabe
Verfasst: 9. Juni 2010 14:52
von dd0815
Hallo nochmal,
bin grade über das Thema Speicherfreigabe gestolptert. Meine eigene Klasse "k" müßte ich ja nun mittels delete wieder freigeben. Dafür habe ich ein Destruktor der Klasse "mainWindow" angelegt und da "delete k" reingeschrieben. Beim Ausführen bzw. beim Beenden bekomme ich nun die wunderschöne Fehlermeldung "... hat ein Problem festgestellt und muss beendet werden".
Ich vermute, dass ich den bereits vorhandenen Destruktor überschrieben habe und somit die ganzen Qt Widgets nicht mehr richtig gelöscht werden?
Was mich nun wieder zu der Softwarestruktur-Frage bringt. Sinnvoll ist die Hierarchie
mainWindow (alle Widgets)
- Klasse k
- Klasse m..n
nicht wirklich, oder? (ich würde mich gern über das Thema belesen...)
->dd0815
Verfasst: 9. Juni 2010 15:18
von franzf
Kannst du mal Klassendefinition und Konstruktordefinition zeigen? Ich nehme an, du hast nen Member "komm *k;", deklarierst aber im Konstruktor ein neues Objekt.
Eine bessere Herangehensweise wäre, komm einfach dein mainWindow (also "this") als parent mitzugeben. Ein QObject zerstört automatisch alle children. Wenn jetzt "komm *k" dein mainWindow als parent bekommt, wird k automatisch zerstört, sobald mainWindow zerstört wird.
Das ist eine Eigenart, die QObject mitbringt, und kein C++-Automatismus, sobald du irgend welche parent<->child-Beziehungen hast - nur mal so am Rande

Verfasst: 9. Juni 2010 15:56
von dd0815
Hier die Klassendefinition von mainWindow
Code: Alles auswählen
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QDialog>
#include "komm.h"
#include "datei.h"
QT_BEGIN_NAMESPACE
class QDialogButtonBox;
class QLabel;
class QPushButton;
class QTextEdit;
QT_END_NAMESPACE
class mainWindow : public QDialog
{
Q_OBJECT
public:
mainWindow(QWidget *parent = 0);
// ~mainWindow();
private:
QLabel *statusLabel;
QPushButton *startButton;
QPushButton *quitButton;
QDialogButtonBox *buttonBox;
QTextEdit *textEdit;
komm *k;
datei *d;
public slots:
void writeLog(const QString&);
};
#endif // MAINWINDOW_H
(Konstruktordefinition)
Code: Alles auswählen
mainWindow::mainWindow(QWidget *parent)
: QDialog(parent)
{...}
Dass Qt dieses Autodelete mitbringt ist klar, unklar war nur das Verfahren bzw. das Vermischen von Klassen die vom QObject abgeleitet waren mit eigenen Klassen.
Ein Member komm *k habe ich. Wie ich Deiner Frage entnehmen kann brauche ich dann kein neues Objekt? (Du merkst, da fehlen wirklich die Basics - komme ja auch aus der Automatisierungstechnik

). Aber ohne das neue Objekt ist zwar Kompilieren möglich, aber beim Start stürzt das Programm gleich ab.
dd0815
Verfasst: 9. Juni 2010 16:36
von franzf
Bei deinem Konstruktor hätte mich eben genau das zwischen den Klammern interessiert

(das gehört ja eben zur Definition)
Code: Alles auswählen
class mainWin : public QDialog
{
Q_OBJECT
komm *k;
/// usw.
};
mainWin::mainWin(QWidget* parent)
: QObject(parent)
{
komm *k = new komm(this); // 1)
k = new komm(this); // 2)
}
1) k ist ein NEUES Objekt, hat nix mit deinem Member gleichen Namens zu tun. Im Scope des Konstruuktors überdeckt das dort deklarierte k den Member.
Dadurch bleibt natürlich dein Member
uninitialisiert! Das führt dazu, dass bei einem "delete k" im Destruktor dein Programm crasht.
2) Das willst du

Das deklariert kein neues Objekt sondern initialisiert direkt den Member deines mainWin.
Ich denke du hast das 1) in deinem Konstruktor stehen. Wenn nicht liegt der Fehler wahrscheinlich wo anders.
Verfasst: 9. Juni 2010 16:59
von dd0815
Hier nochmal der Konstruktor komplett
Code: Alles auswählen
mainWindow::mainWindow(QWidget *parent)
: QDialog(parent)
{
// ##### UI definieren #####
setWindowTitle(tr("Test Leitsystem"));
startButton = new QPushButton(tr("&Start"));
quitButton = new QPushButton(tr("&Quit"));
textEdit = new QTextEdit;
// ##### Klassen definieren & UI-Signale #####
komm *k = new komm;
connect(k, SIGNAL(log(const QString&)), this, SLOT(writeLog(const QString&)));
k->emitLog();
QVBoxLayout *mainLayout = new QVBoxLayout;
// mainLayout->addWidget(buttonBox);
mainLayout->addWidget(startButton);
mainLayout->addWidget(quitButton);
mainLayout->addWidget(textEdit);
setLayout(mainLayout);
//bool check = connect(startButton, SIGNAL(clicked()),
// this, SLOT(writeLog(const QString&)));
bool check = connect(startButton, SIGNAL(clicked()), k, SLOT(broadcastDatagram()));
if (!check) {textEdit->append("connect nicht erfolgreich");}
else {textEdit->append("connect erfolgreich");}
// k->broadcastDatagram();
// connect(startButton, SIGNAL(clicked()), this, SLOT(close()));
connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
// ##### UI Layout #####
/*buttonBox = new QDialogButtonBox;
buttonBox->addButton(startButton, QDialogButtonBox::ApplyRole);
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
*/
datei *d = new datei;
d->schreiben();
}
Hast richtig vermutet das ich Variante 1 drin hatte...
Ich werde jetzt mal pausieren bis morgen und Variante 2 umsetzen. Besten Dank schonmal für Deine Hilfe, ohne die ich noch endlos weiter rumstochern würde ohne weiterzukommen

st schon frustrierend nicht zu wissen
wie man anfangen soll zu lernen, denn auf solche Anfänger-Fragen / -Fehler kann kein Handbuch eingehen).
Einen schönen Abend noch,
::dd0815::
Doch noch schnell ...
Verfasst: 9. Juni 2010 17:09
von dd0815
Funktioniert leider nicht, da die Konstruktoren meiner eigenen Klassen nichts erwarten ("no matching funktion for call komm::komm(mainWindow * const)
Hier mal die "eigene" Klasse Kommunikation:
Code: Alles auswählen
#ifndef KOMM_H
#define KOMM_H
#include <QDialog>
#include <QtNetwork>
// #include <QTimer>
QT_BEGIN_NAMESPACE
class QTimer;
class QUdpSocket;
QT_END_NAMESPACE
class komm : public QDialog
{
Q_OBJECT
public:
komm();
QTimer *timer;
void emitLog();
public slots:
void broadcastDatagram();
signals:
void log( const QString& );
private slots:
void processPendingDatagrams();
private:
QUdpSocket *udpSocket;
int messageNo;
};
#endif // KOMM_H
Und hier dessen Konstruktor:
Code: Alles auswählen
komm::komm()
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(44444, QUdpSocket::ShareAddress);
timer = new QTimer(this);
messageNo = 1;
connect(udpSocket, SIGNAL(readyRead()),
this, SLOT(processPendingDatagrams()));
}
Ich weiß jetzt auch gar nicht, wie ich diese erweitern kann...
::dd0815::
Ziel
Verfasst: 9. Juni 2010 17:26
von dd0815
Ich erzähl einfach mal kurz, was ich überhaupt so insgesamt Schlimmes vorhabe

ch hoffe Du / Ihr nehmt es nicht übel, wenn ich nicht nur den kleinen Finger, sondern mal die ganze Hand nehme).
Ich möchte eine modulare Software erstellen, die auf unterster Ebene die Kommunikation (UDP) abwickelt und die die Messages irgendwie für eine Logik- Ebene bereitstellt (Stichworte Middleware, IPC - mir grausts schon). Diese wiederum ist in Kontakt mit einer Visualisierungsebene bzw. tauscht mit anderen Kommunikationsebenen (z.B. Dateien im XML-Format) oder Datenhaltungsebenen (Dateien, SQL) Daten aus. Die "Ebenen" sollen unabhängig voneinander laufen können und somit einzeln erweiterbar sein. Wie die Ebenen miteinander reden können in welchem Format verschwimmt im meinem geistigen Nebel, weil das schon ganz weit von meinem jetztigen Kenntnisstand ist.
Also, falls Ihr Wissensträger mal einige Schlagworte fallen lassen könntet, wäre ich dankbar, ansonsten vergeßt mal diese Posting...
Re: Doch noch schnell ...
Verfasst: 9. Juni 2010 18:10
von franzf
dd0815 hat geschrieben:
Funktioniert leider nicht, da die Konstruktoren meiner eigenen Klassen nichts erwarten ("no matching funktion for call komm::komm(mainWindow * const)
Jut

Dann musst du dir den so schreiben (funktioniert genauso wie bei mainWindow), oder du lässt den Parameter weg und kümmerst dich selber ums Zerstören. Heißt ein "delete k" im Destruktor von mainWindow.
Verfasst: 10. Juni 2010 07:23
von dd0815
Habe den Konstruktor der Klasse "komm" nun so erweitert:
(Deklaration)
(in .cpp)
Ich benutze Qt Creator und der färbt in der .cpp das parent in "komm::komm(QWidget *parent)" grau, was bedeutet das? Laut Einstellungen vom Qt Creator TextEditor "nicht verwendet". Er kompilierts und es geht, aber kann ich nun sicher sein, dass die mit
"k = new komm(this);" initialisierte Instanz automatisch deleted wird?

n der mainWindow Klasse ist er nicht grau)
Noch einmal die Frage: Wenn ich nun in der mainWindow-Klasse den Destruktor selbst baue, wird dann nicht der von Qt "automatisch" generierte Destruktor überschrieben und somit bleiben alle Widgets im Freispeicher hängen?
Verfasst: 10. Juni 2010 07:29
von Christian81
wenn parent grau ist wird die Variable nicht verwendet. Mann muss sie schon dem QObject/QWidget/Basisklassen ctor weitergeben...
Verfasst: 10. Juni 2010 07:34
von franzf
dd0815 hat geschrieben:Ich benutze Qt Creator und der färbt in der .cpp das parent in "komm::komm(QWidget *parent)" grau, was bedeutet das? Laut Einstellungen vom Qt Creator TextEditor "nicht verwendet". Er kompilierts und es geht, aber kann ich nun sicher sein, dass die mit
"k = new komm(this);" initialisierte Instanz automatisch deleted wird?

n der mainWindow Klasse ist er nicht grau)
Wenn du wie im mainWindow den Basisinitialisierer verwendest, sollte parent verwendet sein. Ansonsten hängst du dich auch nicht an das parent und wirst nicht automatisch zerstört.
Code: Alles auswählen
komm::komm(QWidget* parent=0)
: QDialog(parent) // Basisinitialisierer
{
///
}
Noch einmal die Frage: Wenn ich nun in der mainWindow-Klasse den Destruktor selbst baue, wird dann nicht der von Qt "automatisch" generierte Destruktor überschrieben und somit bleiben alle Widgets im Freispeicher hängen?
Der "automatisch generierte" Destruktor macht einfach gar nix

Deshalb ist es auch kein Problem, den selber zu implementieren. Aber nur wenn du auch was eigenes machen willst/musst, wenn das Objekt zerstört wird, ansonsten bringts nix.
Destruktoren werden in der Vererbungshierarchie beim Zerstören eines Objektes übrigens automatisch rückwärts aufgerufen:
delete komm ruft zuerst komm::~komm auf. Dann automatisch QDialog::~QDialog, QWidget::~QWidget, QObject::~QObject. Zum Schluss wird der Speicher, den das Objekt "k" belegt hat, freigegeben. Wäre ja ein Witz, wenn ein eigener Destruktor das Speichermanagement durcheinanderhauen würde

Verfasst: 10. Juni 2010 15:52
von dd0815
@franzf: Ich danke vielmals für Deine Ausdauer, jetzt gehts und fängt an Spaß zu machen
