Extern auf GUI-Elemente zugreifen

Du bist neu in der Welt von C++? Dann schau hier herein!
GGStefan
Beiträge: 22
Registriert: 31. August 2012 23:59
Wohnort: Brandenburg (LDS)

Extern auf GUI-Elemente zugreifen

Beitrag von GGStefan »

Hallo an alle hier im Forum,

ich habe angefangen mit QT4 zu programmieren, und habe auch schon einiges mit Hilfe von Google lösen können. Außerdem habe ich mir auch das Buch QT4.6 GUI-Entwicklung mit C++ zugelegt, allerdings noch nicht durch gelesen. Nach einigen umgesetzten Beispielen aus dem Buch und der in der QT Doku, habe ich angefangen jetzt ein eigenes Programm zu erstellen. Dieses soll dazu dienen eine Relaiskarte von Conrad über die RS232 zu steuern. Dabei habe ich bestimmt nicht ganz den richtigen Weg eingeschlagen da ich mit GUI begann.
Nun zu meinem eigentlichen Problem: Wie kann ich aus einer anderen CPP-DATEI (Klasse) auf die GUI-Elemente zugreifen. Ich möchte z.B. beim Signal clicked() eines QpushButton in der anderen CPP-Datei eine Methode z.B verbinden() aufrufen.
Ich weiß nicht ob das jetzt richtig beschrieben habe, was mein Problem ist und habe daher das Projekt mit im Anhang gepackt.
Vielleicht kann mir ja jemand dieses auf einfache Weise erklären.

Ich habe es jetzt soweit geschafft das wenn ich das Programm in einem Terminal starte es keine Fehlermeldungen mehr gibt. Auch beim Compilieren gibt es nur noch eine Warnung zu einer nicht benutzten Variable, dieses ist "TSteuerung" aus der steuerung.cpp. Diesen Teil mit der Klasse habe ich aus einem QT Tutorial aus dem Netz.

Vielen Dank schon einmal! GGStefan
Dateianhänge
Relais-Karte.tar.gz
Projekt zur Relaiskarten Ansteuerung
(188.91 KiB) 458-mal heruntergeladen
jerry42
Beiträge: 126
Registriert: 9. Oktober 2008 10:48

Re: Extern auf GUI-Elemente zugreifen

Beitrag von jerry42 »

Hi,

prinzipiell machst du so Verbindungen in Qt mit Signals und Slots:
http://doc.qt.nokia.com/4.7-snapshot/si ... slots.html

D.h. wenn Du zum Beispiel auf einen PushButton reagieren willst, könntest du z.B. im Konstruktor von RelaisKarte8 ein connect aufrufen, ungefähr so:
connect(ui->defaultButton, SIGNAL(clicked()), steuerungWidget, SLOT(buttonClicked());

Damit das funktioniert muss es natürlich den entsprechenden Slot in der Klasse mySteuerung geben. Ein Slot ist nichts weiter als eine Methode, die als Slot definiert wurde.
In steuerung.h müsstest du einfach die Methode hinter
"public slots:"
schreiben.

Also
public slots:
void buttonClicked();

Dann Implementierst du die Methode noch in steuerung.cpp und nun sobald du auf den defaultButton klickst, wird buttonClicked aufgerufen.

Hoffe, das war halbwegs verständlich :)

Noch ein Hinweis: Im Konstruktor von RelaisKarte8 definierst du die mySteuerung Variable lokal. Sobald du aus dem Konstruktor raus bist, ist die Variable ungültig.
Am besten steuerungWidget als Member der Klasse definieren und im Konstruktor nur noch initialisieren:
in .h:
mySteuerung *steuerungWidget;

und im Konstruktor in .cpp z.B.:
steuerungWidget = new mySteuerung(this);

Viele Grüße
jerry42
GGStefan
Beiträge: 22
Registriert: 31. August 2012 23:59
Wohnort: Brandenburg (LDS)

Re: Extern auf GUI-Elemente zugreifen

Beitrag von GGStefan »

Hallo Jerry42,

vielen Dank für die sehr ausführliche Antwort. Bin aus beruflichen Gründen noch nicht zum umsetzen gekommen, werde es aber am Wochenende probieren. Beim durchlesen ist mir aufgefallen das Du ein Signal und SLOT ohne Parameter verwendest, ich benötige ja die Werte der Comboboxen und werde mal sehen ob ich das hin bekomme. Wenn nicht melde ich mich noch einmal.

Danke GGStefan
GGStefan
Beiträge: 22
Registriert: 31. August 2012 23:59
Wohnort: Brandenburg (LDS)

