PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : qt Probleme mit dem moc



javatar
22-05-2013, 21:49
Hallo zusammen,

ich entwickle gerade ein Programm, für das ich die qt Bibliothek verwende. Da ich damit bisher noch nie ernsthaft gearbeitet habe funktioniert natürlich nix. Da ich keine Erfahrungen habe komme ich alleine leider auch nicht weiter.
In dem Projekt sollen verschiedene Klassen ein Signal emitieren, wenn sich bestimmte Daten ändern und eine zentrale Klasse soll das dann (zunächst nur als Terminalausgabe) Darstellen. Dazu die Headerdatei


#ifndef DARSTELLUNG_H_
#define DARSTELLUNG_H_
#include <iostream>

class Darstellung{
Q_OBJECT
private:
int *status;
void out();
public:
Darstellung();
public slot:
void setStatus(int, int);
};
#endif

und die Quelldatei

#include "Darstellung.h"

Darstellung::Darstellung() {
status = new int[4];
for(int i=0; i<5; i++){
status[i] = 0;
}
}

void Darstellung::setStatus(int n, int s){
status[n] = s;
out();
}

void Darstellung::out(){
for(int i=0; i<5; i++){
std::cout << status[i] << " ";
}
std::cout << std::endl;
}

versuche ich das nun über

qmake -project
qmake
make
zu kompilieren kommen die folgenden Fehlermeldungen:

g++ -c -m64 -pipe -O2 -Wall -W -D_REENTRANT -DQT_WEBKIT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++-64 -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -I. -o Darstellung.o Darstellung.cpp
In file included from Darstellung.cpp:8:0:
Darstellung.h:20:8: Fehler: expected »:« before »slot«
Darstellung.h:20:8: Fehler: »slot« bezeichnet keinen Typ
Darstellung.cpp:17:41: Fehler: keine Elementfunktion »void Darstellung::setStatus(int, int)« in Klasse »Darstellung« deklariert
make: *** [Darstellung.o] Fehler 1


Natürlich bezeichnet slot keinen Typ, aber diese Schlüsselwörter sollten doch eigentlich durch den moc ersetzt werden, dafür setzt man doch extra das Q_OBJECT? Muss man den moc irgendwie speziell aufrufen? So wie ich das verstanden hatte reichen die 3 Zeilen.

Mit freundlichem Gruß
Javatar

locus vivendi
23-05-2013, 11:06
Es sollte "slots" in der Mehrzahl heißen, oder "Q_SLOT" vor jedem Slot einzeln. Q_SLOT hat den Vorteil das es sich als Makro an die verbreitete Großbuchstaben-Konvention hält, für "slots" (ebenfalls ein Makro) ist das nicht der Fall.

Also Beispiel:
class Darstellung{
Q_OBJECT
private:
int *status;
void out();
public:
Darstellung();

Q_SLOT void setStatus(int, int);
};


Nachtrag am 30.05: anda_skoa hat Recht in seinen beiden Beiträgen unten. Hier müsste noch mehr ausgebessert werden.

javatar
23-05-2013, 14:30
Vielen Dank für die schnelle Antwort. Ich hasse es, wenn es an so kleinen Schreibfehlern scheitert :mad: Die übrigen Fehler (aufrufen des mocs und einbinden der .moc anstelle der .h) habe ich jetzt noch selbst korrigiert. Jetzt kann ich endlich anfangen die logischen Fehler im Programm zu korrigieren.

anda_skoa
29-05-2013, 17:37
Q_SLOT hat den Vorteil das es sich als Makro an die verbreitete Großbuchstaben-Konvention hält, für "slots" (ebenfalls ein Makro) ist das nicht der Fall.


Es gibt Q_SLOTS

Der ursprüngliche Code hatte auch noch das Problem, dass #include <QObject> gefehlt hat und Darstellung keine QObject Subklasse war.

Ciao,
_

