Auf Tastendruck im Dialog reagieren wenn ein Thread läuft
-
In einer SDI-Anwendung rufe ich einen Dialog auf. In diesem Dialog wird ein Workerthread gestartet, der Berechnungen solange ausführt, bis gewisse Endergebnisse einen Abbruch signalisieren oder bis der Benutzer durch drücken einer Taste (hier Escape) den Abbruch erzwingt. Ich habe allerdings das Problem, dass der Tastendruck nicht erkannt wird. Ich hab dazu folgendes implementiert:
BOOL CBerechnungDlg::PreTranslateMessage(MSG* pMsg) { // TODO: Fügen Sie hier Ihren spezialisierten Code ein, und/oder rufen Sie die Basisklasse auf. if (pMsg->message == WM_KEYDOWN) { if (pMsg->wParam == VK_ESCAPE) { if (m_bIsRunning) { m_bWantExit=true; KillThread(); AfxMessageBox(_T("Abbruch durch den Benutzer"), MB_OK | MB_ICONSTOP); return TRUE; } } } return CDialog::PreTranslateMessage(pMsg); }
Wenn der Thread nicht läuft, springt er auch da rein. Wenn er läuft dann nicht. Die OnBnClickedXXX, die den Thread startet, wird auch verlassen. Die Threadfunktion sie im groben wie folgt aus:
UINT CBerechnungDlg::Berechnung(LPVOID pParam) { //Zeiger auf das Dialogobjekt holen CBerechnungDlg* pDialog=(CBerechnungDlg*)pParam; while (true) { //Hier erfolgen Berechnungen Sleep(0); { if (pDialog->m_bWantExit) ::PostMessage(pDialog->GetSafeHwnd(),WM_THREAD_TERMINATE,0,0); return 1; } } ::PostMessage(pDialog->GetSafeHwnd(),WM_UPDATEDIALOG,0,0); ::PostMessage(pDialog->GetSafeHwnd(),WM_THREAD_TERMINATE,0,0); return 0; }
Was mach ich da falsch?
-
Hallo!
Durch die While-Schleife im Thread wird die Event-Verarbeitung unterbrochen,
daher wird der Tasten-Event von CBerechnungDlg::PreTranslateMessage nicht empfangen.
Wenn man in die While-Schleife folgendes einfügt::AfxPumpMessage();
dann sollte es klappen.
Gruß, Lothar.
-
Sowada schrieb:
Hallo!
Durch die While-Schleife im Thread wird die Event-Verarbeitung unterbrochen,
daher wird der Tasten-Event von CBerechnungDlg::PreTranslateMessage nicht empfangen.
Wenn man in die While-Schleife folgendes einfügt::AfxPumpMessage();
dann sollte es klappen.
Gruß, Lothar.
Hallo Lothar,
vielen Dank für die Info. Wenn ich das so mache, dann returniert er gar nicht. Ich hab jetzt auch rausgefunden, dass selbst wenn die Threadfunktion verlassen wird und der Thread beendet wird trotzdem die Nachricht nicht beim Dialog angekommt. Ganz komisches Verhalten...
-
@Sowada: Sofern das eine Threadfunktion ist stimmt das nicht. Denn der Workerthread muss keine Nachrichten behandeln.
@AndyDD:
Wie startest Du den Workerthread?
Wieso benutzt Du bitte KillThread? Und das ohne Parameter, wie den das?
-
Martin Richter schrieb:
@Sowada: Sofern das eine Threadfunktion ist stimmt das nicht. Denn der Workerthread muss keine Nachrichten behandeln.
@AndyDD:
Wie startest Du den Workerthread?
Wieso benutzt Du bitte KillThread? Und das ohne Parameter, wie den das?Also KillThread macht folgendes:
void CBerechnungDlg::KillThread(void) { if (m_pThread) { ::WaitForSingleObject(m_pThread->m_hThread,INFINITE); delete m_pThread; m_pThread=NULL; m_bIsRunning=false; } }
Das komisch ist, wenn ich einen Breakpoint setze und zwischen dem Anwendungsfenster und VS notwendigerweise hin und herspringen muss, dann funktioniert es nach Beenden des Threads wieder, dass er auf die VK_ESCAPE reagiert.
-
Kann es sein, dass der Focus auf ein anderes Fenster gesetzt wird. Was passiert wenn Du explizit in den Dialog noch mal hineinklickst und dann die Escape Taste drückst.
-
Martin Richter schrieb:
Kann es sein, dass der Focus auf ein anderes Fenster gesetzt wird. Was passiert wenn Du explizit in den Dialog noch mal hineinklickst und dann die Escape Taste drückst.
Das ändert leider nichts an dem Problem. Das Fenster scheint den Focus zu haben, denn die Buttons auf der Oberfläche funktionieren ja auch. Ich hab das gleiche Problem mit einem anderen Dialog, wo ich auch mit Threads arbeite. Möglicherweise mach ich da was falsch. Aber selbst wenn ich Autodelete auf true lasse, den Thread starte und ihn selbst beenden lasse habe ich dieses Verhalten. Keine Ahnung wo ich suchen soll...
-
Baust Du eine eigene Nachrichten Loop auf, wenn Du den Thread gestartet hast?
-
Martin Richter schrieb:
Baust Du eine eigene Nachrichten Loop auf, wenn Du den Thread gestartet hast?
Nein, ich wollte ja eben die vom Dialog nehmen. Ich habe jetzt festgestellt, dass das Deaktivieren eines Buttons mir dazwischenfunkt. Ich habe ein Member vom Typ CButton*, denen ich in der OnInitDialog die Verbinung zum Button gebe. Über diesen Zeiger deaktiviere ich in der OnBnClickedXXX den Button, damit der Thread nicht nochmal gestartet werden kann. Wenn der Thread returniert wird der Button wieder aktiviert. Ich greife auch nicht aus der Threadfunktion auf GUI-Elemente zu.
-
Also, wenn ich die Sachen mit dem Aktivieren/Deaktivieren weglasse, dann funktioniert es problemlos. Woran kann denn das liegen?