Nicht-modaler Dialog reagiert nicht wenn Aufrufer beschäftigt ist



  • Hallo zusammen,

    ich habe eine (historisch gewachsene) Situation wie folgt:

    - ein "dummer" Dialog, nur mit Progress-Bar und Cancel-Button
    - ein Algorithmus, der über längere Zeit läuft und seinen prozentualen Fortschritt nach außen geben kann
    - ein Aufrufer, der diesen Dialog mit Create() erzeugt; per Signal/Slot (Callback) wird vom Algorithmus dessen Fortschritt mit dem Progress-Bar des Dialogs verknüpft

    Pseudo Code:

    ProgressDlg dlg;
    dlg.Create();
    
    Algorithm alg;
    alg.ProgressSignal.Connect( dlg.ProgressSlot );
    alg.Execute();
    

    Jetzt ist es so, dass der Cancel-Button des nicht-modalen Dialogs nicht klickbar ist, solange der Algorithmus Rechenzeit braucht (bzw. der ganze Dialog reagiert auf nichts).

    Ein erster "Hack" war, in der Dlg-Funktion die den Progressbar aktualisiert, per while-Schleife (mit PeekMessage+DispatchMessage) die Nachrichten abzuarbeiten. Dadurch kann, wenn diese Methode aufgerufen wird, desöfteren der Cancel-Button gedrückt werden. Dies kann aber dauern - und selbst dann klappt es nicht immer.

    Das ist also Mist.
    Zweiter Ansatz war, per SetTimer die Queue zu prozessieren. Wenn man keine Callback-Funktion angibt, wird eine Message gepostet - das klappt sowieso nicht, da ja keine Nachrichten abgearbeitet werden. Aber selbst wenn man eine Callback-Funktion in SetTimer angibt, wird diese nicht aufgerufen. Vermutlich arbeitet die intern auch irgendwie mit Messages.

    Nun die spannende Frage:
    gibt es eine einfache (nicht unbedingt schöne) Lösung für das Problem?

    Hintergrund dieses "Designs" (nennen wir es mal so) war wohl, dass man einen allgemein gültigen, wiederverwendbaren Dialog hat und damit den Fortschritt eines jeden Vorgangs anzeigen lassen kann (der seinen Fortschritt auch propagiert).
    Das heißt in meinem Fall leider auch, das relativ viele Algorithmen diese Methodik benutzen und daher eine grundlegende Änderung sehr viel Zeit beanspruchen würde (dass das die sauberste Lösung und langfristig auch die kostengünstigere wäre, ist schon klar, aber ihr wisst ja wie's läuft :D)

    Grüße Flo



  • Ich gehe mal davon aus, dass dlg und alg im gleichen Thread laufen...??
    Da ist das Verhalten vorherzusehen. Abhilfe: du lagerst alg in einen Workerthread aus (die ist allerdings keine (Zitat) "... einfache (nicht unbedingt schöne) Lösung für das Problem...)


  • Mod

    Hier wird gezeigt wie man einen Progress-Dialog auch ohne Workerthread bauen kann:
    http://www.microsoft.com/msj/0798/c0798.aspx



  • Martin Richter schrieb:

    Hier wird gezeigt wie man einen Progress-Dialog auch ohne Workerthread bauen kann:
    http://www.microsoft.com/msj/0798/c0798.aspx

    Danke Martin, der Artikel beschreibt jedoch exakt das "Design-Pattern" wie ich/wir es schon benutzen (und ich versucht habe oben zu beschreiben).

    Das Problem ist, dass die Abarbeitung der Messages nur in der Funktion des nicht-modalen Dialogs stattfindet, die von außerhalb aufgerufen wird (in meinem Beispiel die Übermittlung eines neuen Fortschritts, im Beispiel vom Paul DiLascia der Aufruf von Abort() in der for-Schleife).
    Wird diese Funktion "zu selten" aufgerufen (weil es von 0% zu 1% halt einfach 60s dauert), dann sieht es für den Benutzer aus, als ob es hängt, denn der Dialog reagiert erst dann wieder, wenn die Message-Queue abgearbeitet wird.

    Daher der Versuch mit dem Timer, die Queue auch zwischendurch mal zu prozessieren; das funktioniert aber ebenfalls nicht, da der Timer auch mit Messages arbeitet...

    @AndyDD: ja, dlg und alg laufen im gleichen Thread; das Auslagern wäre zwar die saubere Lösung, aber auf Grund des Umfangs der nötigen Umbauarbeiten an sehr vielen Stellen auch die aufwändigste...

    Gruß Flo


  • Mod

    Dann bleibt Dir nur ein Workerthread!


Anmelden zum Antworten