Problem: Quelltext kurz warten lassen, dabei aber Timer weiter ausführen
-
Hallo Leute,
ich habe folgendes Problem wie auch schon in der Überschrift beschrieben: Ich habe einen Timer gestartet, der das ganze Programm über die aktuelle Zeit abfragt und anzeigt.
Nun möchte ich einen Sound abspielen und will das Programm warten lassen, bis der Sound vorbei ist. Im Internet habe ich ->PlaySync() gefunden, aber wenn ich das mache, wird der Timer auch nicht weiter ausgeführt und die Uhrzeit somit nicht aktualisiert. Wie kann ich es schaffen, den Quelltext zwar anzuhalten, aber trotzdem den Timer weiterlaufen zu lassen?private: void Form1_Load() { ... clock = gcnew System::Windows::Forms::Timer(); clock->Tick += gcnew EventHandler(this, &Form1::CountTime); clock->Interval = 100; ... clock->Start(); watch = Stopwatch::StartNew; ... } private: void CountTime(Object ^sender, EventArgs ^e) { int milliseconds, seconds, minutes, hours, remaining; milliseconds = Convert::ToInt32(watch->ElapsedMilliseconds); hours = milliseconds / (60*60*1000) + savedhours; remaining = milliseconds % (60*60*1000); minutes = remaining / (60*1000) + savedminutes; remaining = remaining % (60*1000); seconds = remaining / 1000 + savedseconds; stoptime->Text = hours.ToString("00") + ":" + minutes.ToString("00") + ":" + seconds.ToString("00"); } private: void playsound() { sound->PlaySync() }
Mit vielen Grüßen und in der Hoffnung auf Hilfe
Ialokim
-
Etwas wenig Code, wäre interessant wo "playsound" aufgerufen wird. Und ich gehe einfach mal davon aus dass "stoptime" ein Label ist.
Das Problem ist leicht widersprüchlich. Wenn du "PlaySync" verwendest frierst du ja solange dein Programm ein. D.h. selbst wenn du es schaffen würdest den Timer weiterlaufen zu lassen (z.B. indem du den Timer aus System::Timers statt den aus System::Windows::Forms nimmst) könntest du das Label mit "stoptime->Text " nicht updaten - da ja der gesamte Mainthread von "PlaySync" blockiert ist..
-
Ich würde mal sagen, es ist komplett egal, wo genau playsound aufgerufen wird, oder? Es kommt nur darauf an, dass der Aufruf an einer Stelle im Quelltext steht, wo es hinterher noch weitergeht, d.h. nachdem der Sound abgespielt wurde, soll noch eine weitere Sache passieren, aber eben erst danach.
Also ist meine Frage weiterhin: Wie kann ich das Programm dazu bringen, beim weiteren Ausführen des Quelltextes bis zum Ende des Sounds zu warten, aber gleichzeitig die Uhr weiter zu aktualisieren? Wahrscheinlich ist dafür PlaySync() nicht die richtige Methode, aber ich habe sonst nichts anderes gefunden...
Ich kann mir eigentlich fast nicht vorstellen, dass das nicht irgendwie funktioniert...LG,
IalokimP.S. ja, "stoptime" ist ein Label!
EDIT: Hier noch ein bisschen Code:
Random ^zufall = gcnew Random(); wurf = zufall->Next(1, 7); würfel->Visible = false; würfel->Load("Bilder\\Hilfe\\spielwürfel_" + wurf + ".bmp"); playsound(); würfel->Visible = true;
-
Also wenn du nicht das ganze Programm einfrieren willst solange der Sound spielt sondern einfach etwas machen willst wenn der Sound zu Ende ist ginge das so:
void playsound() { backgroundWorker1->RunWorkerAsync(); } void backgroundWorker1_DoWork(Object^ sender, DoWorkEventArgs^ e) { sound->PlaySync(); } void backgroundWorker1_RunWorkerCompleted(Object^ sender, RunWorkerCompletedEventArgs^ e) { //erst aufgerufen wenn Sound zu Ende }
wobei backgroundWorker1 ein Backgorundworker der Form ist und die zwei Methoden im Designer bei dessen Events angegeben sind.
Sollte doch eigentlich passen oder ?
-
Das mit BackgroundWorker ist eine hervorragende Idee! ich habe mir jetzt überlegt, dass es doch eigentlich schlau wäre, für den sound doch PlaySync() zu verwenden und nur die Zeitanzeige im BackgroundWorker zu bearbeiten. Leider klappt das nicht wie gewünscht: Anscheinend wird CountTime durch den Timer im BackgroundWorker gar nicht aufgerufen...
Form1_Load { ... timecountworker->RunWorkerAsync(); ... } private: System::Void timecountworker_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) { clock = gcnew System::Windows::Forms::Timer(); clock->Tick += gcnew EventHandler(this, &Form1::CountTime); clock->Interval = 100; clock->Start(); watch = Stopwatch::StartNew(); }
Kann man durch einen Backgroundworker etwa keine Funktionen aufrufen, die anderswo im Quellcode zu finden sind (in diesem Fall CountTime)??
LG, Ialokim
-
Doch kannst du. Allerdings scheint der Timer nur zu gehen wenn er im Mainthread erstellt wird (Wie gesagt es ist der Timer aus System::Windows::Forms). Das ganze ließe sich z.B. über einen Invoke Aufruf lösen, ist aber hier eigentlich nebensächlich.
Wie gesagt, dein Timer updatet ja deine Form - und wenn du mit "PlaySnyc" den Mainthread komplett blockierst würden dir die Veränderung eh nicht angezeigt bis der Sound zu Ende ist insofern kann der Timer solang auch stehenbleiben.Was ist denn an meiner Lösung unpassend ? Der Timer würde weiterlaufen und nach dem Beenden des Sounds der Würfel sichtbar gemacht werden. Oder willst du was anderes ?
-
Nun ja, ich denke, es wäre eleganter, wenn das Programm an sich die ganze Zeit im Hauptthread ausgeführt wird und nur die Zeitzählung in einem Extra-Thread wäre...
Würde es denn gehen, das Label irgendwie in dem Extra-Thread zu definieren, sodass es nicht einfrieren kann, aber dass es trotzdem im Hauptbildschirm angezeigt werden kann?Vielleicht bin ich jetzt ein bisschen kleinlich, aber ein Code, bei dem durch einen Klick erstmal eine Funktion x aufgerufen wird, die wiederum einen Thread y erstelllt, in dem dann ein Sound abgespielt wird und der Rest vom Code, der eigentlich ja noch zu der Funktion x gehört, steht dann irgendwo bei backgroundWorker_DoWorkCompleted... naja, das kommt mir schon ganz schön gewurschtelt vor.
Möglicherweise sehe ich das zu eng, aber wenn ich es doch irgendwie anders machen kann, wäre mir das lieber...LG, Ialokim
-
Würde es denn gehen, das Label irgendwie in dem Extra-Thread zu definieren, sodass es nicht einfrieren kann, aber dass es trotzdem im Hauptbildschirm angezeigt werden kann?
Nein, die Steuerelemente sind im Mainthread.
Ganz so kompliziert wie das klingt ist es ja nicht
Einfach statt den Sound abzuspielen einen Backgroundworker erstellen der den Sound abspielt und wenn der Sound fertig ist noch den restlichen Code ausführt
-
Hmm... schade! Naja, dann mach ichs eben doch so wie von dir oben erklärt...
Trotzdem vielen Dank für die Hilfe!LG, Ialokim