Grafikausgabe verursacht "keine Rückmeldung" in der Title-Bar der Anwendung



  • Hallo zusammen,
    folgendes Problem:

    Aus einer Messwertetabelle zeichne ich in einem Fenster den Messwert-Graphen.
    Das dauert sehr lange.
    Leider so lange, dass Windows glaubt, die Anwendung würde nicht mehr reagieren.
    Es kommt daher "keine Rückmeldung" in der Titlebar.
    Das viel Schlimmere daran ist allerdings, dass ab da die Anwendung mit der Ausgabe von vorne beginnt.
    sie befindet sich damit in einer Endlosschleife.

    Ich habe versucht, das über ein "PeekMessage(..)" zu lösen, was teilweise auch funktioniert aber Nebeneffekte hat.
    Verschiedene Varianten habe ich ausprobiert.
    Entweder wird der Graph abgebrochen oder die Anwendung ist über TeamViewer nicht mehr zu bedienen.

    Wenn ich die Messages filtere, verliert diese Methode ihre Wirkung.

    Welche Möglichkeiten gibt es denn noch?
    Kann bitte jemand helfen?

    Grüsse
    Helmut
    Welch



  • Die Funktionalität wirst du dann z.B. in einen eigenen Thread auslagern müssen, s.a. Preventing Hangs in Windows Applications.

    Hast du während der Grafikausgabe noch komplexe Berechnungen oder zeichnest du Millionen von Punkten (oder Linien etc.)? Oder bedeutet "Messwertetabelle" wirklich, daß du Datenbank-Zugriffe hast?
    Wenn die Daten fix sind (bzw. keine Echtzeitdaten sind), dann könntest du auch im Hintergrund die Daten in ein Image zeichnen und danach einfach blitten.


  • Mod

    Erzeuge eine interne Bitmap in einem anderen Thread. Die aktualisierst Du immer.

    Im WM_PAINT gibst Du dann die Bitmap auf.
    Kannst Du auch mit einer Windows Meta Datei machen...



  • @Th69
    Hi Th69, hi Martin,

    vielen Dank schonmal.

    Ich weiss, dass Auslagern das Beste ist. Das wird aber kompliziert!
    Und wie immer sind wir bei Messungen, die ab sofort angesehen werden müssen!

    Die Daten kommen aus einer Datei.
    Die Berechnungen sind nicht so komplex.
    Aber es werden die einzelnen Messpunkte durch eine Linie verbunden.
    Und es sind inzwischen schon über 300000. Das kostet nunmal die Zeit.

    Inzwischen bin ich zu "SendMessage(hwnd, SB_SIMPLE,..)" übergegangen.
    Das scheint besser zu gehen (weniger Dreckeffekte).

    Vor allem mit TeamViewer oder vnc gibts Dreckeffekte, wie Sanduhr über Buttons
    oder plötzlich keine Maus mehr.
    Irgendwie reagiert es auf jedem System anders.

    Gibts da nicht noch was in der Richtung mit SendMessage oder PostMessage?



  • warum meinst du, dass das kompliziert wird? sobald du im thread irgendwas fertig berechnet hast, rufst du InvalidateRect auf und es wird sofort neu gezeichnet.

    ansonsten kannst du vom thread aus ja auch direkt die entsprechende zeichenfunktion aufrufen.



  • @Wade1234
    Letzteres kommt mir noch am angenehmsten vor.
    Aber ich muss trotzdem viel testen, und es ist leider nicht mit einem halben Tag getan.

    Wenn ich die Berechnung einen Thread machen lasse, dann würde ja dieser 300000 aufgerufen werden.
    Das wäre ein riesen Overhead.

    Aber wäre dann die Thread-Kommunikation ausreichend, um dem Windows Aktivität zu melden?

    Die Sache ist eh schon sehr langsam. Und ich habe noch andere Funktione wie Fadenkreuz u. Zoom drin.



  • @elmut19

    du könntest den thread ja auch durchgehend laufen lassen, anstatt für jede einzelne berechnung einen thread zu erstellen.



  • @Wade1234
    ... und ihm dann nur neue Daten übergeben, auf die er dann reagiert.
    Dann muss ich die Rückgabe der Daten synchronisieren...



  • @elmut19

    naja du könntest z.b. eine datenstruktur anlegen, in der die zu zeichnenden daten, pixelkoordinaten, oder was auch immer, abgelegt sind, und diese vom thread aus nach der berechnung beschreiben und dann InvalidateRect aufrufen, was dann ja ein WM_PAINT auslöst, welches wiederum die daten aus der struktur ausliest und deine ergebnisse zeichnet.

    also ich musste im studium auch mal eine software programmieren, die ein diagramm mehr oder weniger in echtzeit zeichnet, und das war habe ich auch nicht einfach mal so gemacht. aber ohne threads und zig zustandsvariablen ging das nicht.



  • @elmut19

    ... Synchronisieren muss ich ja eh.
    Also auch wieder Wartezeit.
    Dann den Thread in den View zeichnen lassen.
    Da brauch ich ein paar Tage, bis das läuft.

    Ich hatte mir was Einfacheres erhofft.

    Mein Vorgänger hatte sich die Variante mit dem "PeekMessage" ersonnen.
    Das ist an sehr wenigen Stellen noch drin. Für meinen Fall hat es diese groben Dreckeffekte, die bisher nicht auftraten.

    Das mit dem extra Thread werde ich mir auf jeden Fall und auf irgendeine Art antuen müssen.
    Aber kurzfristig ist das SendMessage noch am Brauchbarsten, Wenn nicht noch jemanden eine Methode ohne Nebeneffekte einfällt.



  • Es ist echt traurig, daß auf diese Art (professionelle) Software entwickelt wird...

    Dann scheint auch eure gesamte Anwendungsarchitektur nicht zu stimmen (wenn ihr mit solchen Hacks arbeitet - darum verstehe ich auch nicht den Aufruf von SB_SIMPLE ?!).



  • wieso wie macht man das denn sonst?



  • @Th69
    Es gibt Verbesserungspotential!

    Wegen SB_SIMPLE ...
    Ich habe einfach nach etwas gesucht, das den geringsten Einfluss hat.

    Dass ich bald was Besseres brauch, weiss ich auch.
    Nur im Moment arbeiten wir an einer Testanlage und der entsprechende Prozess läuft gerade.

    Bisher war die Ausgabe auch ok, da die Datenmenge meist nur ein paar hundert Daten enthält.
    Nur plötzlich die Zwickmühle...



  • Der einfachste Weg ist die Synchronisierung per SendMessage

    Nebenläufiger Thread:

    • erhält das Fensterhandle des Fensters, in dem das Diagramm angezeigt wird.
    • liest die Daten ein und bereitet sie auf.
    • meldet dem Zielfenster per SendMessage, dass die Daten zur Anzeige bereit sind. In welcher Form auch immer, ob das jetzt schon eine fertige Bitmap ist oder sonstwas. Hier bietet sich eine Kapselung der Daten in einem unique_ptr an.
    • zurück zur Datenaufbereitung

    Hauptfenster:

    • startet den nebenläufigen Thread zur Datenaufbereitung
    • stellt eine Behandlungsfunktion für benutzerdefinierte Fensternachrichten zur Verfügung
    • in dieser Behandlungsfunktion übernimmt es die Daten des nebenläufigen Threads und kümmert sich um die Anzeige. Dazu kann es notwendig sein, dass die Daten zwischengespeichert werden müssen, weil sie erst während der Behandlung einer WM_PAINT Fensternachricht benötigt werden. Da sollte man sich überlegen, ob die Daten per unique_ptr gekapselt werden können und das Hauptfenster sie dem Thread einfach wegnimmt, indem der unique_ptr den Besitz über die Daten übernimmt.

    Der Vorteil bei SendMessage ist, dass der Aufruf erst zurückkehrt, wenn die Fensternachricht im Erstellerthread des Fensters behandelt wurde. Das heisst, dass der Thread so lange wartet, bis die Nachricht im Hauptfenster der Anwendung behandelt wurde und macht dann erst weiter. Die Synchronisierung wird einem also vom Betriebssystem geschenkt, da muss man sich um nichts mehr selber kümmern.



  • @DocShoe
    Vielen Dank DocShoe.
    Das werde ich auch in die Änderungen einfliessen lassen.



  • Nochmal zur Schnelllösung:

    Das mit dem "SendMessage(..)" hatte leider nur scheinbar ausgereicht.
    Das mit dem "PeekMessage(..)" + REMOVE + Translate..() + Dispatch.. ginge zwar, macht aber TeamViewer Sitzung unbrauchbar.

    Eine "ordentliche" Lösung ist in der Kürze nicht machbar!!!

    Was gäbe es noch, um dem Windows eine Rückmeldung zu geben,
    damit die Meldung: "keine Rückmeldung" nicht kommt?

    Denn durch diese Meldung komme ich in eine Endlosschleife!

    Gäbe es eine bestimmte Message von Windows, auf die ich mit "PeekMessage(..)" reagieren könnte,
    die den Teamviewer, etc. nicht stört?

    Aber eine, die auch sicher öfter gesendet wird.



  • Also...
    Alle Windows Anwendungen mit Fenstern sind nachrichtengesteuert, d.h. iwo in deiner Anwendung muss es einen Funktionsblock geben, der Nachrichten aus der Nachrichtenqueue holt und verarbeitet. Normalerweise macht man das per GetMessage(), man kann sich aber auch was mit PeekMessage() und PM_REMOVE basteln. Die Benutzung der Funktionen erzeugt per se keine Endlosschleife bzw. Stillstand des Programms. Und dass die Benutzung von PeekMessage() den TeamViewer stört kann ich mir auch nicht vorstellen. Es sei denn, man baut in seiner Anwendung Mist.



  • also eigentlich gibt es in der winmain eine endlosschleife, die die ganzen nachrichten verarbeitet und die callbackfunktion aufruft. man kann das aber auch alles weglassen und ohne nachrichten arbeiten, wenn man das denn unbedingt will.

    ich weiß jetzt nicht, warum das so schwer ist, die berechnungen in einen thread auszulagern und von dort aus die entsprechenden nachrichten zum neuzeichnen auszulösen.



  • Das grundsätzliche Problem ist eben, dass du in den DC des Fensters zeichnest:

    case WM_PAINT:
      BeginPaint(...);
      Sleep(10000); // langer Zeichenvorgang
      EndPaint(...);
    

    Wenn dieser Zeichenvorgang abgeschlossen ist, kann es sein (bzw. ist es, nachdem Windows Inaktivität festgestellt hat, sehr wahrscheinlich), dass direkt die nächste Paint-Nachricht reinkommt und das Spiel beginnt von vorne.
    Darum kam eben der Vorschlag mit dem double-buffering. Nur, wenn es nötig ist, in eine Bitmap zeichnen und diese im Paint-Zweig blitten (und keinesfalls dabei neu hineinzeichnen).

    Das kann (und sollte eigentlich auch) natürlich auch noch beliebig erweitert werden: Ein eigenes Control für die Bitmap, das vom Scrollen (über Scrollbars und Mausziehen) bis Zoomen selbst alles übernehmen kann, einen anderen Thread fürs Zeichnen verwenden, für eine bessere Navigation den Zeichenvorgang aufteilen (bspw. erst das Koordinatensystem zeichnen und wenn das Navigieren abgeschlossen ist, die Messwerte einzeichnen), ...
    Am grundsätzlichen Problem ändert das allerdings nichts.



  • Das mit dem Teamviewer und "PeekMessage" berichtet mir mein Kollege,
    der die Testanlage betreut.
    Ich konnte es mir auch nicht vorstellen.
    Aber wahrscheinlich sendet der dauernd was und meine Anwendung nimmt diese Nachrichten weg.
    Auf meinem Entwicklungsrechner passiert nichts weiter, wenn ich das PeekMessage auf alle Handles und alle Messages anwende.
    Wenn ich allerdings den Filter auf WM_TIMER setze, wird die Toolbar nicht mehr refreshed.

    Seltsamerweise passieren die Effekte mit dem endlosen Neuzeichnen der Grafik nicht auf meinem Entwicklungsrechner

    In das Thema mit dem Thread muss ich mich für den speziellen Fall erst einarbeiten.
    Ihr habt zwar ein paar Einstiegsgedanken gegeben, aber probieren muss sich das halt.


Log in to reply