[gelöst] Was kann das EnableWindow(FALSE) blockieren?
-
Hallo,
ich verzweifle gerade an einem total bekloppten Phänomen.
Ich schreibe eine Software für ein Gerät. Zu diesem Gerät sollen Settings während der Messung übertragen werden können. Nun dauert es einen Moment, bis diese Settings bestätigt sind. Damit der Benutzer in dieser Zeit nichts verstellen kann, möchte ich die Controls des Dialogfeldes deaktivieren.
Die Steuerung übernimmt dabei ein DFA, der aus den Zuständen Unavailable, Idle und Busy und einem Bool-Array die Werte TRUE oder FALSE für die einzelnen Aufrufe zusammenstellt. SEL ist dabei eine ComboBox, NAME ein Edit Control:
bool tmp[3][13] = // SEL ACT REC VR1 2 3 DCM DCC HP1 2 LP BLC NAME /* 0: SltIdle */ {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* 1: -Busy- */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* 2: -Empty- */ {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
int slotdfa::GetCtrlEnableIndex() { if(SlotEmpty) return 2; if(SlotDFA_CurrentState != SltIdle) return 1; return 0; }
Der eigentliche Aufruf ist dabei immer dieselbe Codezeile:
void Slot::LockSlot() { if(SlotDFA->StateChanged()) { int i = SlotDFA->GetCtrlEnableIndex(); SlotControls.m_ctrlSEL->EnableWindow (SlotDFA->DlgCtrls[i][0]); SlotControls.m_ctrlACT->EnableWindow (SlotDFA->DlgCtrls[i][1]);
Das funktioniert für alle Check- und Radio-Boxen zuverlässig, für die Combo- und Edit Controls aber nicht: Im Zustand Idle und Unavailable geht's - die Controls werden gemäß der Tabelle gesperrt.
Im Zustand Busy hat der Tabelleneintrag aber keinerlei Auswirkungen, es sei denn, ich rufe unmittelbar nach den ganzen EnableWindows() einmalAfxMsgBox("") auf - dann seh ich, wie die Controls disabled sind und später wieder enabled werden.
Jetzt hab ich natürlich daran gedacht, dass an irgend einer anderen Programmstelle, die nur im Zustand Busy erreicht wird, irgend etwas mit dem Control passiert, was das Problem verursacht. Die gepostete Stelle ist jedoch der einzige Zugriff auf die Control-Variable, an sonsten passieren nur Zugriffe auf die Value-Variable und UpdateDatas. Dazu hab ich aber gerade ein kleines Testprogramm geschrieben - das verursacht den Fehler nicht.
Kann mir jemand einen Tip geben? Ich check' vorallem den Zusammenhang mit einer MessageBox nicht. Achja, die Controls haben im Moment des Enable/Disable NICHT den Fokus.
Ciao, Gerry
-
Setz einfach mal auf ALLE SlotControls.m_ctrlSEL->EnableWindow einen Breakpoint.
Du aktivierst die irgendwo wieder, ohne es zu wollen.
-
vielleicht mal ein RedrawWindow() oder UpdateData()
-
Du aktivierst die irgendwo wieder, ohne es zu wollen.
Naiiiinn, ja eben nicht! Das war ja genau die Intention dabei, das über einen DFA zu steuern: Es gibt im gesamten Programm genau diesen einen Zugriff auf das Steuerelement.
Ich hab das Problem gefunden - es hatte gar nichts mit dem Enable/Disable selbst zu tun.
Das hat nämlich funktioniert, als ich den DFA so umgeschrieben habe, so dass er nie wieder in den Zustand idle kam, wenn er ihn erstmal verlassen hatte. Allerdings mit merkwürdigem Effekt:
In dem Programmteil, der das Gerät ansteuert, (die Klasse ist in CMainFrame instanziert, ebenso wie die DialogBar, auf der das besagte Dialogfeld als PropPage in einem PropSheet eingebettet ist) habe ich eine Warteschleife eingebaut, die mir die Chance gibt, das korrekte Ausgrauen zu beobachten. Die war vom Typ
for(int i = 0; i < 10000000; i++);
Aus irgend einem mir nicht ganz verständlichen Grund ist Windows der Meinung, zuerst nur die Check- und Radioboxen zu disablen, dann diese (offenbar in einem anderen Thread laufende) Funktion auszuführen und erst danach die anderen beiden zu disablen. Das ließ sich dabei gut beobachten: Nach dem Klick auf eines der Steuerelemente trat der Automat in den Zustand 'busy' ein und die Check und Radioboxen waren grau, dann dauerte es etwa 5 Sekunden und danach, als eigentlich der Wechsel zu 'idle' angestanden hätte, welcher die Controls wieder freigeschaltet hätte, der aber jetzt blockiert war - verschwanden auch die Combobox und das Edit Control im Nebel.
Jetzt hab ich ein anderes Warteverfahren eingebaut und siehe da, es funktioniert. Phantom gejagt.
Da soll man drauf kommen
Ein ganzer Tag flöten.
-
Das Ganze kann so nicht funktionieren, weil keine Windowsnachrichten
mehr abgearbeitet werden. Du musst Windows schon mal die Chance geben,
Nachrichten abzuarbeiten.In Delphi gabs dazu die Funktion Application.ProcessMessages
Die schreibst Du dir am besten gleich selber
void ProcessMessages () { MSG msg; while (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
Und schon wird alles richtig angezeigt.
-
Hallo nemeses,
vielen Dank für diesen Tip. So funktioniert's!