anda_skoa
29-05-2013, 17:41
Natürlich bezeichnet slot keinen Typ, aber diese Schlüsselwörter sollten doch eigentlich durch den moc ersetzt werden, dafür setzt man doch extra das Q_OBJECT? Muss man den moc irgendwie speziell aufrufen? So wie ich das verstanden hatte reichen die 3 Zeilen.


Die Präprozessor Definitionen sind in der Datei qglobal.h, die indirekt über QObject oder eine davon abgeleitet Klasse inkludiert wird.

Die drei Checklistenpunkte für Qt Slots sind immer

QObject Subklasse (direkt oder indirekt)
Q_OBJECT Macro
public/protected/private slots/Q_SLOTS Sektion


Für Signale gelten die ersten beiden Punkte plus signals/Q_SIGNALS Sektion

Ciao,
_

javatar
02-06-2013, 11:44
Hallo nochmal,

ich habe jetzt noch ein weiteres Problem mit den Signal/Slots in Verbindung mit Threads. Die Threads sollen ein signal emittieren, dass eine andere Klasse dann fängt, allerdings kommt es da scheinbar nie an.
Habe dazu auch schon viel ergoogelt, allerdings habe ich entweder die Lösungen nicht verstanden, sie haben nicht funktioniert, es gab gar keine oder das Problem lag woanders.

Im Anhang befindet sich eine kleines Testprogramm, als Ausgabe hätte ich gerne ein paar mal die 1, allerdings kommt einfach gar nichts. Wäre super, wenn es auch dafür eine einfache Lösung gäbe.

Liebe Grüße

Edit: Kann mir auch noch jemand kurz erklären, warum cout Ausgaben nicht mehr im Terminal erscheinen, sonderm man stattdessen qDebug verwenden muss. Ich muss mein Programm, wenn es mal fertig ist, anderen Leuten vorstellen und da wäre es natürlich gut, wenn ich sowas auch begründen könnte

locus vivendi
02-06-2013, 19:33
Ich kenne mich mit Qmake nicht aus, aber ich glaube in deiner Beispiel.pro muss noch eine "CONFIG += qt"-Zeile hinein. Siehe hier:
http://qt-project.org/doc/qt-4.8/qmake-tutorial.html


Kann mir auch noch jemand kurz erklären, warum cout Ausgaben nicht mehr im Terminal erscheinen, sonderm man stattdessen qDebug verwenden muss. Ich muss mein Programm, wenn es mal fertig ist, anderen Leuten vorstellen und da wäre es natürlich gut, wenn ich sowas auch begründen könnte

Stichwort "Pufferung".

Es dünkt mich übrigens, dass dein Beispielprogramm kein besonders gelungenes Beispiel für Nebenläufigkeit ist, weil du direkt nach dem Starten jedes einzelnen Threads auf dessen Ende wartest. Im Effekt werden also die Threads hintereinander ausgeführt, und nicht parallel. Natürlich könnte das auch Absicht sein, ich wollte es trotzdem erwähnen.

anda_skoa
03-06-2013, 09:23
ich habe jetzt noch ein weiteres Problem mit den Signal/Slots in Verbindung mit Threads. Die Threads sollen ein signal emittieren, dass eine andere Klasse dann fängt, allerdings kommt es da scheinbar nie an.


Für Signal/Slot Verbindungen zwischen Objekten in zwei Threads gibt es mehr oder weniger zwei Möglichkeiten:

Direkte Verbindung
Indirekte Verbindung


Bei ersterem erfolgt der Slotaufruf wie im Singlethread Fall direkt, d.h. der Thread, der emit ausführt, führt auch den Slot aus.
Erreicht wird das durch Angabe von Qt::DirectConnection als fünften Parameter von conenct().

Logischerweise obliegt es dann dem Applikationscode die Threadsicherheit zu gewährleisten.

