UpdateWindow(FALSE) - funktioniert nicht.
-
Hallo Leute,
bin neu hier und auch neu in der Programmierung-Welt...
Ich habe ein kleines Programm geschrieben (mein erstes mit MFC), es soll 4 Vierecke blinken lassen mit einem bestimmten Zeit Abstand.
Ein Screenshot des Programmes kann man hier sehen:
http://img514.imageshack.us/img514/8739/c01my9.png
Ich habe es mit Sleep() realisiert, ich poste mal den Code:
// Die Variablen werden im Konstruktor initialisiert: CMemoryTrainingView::CMemoryTrainingView() { // ZU ERLEDIGEN: Hier Code zur Konstruktion einfügen, //Initialisierung der Variablen ID = -1; m_feldZ = 1; m_runde = 0; m_comp = false; for(int i = 0; i < 200; i++) { m_feldReihe[i] = 0; } m_background.SetRect(103, 25, 353, 275); m_feld[0].SetRect(113, 35, 228, 150); m_feld[1].SetRect(228, 35, 343, 150); m_feld[2].SetRect(113, 150, 228, 265); m_feld[3].SetRect(228, 150, 343, 265); // Array für Farbenwechsel m_farben[0].CreateSolidBrush(0x00CC3300); // blau, hell Feld 1 m_farben[1].CreateSolidBrush(0x00CCADA3); // blau, blass Feld 1 m_farben[2].CreateSolidBrush(0x0000FFFF); // gelb, hell Feld 2 m_farben[3].CreateSolidBrush(0x00CCFFFF); // gelb, blass Feld 2 m_farben[4].CreateSolidBrush(0x0000FF00); // rot, hell Feld 4 m_farben[5].CreateSolidBrush(0x00CCFFCC); // rot, blass Feld 4 m_farben[6].CreateSolidBrush(0x000000CC); // grün, hell Feld 3 m_farben[7].CreateSolidBrush(0x00A3A3CC); // grün, blass Feld 3 m_farben[8].CreateSolidBrush(0x00C0C0C0); // hintergrund hellgrau m_farben[9].CreateSolidBrush(0x00696969); // hintergrund dunkelgrau } //FeldVorgabe() wird vom Start Button ausgelöst, sie soll ein Array mit 200 //mögliche Runde aufbauen und in Reihe blinken lassen... void CMemoryTrainingView::FeldVorgabe() { m_runde = 0; //dient als User click Zähler m_feldZ = 1; //Anzahl der zublinkenden Felder srand((unsigned)time(NULL)); for(int i = 0; i < 200; ++i) { //Zufallszahl generieren int m_Zahl= (rand()%4); m_feldReihe[i] = m_Zahl; } CompSpiele(); } //Die Funktion CompSpiele(): void CMemoryTrainingView::CompSpiele() { //Verbindung zur Documenten-Klasse herstellen CMemoryTrainingDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(pDoc->GetSpielStatus()) { CString str; str.Format("%i",m_feldZ); m_Textfeld.SetWindowText(str); m_comp = true; InvalidateRect(m_background); UpdateWindow(); for( int i = 0; i<m_feldZ; i++) { ID = m_feldReihe[i] * 2; Sleep(pDoc->m_iRadio); Blinke(ID); } m_runde = 0; m_comp = false; InvalidateRect(m_background); UpdateWindow(); } } //Die Funktion Blinke(): void CMemoryTrainingView::Blinke(int ID) { WechsleFarbe_h(ID); Sleep(300); WechsleFarbe_d(ID); } void CMemoryTrainingView::WechsleFarbe_h(int ID) { CDC* pDC = GetDC(); //Zeiger auf internen Gerätekontext pDC->FillRect(m_feld[ID/2], &m_farben[ID]); ReleaseDC(pDC); } void CMemoryTrainingView::WechsleFarbe_d(int ID) { CDC* pDC = GetDC(); //Zeiger auf internen Gerätekontext pDC->FillRect(m_feld[ID/2], &m_farben[ID+1]); ReleaseDC(pDC); }Es funktioniert aber:
Während der Computer spielt und der User irgendwo klickt, dieser Klick wird wahrgenommen und das möchte ich vermeiden. Ich versuche es mit der Variable m_comp und EnableWindow(FALSE) in der Methode OnDraw():
void CMemoryTrainingView::OnDraw(CDC* pDC) { CMemoryTrainingDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // ZU ERLEDIGEN: Hier Code zum Zeichnen der ursprünglichen Daten hinzufügen //Background Bild wird geladen CBitmap bitmap; CDC dcMemory; bitmap.LoadBitmap(IDB_BITMAP1); dcMemory.CreateCompatibleDC(pDC); dcMemory.SelectObject(&bitmap); pDC->BitBlt(0, 0, 461, 300, &dcMemory, 0, 0, SRCCOPY); //Viereck Background wird gezeichnet if(pDoc->GetSpielStatus()) { if(m_comp) { EnableWindow(FALSE); //So 'n Mist... Funktioniert hier nicht... Sleep() schuld? pDC->FillRect(m_background, &m_farben[9]); } else { EnableWindow(); pDC->FillRect(m_background, &m_farben[8]); } } else { pDC->FillRect(m_background, &m_farben[8]); EnableWindow(FALSE); } //Blasse Vierecke zeichnen pDC->FillRect(m_feld[0], &m_farben[1]); pDC->FillRect(m_feld[1], &m_farben[3]); pDC->FillRect(m_feld[2], &m_farben[5]); pDC->FillRect(m_feld[3], &m_farben[7]); }Die Ermittlung und abchecken von User Klicks habe ich so gemacht:
void CMemoryTrainingView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen und/oder Standard aufrufen ID = -1; if(m_feld[0].PtInRect(point)) { ID = 0; } if(m_feld[1].PtInRect(point)) { ID = 2; } if(m_feld[2].PtInRect(point)) { ID = 4; } if(m_feld[3].PtInRect(point)) { ID = 6; } if(ID != -1) { m_runde++; Spieler(ID); } CView::OnLButtonDown(nFlags, point); } void CMemoryTrainingView::Spieler(int ID) { //Verbindung zur Documenten-Klasse herstellen CMemoryTrainingDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(ID/2 != m_feldReihe[m_runde-1]) { //Falsches klicken CString str; str.Format("%i",m_feldZ-1); MessageBox("Sie haben "+str+" Runden durchgehalten"); //Ausgabe im Box m_Textfeld.SetWindowText("0"); pDoc->m_spiel = false; m_runde = 0; //Runde auf null setzen m_feldZ = 1; //Neu zeichen des Fensters und inaktiv machen Invalidate(); UpdateWindow(); EnableWindow(FALSE); } else { Blinke(ID); if(m_feldZ == m_runde) { m_feldZ++; CompSpiele(); } } }Frage: Warum funktioniert das nicht??? Ist Sleep() Schuld?? Wenn ja, wäre es besser (und möglich) mit SetTimer() zu realisieren?? Mit SetTimer() habe ich schon die Funktion Blinke() geschafft, aber die Schleife in der Funktion CompSpiele() hat Menge Probleme damit...
Sorry fürs Chaos

Vielen Dank.
-
Ich habe den Titel editiert und formuliere meine Frage anders.
Ich möchte dass die User Klicks während der Computer spielt nicht wahrgenommen werden.
Wie oben beschrieben, habe ich mit UpdateWindow(FALSE) versucht. Es klappt aber nicht.
Frage: Warum nicht?? Hätte ich vielleicht anders vorgehen müssen?
Für eine Antwort wäre ich sehr dankbar. Ich fange jetzt an mit der Programmierung, also, ich habe nicht viel Ahnung...
Wenn es hilft, das Spiel kann man hier runterladen:
www.tudobom.de/privat/MemoryTraining.zip
Danke!!
-
Mach doch einfach eine bool Variable, die du auf true setzt, wenn auf Klicks reagiert werden darf und die du in OnLButtonDown abfragst.

-
Hallo estartu,
Danke für die Antwort.
Tja... Das hatte ich schon versucht. Ich habe mit einem Zeiger die Variable m_comp in der Funktion CompSpiele() auf true und/oder false gesetzt und in OnLButtonDown abgefragt.
void CMemoryTrainingView::CompSpiele() { //Verbindung zur Documenten-Klasse herstellen CMemoryTrainingDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(pDoc->GetSpielStatus()) { CString str; str.Format("%i",m_feldZ); m_Textfeld.SetWindowText(str); // m_comp = true; *pComp = true, InvalidateRect(m_background); UpdateWindow(); for( int i = 0; i<m_feldZ; ++i) { ID = m_feldReihe[i] * 2; Sleep(pDoc->m_iRadio); Blinke(ID); } m_runde = 0; // m_comp = false; *pComp = false; InvalidateRect(m_background); UpdateWindow(); } } void CMemoryTrainingView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen und/oder Standard aufrufen ID = -1; if(!m_comp) { if(m_feld[0].PtInRect(point)) { ID = 0; } if(m_feld[1].PtInRect(point)) { ID = 2; } if(m_feld[2].PtInRect(point)) { ID = 4; } if(m_feld[3].PtInRect(point)) { ID = 6; } } if(ID != -1) { m_runde++; Spieler(ID); } CView::OnLButtonDown(nFlags, point); }Es funktioniert aber nicht. Wenn die Logik stimmt, habe ich eine Vermutung...
Meine Intuition sagt dass vielleicht werden die Klicks-Nachrichten in einer Warteschleife gesammelt und werden erst bearbeitet als der Computer eigentlich schon gespielt hat, das heisst, m_comp ist immer false bei der Klicks Bearbeitung... Ist das Blödsinn???
Gruß
bird
-
Warum machst du das mit einem Zeiger?

-
Da hast Du eine gute Intuition
Du setzt natürlich die ganze Nachrichtenbehandlung mit dem Sleep/for außer Kraft. Du könntest also mit einem Thread arbeiten oder mit einem Timer, aber die For-Schleife mit dem Sleep ist tödlich.
-
estartu schrieb:
Warum machst du das mit einem Zeiger?

Nochmal Anfänger Vermutung... Da es nicht funktioniert hat, dachte ich wäre es weil der aktuelle Wert von m_comp nicht in OnLButtonDown zur Verfügung stand. Das war ein Versuch m_comp Wert für alle Funktionen zu ändern... Falsch??
Im Konstruktor habe ich das geschrieben:
m_comp = false; pComp = &m_comp;Naja... Aber egal was ich tue, mit oder ohne pointer, funktioniert nicht...
-
connan schrieb:
Da hast Du eine gute Intuition
Du setzt natürlich die ganze Nachrichtenbehandlung mit dem Sleep/for außer Kraft. Du könntest also mit einem Thread arbeiten oder mit einem Timer, aber die For-Schleife mit dem Sleep ist tödlich.Oh, das hatte ich übersehen. Das ist wohl die wahrscheinlichere Ursache.
Ich würde es nun mit einem Timer versuchen.
-
connan schrieb:
Da hast Du eine gute Intuition
Du setzt natürlich die ganze Nachrichtenbehandlung mit dem Sleep/for außer Kraft. Du könntest also mit einem Thread arbeiten oder mit einem Timer, aber die For-Schleife mit dem Sleep ist tödlich.Hallo connan und estartu,
Die folgende Intuition nach dieser Intuition
war die Sleep() Funktion...Ich habe dann versucht mit SetTimer() zu arbeiten. Die Blinke Funktion habe ich hingekriegt, aber die CompSpiele(), mit der For-Schleife scheint mir unmöglich zu realisieren...
-
Unmöglich ist nichts. Du kannst mit Threads arbeiten oder du bearbeitest die Messageloop selbst. Siehe FAQ.
-
ShareBird schrieb:
Ich habe dann versucht mit SetTimer() zu arbeiten. Die Blinke Funktion habe ich hingekriegt, aber die CompSpiele(), mit der For-Schleife scheint mir unmöglich zu realisieren...
Das geht schon

1. Du kannst mehrere Timer setzen und per ID in OnTimer reagieren (also für blink UND compute).
2. Kannst Du, statt der For-Schleife, in einer Funktion einen Timer immer wieder neu setzen und z.B. über eine statische Variable den Zähler(=Abruchbedingung=>KillTimer) realisieren.
Wenn Du aber einfach nur Spaß am Programmieren und Lernen hast, schau Dir Threads an
-
Das einfachste ist es ein durchsichtiges Fenster über Deine eigentlichen Fenster zu legen. Dort werden die entsprechenden Mausklicks behandelt und werden dann in entsprechende MoveWndow/SetWindowPos auf die eigentlichen Objekte unter diesem Control ausgeführt.
-
Martin Richter schrieb:
Das einfachste ist es ein durchsichtiges Fenster über Deine eigentlichen Fenster zu legen. Dort werden die entsprechenden Mausklicks behandelt und werden dann in entsprechende MoveWndow/SetWindowPos auf die eigentlichen Objekte unter diesem Control ausgeführt.
Hmmm... Das war meine erste Idee, einer Art "Schutz" Ebene drauf zu legen, aber wie?? Wenn ich ein neues Fenster innerhalb dieses Fenster erzeuge, werden trotzdem Mausklicks wahrgenommen... (ich habe Testweise ein CEdit Objekt erzeugt, ich weiß nicht wie man ein neues Fenster CWindow innerhalb dieses Fenster erzeugt...).
Ich bin sehr dankbar für alle Tips die ich bis jetzt bekommen habe, aber ich schildere kurz meine Schwierigkeiten: Das erste mal dass ich einer Schleife, einer if Anweisung begegnet bin, war vor 30 Jahren!! Damals hat es nicht gefunkt, also, ich habe mich nicht weiter gekümmert.
Das zweite mal ist gerade 8 Monate her gewesen im Rahmen einer Reihe von "Blitz" Kurse: HTML, PHP, JavaScript, Flash, ActionScript, C++ und MFC, jeweils 15 Tage Theorie und 5 Tage Projekt. Bevor hatte ich keine Idee was ein "Array" zu bedeuten hätte... Ich habe Schwierigkeiten mit der Logik (ich habe Stunden gebraucht um die Spieler Funktion zu realisieren), Flow-Charts, etc., etc., etc...
Egal.. Irgendwie hat es diesmal gefunkt, ich lerne weiter.
Danke für die Geduld

-
Du musst das "obere" Fenster in der Z-Order so legen, dass es wirklich "über" den anderen Fenstern liegt.
Aber wenn Du so viele Schwieirgkeiten mit den Grundlagen hast. Würde ich mit etwas simpleren anfangen... Just my 2 cents.
-
Tja... Ich habe alles versucht...
Ich setze hier eine Sleep(ne Weile)...
Vielen Dank an alle für den Tips! Echt nett hier

Gruß
-
Hmm... Anscheinend habe ich das Problem gelöst. Ich werde sicherlich (besser, hoffentlich) sehr darüber lachen was für Lösungen ich in dieser Zeit gefunden habe.
Ich habe diesen Code in der Funktion CompSpiele() eingefügt:
MSG message;if(::PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
::TranslateMessage(&message);
::DispatchMessage(&message);
}void CMemoryTrainingView::CompSpiele() { //Verbindung zur Documenten-Klasse herstellen CMemoryTrainingDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(pDoc->GetSpielStatus()) { CString str; str.Format("%i",m_feldZ); m_Textfeld.SetWindowText(str); m_comp = true; InvalidateRect(m_background); UpdateWindow(); for( int i = 0; i<m_feldZ; ++i) { ID = m_feldReihe[i] * 2; Sleep(pDoc->m_iRadio); MSG message; if(::PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) { ::TranslateMessage(&message); ::DispatchMessage(&message); } Blinke(ID); } m_runde = 0; m_comp = false; InvalidateRect(m_background); UpdateWindow(); } }Irgendwann werde ich verstehen warum es geklappt hat...

Gruß
bird