[c++] Vermeiden Sie das Label "(Nicht reagieren)" in Windows, während Sie viele Daten in einem Stück verarbeiten



3 Answers

Ok, zuerst habe ich Fredericks Post hochgestuft, weil es so oder so, der zweite Thread ist wahrscheinlich der beste Weg zu gehen.

Wenn Sie jedoch nicht diesen Weg gehen möchten, können Sie die Nachrichtenwarteschlange manuell in die innere Schleife Ihrer Apps pumpen. Etwas wie das;

int Refresh()
{
    MSG       msg;
    if (PeekMessage (&msg, NULL, 0, 0,PM_NOREMOVE))
        if ((msg.message == WM_QUIT) 
          ||(msg.message == WM_CLOSE) 
          ||(msg.message == WM_DESTROY) 
          ||(msg.message == WM_NCDESTROY)
          ||(msg.message == WM_HSCROLL)
          ||(msg.message == WM_VSCROLL)
          ) 
          return(1); 
    if (PeekMessage (&msg, NULL, 0, 0,PM_REMOVE))
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
    return(0);
}

Dies ist tatsächlich ein Stück Code, den ich vor dem Umschreiben von etwas Ähnlichem als einen separaten Thread verwendet habe. Im Grunde schaue ich mir die Warteschlange an, filtere unerwünschte Nachrichten und poste den Rest. Es funktioniert in gewissem Umfang, verursacht aber gelegentlich gelegentliche unangenehme Nebenwirkungen, daher die Neufassung.

Question

Ich muss gelegentlich eine große Menge von Daten aus einem Paket aus dem Netzwerk verarbeiten, was ausreichend lange dauert, wenn der Benutzer versucht, mit dem Anwendungsfenster zu interagieren, indem er dem Fenstertitel die Zeichenfolge "(Nicht reagieren)" hinzufügt. Ich bin mir bewusst, dass dies daran liegt, dass die Verarbeitung innerhalb eines Anrufs ausgeführt wird, um eine Nachricht zu verarbeiten (etwas im Stapel nach oben) und daher die Nachrichtenpumpe blockiert. Mir ist auch bewusst, dass der beste Weg, dies zu bewerkstelligen, darin besteht, die Daten asynchron in einem separaten Thread zu verarbeiten, so dass die Pumpe weiterlaufen kann. Dies ist jedoch eine GROSSE Desktop-Anwendung, die von oben bis unten mit einem einzigen Gewinde versehen ist und diese Verarbeitung sicher abschließt ist in unserem Zeitrahmen nicht machbar.

Also in diesem Sinne, gibt es zufällig eine Möglichkeit, dass ich zumindest den "nicht reagierenden" Moniker vermeiden kann (was für die meisten Nutzer wie "abgestürzt" heißt), indem ich sage, dass meine Anwendung gerade beschäftigt ist, bevor ich anfange Arbeit? Ich glaube, da ist etwas in dieser Richtung, wenn man auf eine Anfrage zum Schließen reagiert, man kann Fenster immer wieder nach mehr Zeit fragen, um zu vermeiden, dass man nicht "rechtzeitig schließt".

Ich sollte hinzufügen, dass dies eine C ++ - MFC-Anwendung ist.




Angenommen, dass die Verarbeitung der Daten die ganze Zeit und nicht das Empfangen dauert (und Sie ernsthaft einen Thread vermeiden wollen - was IMOHO in Ordnung ist) der Daten, die Sie könnten:

  1. Erstellen Sie in der Funktion, mit der Sie gerade die Nachricht bearbeiten, einen modalen Dialog, der eine Nachricht "Bitte warten" anzeigt (oder versteckt, klein, was auch immer ...). Kopieren Sie (oder senden Sie einen Zeiger usw.) die Daten, die Sie verarbeiten, an eine Mitgliedsvariable dieses Dialogs.
  2. Geben Sie im modalen Dialog eine benutzerdefinierte Nachricht an Sie selbst ein, um die Daten zu verarbeiten.
  3. Behandeln Sie im Nachrichtenhandler des Dialogs eine "Einheit" der Arbeit. Verfolgen Sie, was die nächste "Einheit" der Arbeit ist. Senden Sie dieselbe Nachricht erneut.
  4. Wiederholen Sie diese Post-Nachricht "Schleife", bis Sie fertig sind. Schließen Sie Ihren Dialog.

Die Art des modalen Dialogs hält Ihre Anwendung "reaktionsfähig", mit minimalen Unterbrechungen oder Änderungen an der Funktionsweise der Anwendung. Reentrancy kann ein Problem mit modalen Schleifen sein, besonders wenn dies in einer WM_PAINT-Nachricht enthalten ist. (irgendjemand behauptet jemals innerhalb des Malcodes? gute Zeiten, gute Zeiten ...)

Der Dialog könnte sogar einen Abbrechen-Button haben, wenn Sie möchten.




Win32 hat eine Methode dafür in user32.dll .

DisableProcessWindowGhosting()

Deaktiviert die Fenster-Ghosting-Funktion für den aufrufenden GUI-Prozess. Fenster-Ghosting ist eine Windows-Manager-Funktion, mit der der Benutzer das Hauptfenster einer Anwendung, die nicht reagiert, minimieren, verschieben oder schließen kann.

Zusätzlich zu dem oben dokumentierten Verhalten habe ich hier (in einer C # -Anwendung) auch verifiziert, dass dieser Win32-Aufruf auch verhindert, dass das Etikett " Not Responding" auf dem Fenster wie gewünscht angezeigt wird.

Ich fand dies über die C # Antwort auf ähnliche Frage hier: https://.com/a/15380821/29152 .




Wenn Sie einen Thread abzweigen, sind Sie wahrscheinlich besorgt über eine andere Benutzeraktion, die von dem Ergebnis der lang andauernden Operation abhängt (yeah, concurrency). Wenn Sie einen neuen Thread ausgliedern und einen Fortschrittsbalken erstellen, können Sie den Fokus auf den Fortschrittsbalken setzen, um zu verhindern, dass ein Benutzer mit dem Rest der Anwendung interagiert. Das sollte ausreichen, um einen wirklich einfachen zweiten Thread zu implementieren, ohne sich wirklich Sorgen um Nebenläufigkeit machen zu müssen, da Sie den Rest der App im Wesentlichen sperren, indem Sie die Benutzerinteraktion deaktivieren.




Related