Bei der zweiten Möglichkeit (normales connect() oder Angabe von Qt::QueuedConnection als fünften Parameter) werden die Argumente des Signals mittels Event an das Empfängerobjekt geschickt, der Aufruf des Slots erfolgt damit im Zielthread.

Die Vorraussetzung dafür ist das Laufen der Eventverarbeitung im Zielthread. Im Falle des Hauptthreads ist das üblicherweise durch app.exec() gewährleistet (was in deinem Fall fehlt).



Edit: Kann mir auch noch jemand kurz erklären, warum cout Ausgaben nicht mehr im Terminal erscheinen, sonderm man stattdessen qDebug verwenden muss. Ich muss mein Programm, wenn es mal fertig ist, anderen Leuten vorstellen und da wäre es natürlich gut, wenn ich sowas auch begründen könnte

Funktioniert bei mir einwandfrei wenn ich qDebug() durch cout ersetze und << endl am Ende der Zeile hinzufüge.

Ciao,
_

javatar
03-06-2013, 19:35
Vielen dank erstmal für die guten Rückmeldungen.


Es dünkt mich übrigens, dass dein Beispielprogramm kein besonders gelungenes Beispiel für Nebenläufigkeit ist, weil du direkt nach dem Starten jedes einzelnen Threads auf dessen Ende wartest
Da hast du natürlich vollkommen Recht, dieser Fehler ist erst beim erstellen dieses "Minimalbeispiels" entstanden, da ich dort alle Schleifen möglichst zusammenfassen wollte. Trotzdem danke für den Hinweis.


Erreicht wird das durch Angabe von Qt::DirectConnection als fünften Parameter von conenct().
Logischerweise obliegt es dann dem Applikationscode die Threadsicherheit zu gewährleisten.
Das ist quasi die Variante, die ich erwartet hatte. Für die Threadsicherheit würde es doch genügen, einfach in dem Slot am Anfang einen Mutex zu sperren oder?


Bei der zweiten Möglichkeit (normales connect() oder Angabe von Qt::QueuedConnection als fünften Parameter) werden die Argumente des Signals mittels Event an das Empfängerobjekt geschickt, der Aufruf des Slots erfolgt damit im Zielthread.

Die Vorraussetzung dafür ist das Laufen der Eventverarbeitung im Zielthread. Im Falle des Hauptthreads ist das üblicherweise durch app.exec() gewährleistet (was in deinem Fall fehlt).
Kannst du das vielleicht noch etwas genauer erklären? Wo müsste in dem Beispiel der exec-Aufruf erfolgen?


Funktioniert bei mir einwandfrei wenn ich qDebug() durch cout ersetze und << endl am Ende der Zeile hinzufüge.
Da hast du wohl recht, ich weiß gerade aber auch nicht mehr ganz genau wie ich auf die Idee kam, dass das nicht funktionieren würde.

anda_skoa
04-06-2013, 10:50
Das ist quasi die Variante, die ich erwartet hatte. Für die Threadsicherheit würde es doch genügen, einfach in dem Slot am Anfang einen Mutex zu sperren oder?

Ja.



Kannst du das vielleicht noch etwas genauer erklären? Wo müsste in dem Beispiel der exec-Aufruf erfolgen?


Üblicherweise sieht die main Funktion eines Qt Programms in etwas so aus


int main(int argc, char **argv)
{
QCoreApplication app(argc, argv); // oder QApplication wenn GUI benutzt wird

// objekt(e) erzeugen

return app.exec(); // Eventverarbeitung starten.
}


Ciao,
_

javatar
04-06-2013, 20:10
Sehr gut mein Programm funktioniert jetzt (glaube ich) erstmal als Terminalversion. Im nächsten Schritt muss ich jetzt "nur" noch eine GUI schreiben.
Nochmal danke für die freundliche Betreuung, jetzt ist mir endlich auch klar, wofür man die QApplication braucht.

Liebe Grüße