Re: Extern auf GUI-Elemente zugreifen

Beitrag von GGStefan »

Hallo Jerry42,

vielen Dank für die Super Antwort, vor allem für das ausführliche schreiben. Habe es direkt einmal probiert, klappt soweit auch. Zumindestens bekomme ich keine Fehlermeldungen mehr. Nun stellt sich nartürlich gleich die nächste Frage!

Ich möchte z.B. beim klicken auf den Button connectButton der ui in meinem SLOT mySteuerung::verbinden die aktuell ausgewählten Werte der Comboboxen übergeben. In dem SLOT möchte ich dann entsprechend der gewählten einträge in den Comboboxen die entsprechende Schnitstelle und Baudrate usw. mit hilfe der LIB qextserial einstellen.

Mein Versuch es so zu lösen:

1.steuerung.h mit void verbinden(QString);
2.steuerung.cpp mit void mySteuerung::verbinden(QString port) {
QTextStream out(stdout);
out << "Port: " << port << endl; }
3.realaiskarte8.cpp mit QString port = ui->portComboBox->currentText(); und connect(ui->connectButton, SIGNAL(clicked()), steuerungWidget, SLOT(verbinden(QString port)));

Quitiert die Anwendung beim starten mit folgender Meldung: Object::connect: No such slot mySteuerung::verbinden(QString port)
Object::connect: (sender name: 'connectButton')

Mein erster Versuch es so zu lösen connect(ui->connectButton, SIGNAL(clicked()), steuerungWidget, SLOT(verbinden(QString ui->portComboBox->currentText()))); quitiert der Editor nur ROT unterstrichen.

Ich gehe doch mal davon aus das QT4 bei den SLOTS auch Parameter übergeben kann, oder?

Das Signal clicked() vom Button hat soweit ich das gesehen habe keine Parameter, ich denke ich muss mir irgendwie eigene Signale und Slots bauen, oder bin ich da völlig auf dem falschen Weg?

MfG GGStefan
Dateianhänge
Relais-Karte.tar.gz
Projekt mit den Änderungen
(191.47 KiB) 414-mal heruntergeladen
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Extern auf GUI-Elemente zugreifen

Beitrag von Christian81 »

MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
jerry42
Beiträge: 126
Registriert: 9. Oktober 2008 10:48

Re: Extern auf GUI-Elemente zugreifen

Beitrag von jerry42 »

Hi,

Du kannst nur passende Signals und Slots verbinden.
Das Signal muss alle benötigten Parameter des Slots beliefern. Andersrum kannst du aber Parameter von Signals ignorieren falls nötig.
Also SIGNAL(clicked(int)) --> SLOT(clicked())
sowas geht. Da geht dann halt Information verloren.

Bei dir hat das Button-Signal "clicked()" keinen Parameter. Dein Slot hat aber einen, bzw. du willst ihm einen mitgeben. Das geht so nicht.
Wo soll er den Parameter denn hernehmen. Das mit dem Einsetzen beim connecten geht so nicht.

Du musst es also entweder so machen, dass du deiner Steuerung einfach nur sagst, "verbinden" und die Steuerung holt sich die nötigen Infos selber wieder.
Oder du machst dir einen Slot in deiner RelaisKarte, und darin suchst Du dir die nötigen Infos zusammen und sendest ein eigens-definiertes Signal.
Und das kannst du dann mit deiner Steuerungsklasse wieder verbinden.
Ich würde Variante 2 bevorzugen, da Steuerung und Relaiskarte dann noch klarer voneinander getrennt sind.

Hoffe, das war einigermaßen verständlich.

Gruß
jerry42
GGStefan
Beiträge: 22
Registriert: 31. August 2012 23:59
Wohnort: Brandenburg (LDS)

Re: Extern auf GUI-Elemente zugreifen

Beitrag von GGStefan »

Hallo Christian81,

