Einstellbarer QTimer für Befehlsverzögerung
-
In mainwindows.h fehlte unter private noch "QTimer t;", der Rest war drin. Ist jetzt aber eingefügt. Bekomme beim Kompilieren aber trotzdem noch folgende Fehlermeldung:
ok, wir haben dem Compiler gesagt, "Es gibt eine Klasse QTimer und ich will eine Instanz davon in MainWindow haben"
Und der Compiler sagt uns mit den Fehlermeldungen:
"Schön und gut, aber ich weiß nicht wie QTimer definiert ist"Das ist kein Problem, QTimer ist definiert und Teil des QtFrameworks, aber bisher noch nicht in unserem Projekt.
in MainWindow.h oben bei den includes im oberen Bereich musst du folgendes eintragen:
#include <QTimer>Das sagt dem Compiler, für mainwindow.h brauchst du QTimer, lade es bitte mit in die Datei beim kompilieren.
QTimer t;
t.setInterval(6000); // 6 SekundenQObject::connect(&t, &QTimer::timeout, this, &MainWindow::bandHopping);
t.start();Kannst du hier mehr vom tatsächlichen Constructor zeigen? weil so wie es aussieht besteht eine hohe Gefahr, dass du etwas gemacht hast, was man allgemein hin als
Variable Shadowing bezeichnet!Sorry, I am an absolute beginner with Qt...
Kein problem, wir haben alle irgendwo angefangen, ist aber gut zu wissen, damit man weiß wie weit man ausholen muss, wenn man was erklärt!
Ich würde, unabhängig von deinem jetzigen Projekt, empfehlen mal die Beispiele von Qt durch zu gehen, die sind genauso wie die offizielle Dokumentation ausgezeichnet und nahezu einmalig in Detail und Qualität, verglichen zu anderen Frameworks
https://doc.qt.io/qt-5/qtexamplesandtutorials.htmlQtCreator, der IDE von dem ich annehme, dass du ihn hier verwendest, kommt mit den Beispielen vorinstalliert. Brauchst nur den Beispiel/Examples Knopf zu drücken
-
Hi @J-Hilk, jetzt bin ich einen großen Schritt vorangekommen.
-
Die Kompilierungsfehler habe ich alle beseitigt.
-
Die Grundfunktionalität des Wechsels zum jeweils nächsten klappt jetzt, aber nur wenn ich sie manuell über MainWindow::bandHopping(); auslöse.
-
Denn leider "timed" der Timer einfach nicht. Ich habe ihn übrigens in qsyTimer umbenannt (der Name "t" führte zu Fehlern), aber er löst einfach den Befehl MainWindow::bandHopping() nicht aus.
Woran mag es liegen, dass der Timer nicht den Bandwechsel auslöst?
Hier mein aktueller Code:
void MainWindow::on_pbBandHopping_clicked (bool checked) { if (checked) { QTimer qsyTimer; qsyTimer.setInterval(6000); // 6 Sekunden QObject::connect(&qsyTimer, &QTimer::timeout, this, &MainWindow::bandHopping); qsyTimer.start(); MainWindow::bandHopping(); // manuelle Auslösung des bandHoppings, weil der Timer nicht funktioniert } } void MainWindow::bandHopping() { static int startIndex = 0; if(startIndex >= 19) { // hier fehlte eine geschweifte Klammer startIndex = 0; } // hier fehlte eine geschweifte Klammer int nextStartIndex = startIndex +1; switch (startIndex){ case 0: if (ui->cb2190m->isChecked ()) { setRig (136000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 1: if (ui->cb630m->isChecked ()) { setRig (472000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 2: if (ui->cb160m->isChecked ()) { setRig (1840000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 3: if (ui->cb80m->isChecked ()) { setRig (3573000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 4: if (ui->cb60m->isChecked ()) { setRig (5357000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 5: if (ui->cb40m->isChecked ()) { setRig (7074000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 6: if (ui->cb30m->isChecked ()) { setRig (10136000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 7: if (ui->cb20m->isChecked ()) { setRig (14074000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 8: if (ui->cb17m->isChecked ()) { setRig (18100000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 9: if (ui->cb15m->isChecked ()) { setRig (21074000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 10: if (ui->cb12m->isChecked ()) { setRig (24915000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 11: if (ui->cb10m->isChecked ()) { setRig (28074000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 12: if (ui->cb6m->isChecked ()) { setRig (50313000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 13: if (ui->cb4m->isChecked ()) { setRig (70154000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 14: if (ui->cb2m->isChecked ()) { setRig (144174000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 15: if (ui->cb70cm->isChecked ()) { setRig (432174000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 16: if (ui->cb40mFT4->isChecked ()) { setRig (7047500); on_actionFT4_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 17: if (ui->cb30mFT4->isChecked ()) { setRig (10140000); on_actionFT4_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 18: if (ui->cb20mFT4->isChecked ()) { setRig (14080000); on_actionFT4_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 19: if (ui->cb17mFT4->isChecked ()) { setRig (18104000); on_actionFT4_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } } }
-
-
Noch eine Ergänzung: Wenn ich einen anderen im Projekt schon vorhandenen Timer mit dem bandHopping verbinde, funktioniert es einwandfrei:
void MainWindow::on_pbBandHopping_clicked (bool checked) { if (checked) { connect (&minuteTimer, &QTimer::timeout, this, &MainWindow::bandHopping); } }
Kann ich als Workaround sogar einstweilen verwenden, denn so wechselt das Band immer exakt zur vollen Minute.
Aber: Warum klappt der eigene qsyTimer nicht?
-
@Urbi ok,
du hast gesagt dein QTimer qsyTimer; wäre in der .h Datei von mainwindow.
Ist das der Fall ? Dann haben wir hier in der Tat einen Fall von Variable Shadowing!Zudem kommt noch hinzu dass das hier alles
QTimer qsyTimer; qsyTimer.setInterval(6000); // 6 Sekunden QObject::connect(&qsyTimer, &QTimer::timeout, this, &MainWindow::bandHopping); qsyTimer.start();
Lokale variablen sind und direkt vernichtet werden sobald das Programm
}
erreicht.Also folgendes:
QTimer qsyTimer; nach mainwindow.hprivate: QTimer qsyTimer;
das hier: weg aus on:pBandHopping_clicked und in den constructor der MainWindow Klasse schieben
qsyTimer.setInterval(6000); // 6 Sekunden QObject::connect(&qsyTimer, &QTimer::timeout, this, &MainWindow::bandHopping);
Kannst du mit Begriff Constructor von MainWindow was anfangen?
Die Funktion müsse die Zeile ui->setup(this); enthalten.on_pbBandHopping_clicked
müsste nun so aussehenvoid MainWindow::on_pbBandHopping_clicked (bool checked) { if (checked) { qsyTimer.start(); } else { qsyTimer.stop(); } }
dann sollte es klappen!
-
Hi @J-Hilk, danke für die erneute Hilfestellung.
Ich habe festgestellt, dass ich mit dem vorhandenen minuteTimer eigentlich alles erreichen kann, was ich will. Der Nutzer kann dann zwar nicht mehr das Bandwechsel-Intervall verändern, dafür beginnt es aber jedes Mal exakt zur vollen Minute, was bezüglich der beabsichtigten Funktionalität einige Vorteile bietet. 1 Minute ist als Intervall noch ok, zudem vereinfacht sich dadurch meine Programmergänzung enorm. Ich habe die restlichen Programmierungen eben schon dieser Lösung angepasst und alles finalisiert. Das Band Hopping funktioniert ausgezeichnet! Also werde ich es einstweilen dabei belassen und diesen Fall als "solved" betrachten.
Ganz herzlichen Dank für deine Hilfe!
-
@Urbi ok alles klar !
trotzdem eine Sache noch:
void MainWindow::on_pbBandHopping_clicked (bool checked) { if (checked) { connect (&minuteTimer, &QTimer::timeout, this, &MainWindow::bandHopping); } }
das connect muss in den constructor, ansonsten has du folgende situation.
Beim erstmal pbBandHopping klicken wird wird bandHopping einmal ausgeführt, wenn der timeout passiert.
beim zweiten mal klicken wird bandHopping zweimal ausgeführt
beim 3ten mal klicken 3 mal, beim 4ten mal 4 mal und so weiterdas ist nen massiver bug
-
@J-Hilk
Dann sei bitte so nett und erkläre mir das mit dem Constructor nochmal etwas genauer. Der Begriff sagt mir offen gesagt momentan noch nicht viel. Wo finde ich den in mainwindow.cpp und wohin dort muss ich meinen connect Befehl verschieben? (Und wie binde ich dort das if ein, dass das nur bei eingeschaltetem pbBandHopping Button so sein soll?) -
Ich glaube, ich habe es selber schon gefunden. Habe
connect (&minuteTimer, &QTimer::timeout, this, &MainWindow::bandHopping);
nach vorne geschoben, dorthin, wo auch schon der andere connect für den minuteTimer war. Dann brauche ich die ganze Methode
void on_pbBandHopping_clicked (bool checked)
nicht mehr und habe die Abfrage nach dem angeklickten BandHopping Button in die bandHopping Methode übernommen.
void MainWindow::bandHopping() { if(ui->pbBandHopping->isChecked()) { static int startIndex = 0; int nextStartIndex = startIndex +1; switch (startIndex){ case 0: if (ui->cb2190m->isChecked ()) { setRig (136000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); ...
-
Hi @J-Hilk,
noch eine allerletzte Frage: Ich habe an meinem Code noch folgende Änderungen vorgenommen:-
Mit Hilfe der Methode MainWindow::bandHoppingTimer() verdoppele ich das Taktintervall von 1 auf 2 Minuten (aber unter Beibehaltung der Taktung zur vollen Minute aus dem minuteTimer), denn 2 Minuten sind optimal.
-
Bisher war es immer so, dasss es nach dem letzten Bandwechsel zweimal das Zeitintervall brauchte. Um das zu beheben habe ich unten in den letzten Case das jetzt so modifiziert, dass über den Befehl MainWindow::bandHoppingTimer(); nach dem letzten ausgewählten Band einfach die komplette Methode neu beginnt. Funktioniert bestens.
Meine Frage an dich: Ist das ok so oder erzeuge ich mit letzterem wieder irgendeinen ungewünschten Effekt?
void MainWindow::bandHoppingTimer() { if(ui->pbBandHopping->isChecked()) { static int startIndex = 0; int nextStartIndex = startIndex +1; switch (startIndex){ case 0: startIndex = nextStartIndex; // band hopping every other minute return; case 1: MainWindow::bandHopping(); startIndex = 0; return; } } } void MainWindow::bandHopping() { if(ui->pbBandHopping->isChecked()) { static int startIndex = 0; int nextStartIndex = startIndex +1; switch (startIndex){ case 0: if (ui->cb2190m->isChecked ()) { setRig (136000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 1: if (ui->cb630m->isChecked ()) { setRig (472000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 2: if (ui->cb160m->isChecked ()) { setRig (1840000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 3: if (ui->cb80m->isChecked ()) { setRig (3573000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 4: if (ui->cb60m->isChecked ()) { setRig (5357000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 5: if (ui->cb40m->isChecked ()) { setRig (7074000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 6: if (ui->cb30m->isChecked ()) { setRig (10136000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 7: if (ui->cb20m->isChecked ()) { setRig (14074000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 8: if (ui->cb17m->isChecked ()) { setRig (18100000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 9: if (ui->cb15m->isChecked ()) { setRig (21074000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 10: if (ui->cb12m->isChecked ()) { setRig (24915000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 11: if (ui->cb10m->isChecked ()) { setRig (28074000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 12: if (ui->cb6m->isChecked ()) { setRig (50313000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 13: if (ui->cb4m->isChecked ()) { setRig (70154000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 14: if (ui->cb2m->isChecked ()) { setRig (144174000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 15: if (ui->cb70cm->isChecked ()) { setRig (432174000); on_actionFT8_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 16: if (ui->cb40mFT4->isChecked ()) { setRig (7047500); on_actionFT4_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 17: if (ui->cb30mFT4->isChecked ()) { setRig (10140000); on_actionFT4_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 18: if (ui->cb20mFT4->isChecked ()) { setRig (14080000); on_actionFT4_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 19: if (ui->cb17mFT4->isChecked ()) { setRig (18104000); on_actionFT4_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 20: if (ui->cb6mMSK->isChecked ()) { setRig (50280000); on_actionMSK144_triggered(); startIndex = nextStartIndex; return; } else { nextStartIndex++; } Q_FALLTHROUGH(); case 21: if (ui->cb2mMSK->isChecked ()) { setRig (144360000); on_actionMSK144_triggered(); startIndex = 0; MainWindow::bandHoppingTimer(); return; } else { startIndex = 0; MainWindow::bandHoppingTimer(); } } } }
-
-
Hi @Urbi
Zu der der Zusätzlichen Funktion habe ich nichts einzuwenden, sieht alles normal aus!
Eine Sache bei der
bandHopping
es sollte eigentlich nicht nötig sein, dass du beim letzen case die Funktion nochmal aufrufen musst.Was mir aufgefallen ist, wo setzt du denn
startIndex
wieder auf 0 zurück?ich hätte sowas erwartet:
if(ui->pbBandHopping->isChecked()) { static int startIndex = 0; if(startIndex > 21) startIndex = 0; int nextStartIndex = startIndex +1; switch (startIndex){ .... }
-
@J-Hilk, das hatte ich zuerst, hatte aber den gleichen Effekt (dass es am Ende zweimal das Zeitintervall brauchte. Deswegen hatte ich das zuletzt einfach so gemacht, dass ich im letzten Case startIndex = 0; setze. (Hatte aber am genannten Problem auch nichts verändert). Aber mit der jetzigen Lösung klappt es ja so wie es soll.
Nochmals ganz herzlichen Dank für deine Unterstützung!