ich habe natürlich vor dem Posten die Online Hilfe gelesen, und zwar für V4.6, V4.7 und V4.8, was das umgehen mit Signalen und Slots betrifft. Auch wenn mein englisch nicht besonders ist, habe Anhand der Online Hilfe nicht erkennen können wie ich mein kleines Problem lösen kann. :(

Danke für die Antwort, GGStefan
GGStefan
Beiträge: 22
Registriert: 31. August 2012 23:59
Wohnort: Brandenburg (LDS)

Re: Extern auf GUI-Elemente zugreifen

Beitrag von GGStefan »

Hallo Jerry42,

vielen Dank für die weitere ausführliche Antwort. Das das Signal clicked() keine Parameter hat habe ich ja Anhand der Doku gesehen, nur ich will ja Parameter übergeben und habe versucht es irgendwie zu lösen. Im Grunde wollte ich es so machen wie Du im zweiten Beispiel schreibst, nur ist mir nicht ganz klar wie das genau gehen soll.
Das mit dem Slot in meiner Relaiskarte denke habe ich verstanden und mir auch so gedacht. Aber das mit dem eigens-definierten Signal ist mir wirklich nicht klar. :cry: Ich möchte es ja in Abhängigkeit vom clicken auf dem Button machen.

Habe erst einmal den Slot in Relaiskarte erstellt, hoffe das es so richtig ist und ich richtig verstanden habe.

Das mit den Slot und Signalen finde ich persönlich doch recht verwirrend, das Sie immer vom Rückgabetyp void sind. Mann kann daher ja keine Lösung wie:

Qstring port;

port = wertEinerMethode();

erstellen, wenn wertEinerMethode() z.B. einen Rückgabewert vom Typ Qstring hätte.

Mit freundlichen Gruß GGStefan
Relais-Karte.tar.gz
Aktualisierte Version
(192.86 KiB) 448-mal heruntergeladen
jerry42
Beiträge: 126
Registriert: 9. Oktober 2008 10:48

Re: Extern auf GUI-Elemente zugreifen

Beitrag von jerry42 »

Ich fand Signals&Slots im Vergleich zu Callback-Lösungen von anderen Bibliotheken/Frameworks immer sehr angenehm. Wenn du es einmal verstanden hast, ist es sehr einfach.

Ok, also wie ich sehe, hast Du jetzt Deinen Slot "boardConnect(QString....)" erstellt. Genau so hatte ich es gedacht.
Das eigene Signal war in dem Fall aber dafür gedacht, Deinen Slot auszulösen, und nicht innerhalb des Slots zu liegen. (Prinzipiell kannst du natürlich Signals in Slots auslösen, aber hier war es anders gedacht)

Ich dachte an folgendes:
connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(OnConnectTriggered()));
connect(this, SIGNAL(Connecting(QString,...)), mySteuerung, SLOT(Connect(QString,...)));

und in OnConnectTriggered würde so was ähnliches passieren wie:
emit Connecting(ui->port->currentText(),...);
Und damit würdest du dann in mySteuerung landen, mit all den Dingen, die du brauchst zum Verbinden.

Das eigene Signal wäre hier aber auch nicht unbedingt nötig, denn du hast ja dein Objekt von mySteuerung zur Verfügung:
steuerungWidget->Connect(ui->port->currentText(),...);

Ich hoffe, das war halbwegs verständlich. :)

Gruß
jerry42
GGStefan
Beiträge: 22
Registriert: 31. August 2012 23:59
Wohnort: Brandenburg (LDS)

Re: Extern auf GUI-Elemente zugreifen

Beitrag von GGStefan »

Hallo Jerry42,

wirklich vielen Dank für Deine Geduld und deine ausführlichen Antworten. :D

Es scheint so als würde ich wohl noch eine ganze weile benötigen bis es Verstanden habe. :?:

Beidem was ich bisher so machte fand ich das Callback doch irgendwie etwas einfacher, allerdings habe ich bisher auch noch nicht wirklich etwas größeres programmiert.

QT habe ich jetzt gewählt da es mir Optisch sehr gefällt und der QT-Creator einen sehr guten Eindruck macht. Außerdem wollte ich etwas nehmen das auch Plattform unabhängig ist. Da ich Privat fast ausschließlich nur noch Linux (Ubuntu) verwende und beruflich dann Windows verwenden muss.

Ich muss gestehen das ich deine letzte Nachricht zwar versucht habe umzusetzen jedoch nicht wirklich verstanden habe. Um das ganze besser zu verstehen habe ich mir ein Diagramm für die Signal- Slot-Verbindungen erstellt, liegt mit im Anhang.

Es drängen sich mir jetzt zwei Fragen auf: :?:

1. wofür benötige ich den jetzt noch den Slot „boardconnect“, soweit ich es überblicken kann habe ich Ihn mit keinem Signal verbunden.
2. Die Fehlermeldung die ich jetzt erhalte nachdem ich die Änderungen durchgeführt habe.
Fehler: expected primary-expression before „ , “ token
Warum er jetzt mySteuerung nicht akzeptiert.

Auch muss ich zugeben das ich mir die Idee mit meiner Relaiskarte doch etwas leichter vorgestellt habe als es jetzt dann doch ist. Ich werde wohl darüber nachdenken müssen mir erst etwas leichteres zu suchen, um daran dann zu lernen. Es ist halt nicht leicht etwas zu finden, da die meisten Tutorials oder auch Bücher immer mit Konsolen Anwendungen beginnen, und es im Bezug auf eine GUI-Bibliothek doch recht unpassend finde.

Gruss GGStefan
Dateianhänge
Relais-Karte.tar.gz
mit Diagramm
(130.34 KiB) 415-mal heruntergeladen
jerry42
Beiträge: 126
Registriert: 9. Oktober 2008 10:48

Re: Extern auf GUI-Elemente zugreifen

Beitrag von jerry42 »

Hi,

ja, da hab ich deinen Klassennamen und Variablennamen verwechselt.
Er erwartet die Instanz einer Klasse beim connect. Also in Deinem Fall steuerungWidget, und nicht mySteuerung.

Ja du hast recht das „boardconnect“ brauchst du dann eigentlich nicht mehr.
Und die Signale der einzelnen UI-Elemente musst du auch nicht verbinden, außer du willst auf Änderung direkt darauf reagieren.
Aber mir scheint so als willst du das ganze erst auswerten, wenn man explizit auf verbinden klickt.

Ich denke auch, dass Du vielleicht ein paar einfachere Beispiele vorschieben solltest. :)

Gruß
jerry42
GGStefan
Beiträge: 22
Registriert: 31. August 2012 23:59
Wohnort: Brandenburg (LDS)

Re: Extern auf GUI-Elemente zugreifen

Beitrag von GGStefan »

Hallo Jerry42,

das mit steuerungWidget hatte ich mir schon fast gedacht, nur in meinen ganzen Änderungen irgendwie nicht berücksichtigt. Jedenfalls funktioniert der Teil jetzt Super! :D

Aber ich denke auch das ich vorher noch etwas einfacheres probieren sollte, nur stellt sich mir die Frage was? Das mit der Relaiskarte wollte ich als Einstieg nehmen um später meine Mikrocontroller (Arduino) und Roboter (Asuro) über die Serielle Schnittstelle zu Steuern bzw. Daten von diesen zu empfangen. Daher dachte ich das mit der Relaiskarte wäre ein guter Einstieg.

Hast Du eventuell etwas was ich zum Anfang nehmen könnte was in diese Richtung geht? :?:

Gruß Stefan
jerry42
Beiträge: 126
Registriert: 9. Oktober 2008 10:48

Re: Extern auf GUI-Elemente zugreifen

Beitrag von jerry42 »

das ist natürlich schwer.
Im Prinzip ist ist die GUI von Relais-Einstellungen ja schon geeignet. Wobei serielle Verbindungen nicht ganz so einfach sind, aber vielleicht hast du ja schon deutlich mehr Erfahrung?!

Um einfach in die Signal&Slot Sache reinzukommen, reicht es vielleicht auch mal die Beispiele von Qt anzuschauen, und vielleicht das eine oder andere etwas anzupassen.
Oder du fängst mit nem Taschenrechner oder so an. Sorry was besseres fällt mir grad nicht ein :)

Gruß
jerry42
GGStefan
Beiträge: 22
Registriert: 31. August 2012 23:59
Wohnort: Brandenburg (LDS)

Re: Extern auf GUI-Elemente zugreifen

Beitrag von GGStefan »

Hallo Jerry42,

danke für deine Antwort. Habe mir die Examples von QT-Creator angesehen, muss allerdings sagen das ich diese gerade für Anfänger recht heftig finde. :!: :?:
Mein GUI mag ja gelungen sein :lol: nur hat es halt keine Funktionalität, was das steuern der Relais anbelangt. Vielleicht sollte ich erst einmal auf die Trennung von GUI und Funktion verzichten und versuchen alles in der Klasse Relaiskarte8 zu bewerkstelligen, oder ist dieser Ansatz nicht zu empfehlen? :?:
Werde mit in den nächsten Tagen mal Gedanken machen. :idea:

Vielleicht hast Du ja noch eine Idee für ein Übungs-Projekt für mich.

Gruß GGStefan
jerry42
Beiträge: 126
Registriert: 9. Oktober 2008 10:48

Re: Extern auf GUI-Elemente zugreifen

Beitrag von jerry42 »

wieviel Erfahrung hast Du denn mit C++ an sich?
Ja, vielleicht erstmal ohne GUI versuchen

Gruß
Antworten