witch doctor Geschrieben 11. Dezember 2004 Geschrieben 11. Dezember 2004 Hi, ich habe so für mich ein kleines TIC TAC TOE Spiel programmiert. Das dumme ist nur, dass die Grafik weg ist, sobald sie von einem Fenster verdeckt wird. Jetzt habe ich gelesen, dass man das mit der OnDraw Methode im View lösen muss. Doch irgendwie blicke ich da nicht durch. Was muss ich da genau machen? Zitieren
witch doctor Geschrieben 11. Dezember 2004 Autor Geschrieben 11. Dezember 2004 Hier ist meine OnPaint Methode, bisher ist es nur das Aussehen: void spiel::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: Fügen Sie hier Ihren Meldungsbehandlungscode ein. // CDialog::OnPaint() soll zum Zeichnen von Meldungen nicht aufgerufen werden. dc.FillRect(frame,&stdbrush.white); for(int z=0;z<3;z++) { for(int s=0;s<3;s++) { int x = frame.left+s*feldbreite; int y = frame.top+z*feldhoehe; feld.SetRect(x,y,x+feldbreite,y+feldhoehe); dc.Rectangle(feld); felder[z][s]=feld; } } void* oldpen; if(kreuz==true) { oldpen = dc.SelectObject(&stdpen.rgb5); CPoint topleft = kreuz_rechteck.TopLeft(); CPoint bottomright = kreuz_rechteck.BottomRight(); int x = topleft.x; int y = topleft.y; int x2 = bottomright.x; int y2 = bottomright.y; dc.MoveTo(kreuz_rechteck.TopLeft()); dc.LineTo(kreuz_rechteck.BottomRight()); dc.MoveTo(x,bottomright.y); dc.LineTo(bottomright.x,topleft.y); kreuz=false; kreis=true; } else //Kreis { oldpen = dc.SelectObject(&stdpen.blue5); dc.Ellipse(kreis_rechteck); kreis=false; kreuz=true; } } Die OnDraw Methode ist jetzt so ähnlich wie die OnPaint, doch da passiert es, dass beim Verdecken sich nur willkürlich Grafiken gemerkt werden. Ich verstehe es nicht mehr. void CtictactoeView::OnDraw(CDC* pDC) { CtictactoeDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; CRect feld; GetClientRect(&feld); game.zeichnen(pDC); } game ist dabei ein extern meiner Spieldatei, wo die OnPaint Methode ausprogrammiert wurde. Die Zeichnen Methode ist dann folgendermaßen: void spiel::zeichnen(CDC* pDC) { pDC->FillRect(frame,&stdbrush.white); for(int z=0;z<3;z++) { for(int s=0;s<3;s++) { int x = frame.left+s*feldbreite; int y = frame.top+z*feldhoehe; feld.SetRect(x,y,x+feldbreite,y+feldhoehe); //dc.Rectangle(feld); pDC->Rectangle(feld); felder[z][s]=feld; } } void* oldpen; if(kreuz==true) { oldpen = pDC->SelectObject(&stdpen.rgb5); CPoint topleft = kreuz_rechteck.TopLeft(); CPoint bottomright = kreuz_rechteck.BottomRight(); int x = topleft.x; int y = topleft.y; int x2 = bottomright.x; int y2 = bottomright.y; pDC->MoveTo(kreuz_rechteck.TopLeft()); pDC->LineTo(kreuz_rechteck.BottomRight()); pDC->MoveTo(x,bottomright.y); pDC->LineTo(bottomright.x,topleft.y); kreuz=false; kreis=true; } else //Kreis { oldpen = pDC->SelectObject(&stdpen.blue5); pDC->Ellipse(kreis_rechteck); kreis=false; kreuz=true; } } kreis und kreuz sind zwei boolean. Dies dient dazu, damit wirklich abwechselnd gespielt wird. Kann mir jemand helfen? Zitieren
Klotzkopp Geschrieben 12. Dezember 2004 Geschrieben 12. Dezember 2004 Für mich sieht das so aus, als ob du immer nur das Feld für den zuletzt gemachten Zug ausmalst. Du malst ja immer nur entweder einen Kreis oder ein Kreuz. Die vorausgegangenen Züge musst du auch malen. P.S.: Wenn kreis sowieso immer !kreuz, kannst du auch auf eine der beiden Variablen verzichten. Zitieren
witch doctor Geschrieben 12. Dezember 2004 Autor Geschrieben 12. Dezember 2004 Nach einer Fehleranalyse habe ich gemerkt, dass er sich immer die vorherige Grafik merkt. Die Boolean Variablen habe ich mal aus OnDraw rausgeschmissen. Hm...stimmt, er soll alles zeichnen. Könnte man das evtl. mit einem Array lösen, welches die Werte ausliest ? (x und y werte) Wie ist denn überhaupt das prinzipielle Vorgehen bei der OnDraw Methode? Zitieren
witch doctor Geschrieben 12. Dezember 2004 Autor Geschrieben 12. Dezember 2004 Habe es mal folgendermaßen abgeändert. Die Rechtecke werden in ein 3x3 Array abgespeichert. Nur irgendwie funktioniert das auch nicht, und ich weiß nicht warum. void spiel::zeichnen(CDC* pDC) { /* Hier wird der Fensterinhalt zurückgeschrieben */ for(int z=0;z<3;z++) { for(int s=0;s<3;s++) { pDC->SelectObject(&stdpen.rgb5); // Kreuze neu zeichnen CPoint topleft = r_array[z][s].TopLeft(); CPoint bottomright = r_array[z][s].BottomRight(); int x = topleft.x; int y = topleft.y; int x2 = bottomright.x; int y2 = bottomright.y; pDC->MoveTo(r_array[z][s].TopLeft()); pDC->LineTo(bottomright.x,topleft.y); //Kreise neu zeichnen pDC->SelectObject(&stdpen.blue5); pDC->Ellipse(r_array[z][s]); } } } Der Code zum klicken wurde folgendermaßen verändert: void spiel::OnLButtonDown(UINT nFlags, CPoint point) { if(!frame.PtInRect(point)) return; int spalte=point.x/feldbreite; int zeile=point.y/feldhoehe; if(geklickt[zeile][spalte]) return; if(kreuz) { kreuz_rechteck.SetRect(felder[zeile][spalte].TopLeft(),felder[zeile][spalte].BottomRight()); r_array[zeile][spalte]=kreuz_rechteck; zaehler++; InvalidateRect(kreuz_rechteck,false); geklickt[zeile][spalte]=1; } else //Kreis { kreis_rechteck.SetRect(felder[zeile][spalte].TopLeft(),felder[zeile][spalte].BottomRight()); r_array[zeile][spalte]=kreis_rechteck; zaehler++; InvalidateRect(kreis_rechteck,false); geklickt[zeile][spalte]=1; } CDialog::OnLButtonDown(nFlags, point); } Alles andere ist gleich geblieben. Zitieren
witch doctor Geschrieben 15. Dezember 2004 Autor Geschrieben 15. Dezember 2004 Hi, habe das Problem gelöst!! Es ist ziemlich egal ob man OnDraw oder OnPaint nimmt. Obwohl in OnPaint funktioniert es. Hier der Code ohne Spiellogik (noch ist ein brutales Invalidate() enthalten, dies sollte man durch invalidaterect(rechteck) oder einem offscreen ersetzen): // spiel.cpp : Implementierungsdatei // #include "stdafx.h" #include "tictactoe.h" #include "spiel.h" #include ".\spiel.h" #include "draw.h" spiel game; // spiel-Dialogfeld IMPLEMENT_DYNAMIC(spiel, CDialog) spiel::spiel(CWnd* pParent /*=NULL*/) : CDialog(spiel::IDD, pParent) { abstand = 5; for(int i=0;i<3;i++) { for(int j=0;j<3;j++) { geklickt[i][j]=0; } } for(int i=0;i<3;i++) { for(int j=0;j<3;j++) { inhalt[i][j]=0; } } } spiel::~spiel() { } void spiel::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_RAHMEN, rahmen); } BEGIN_MESSAGE_MAP(spiel, CDialog) ON_WM_PAINT() ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() // spiel-Meldungshandler void spiel::OnPaint() { UpdateData(TRUE); CPaintDC dc(this); // device context for painting // TODO: Fügen Sie hier Ihren Meldungsbehandlungscode ein. // CDialog::OnPaint() soll zum Zeichnen von Meldungen nicht aufgerufen werden. dc.FillRect(frame,&stdbrush.white); void* oldpen; for(int z=0;z<3;z++) { for(int s=0;s<3;s++) { int x = frame.left+s*feldbreite; int y = frame.top+z*feldhoehe; feld.SetRect(x,y,x+feldbreite,y+feldhoehe); dc.Rectangle(feld); felder[z][s]=feld; } } for(int z=0;z<3;z++) { for(int s=0;s<3;s++) { if(inhalt[z][s]==KREUZ) { oldpen = dc.SelectObject(&stdpen.rgb5); CPoint topleft = gezeichnet[z][s].TopLeft(); CPoint bottomright = gezeichnet[z][s].BottomRight(); int x = topleft.x; int y = topleft.y; int x2 = bottomright.x; int y2 = bottomright.y; dc.MoveTo(topleft); dc.LineTo(bottomright); dc.MoveTo(x,bottomright.y); dc.LineTo(bottomright.x,topleft.y); } if(inhalt[z][s]==KREIS) { oldpen = dc.SelectObject(&stdpen.blue5); dc.Ellipse(gezeichnet[z][s]); } } UpdateData(false); } if(kreuz==true) { oldpen = dc.SelectObject(&stdpen.rgb5); CPoint topleft = kreuz_rechteck.TopLeft(); CPoint bottomright = kreuz_rechteck.BottomRight(); int x = topleft.x; int y = topleft.y; int x2 = bottomright.x; int y2 = bottomright.y; dc.MoveTo(kreuz_rechteck.TopLeft()); dc.LineTo(kreuz_rechteck.BottomRight()); dc.MoveTo(x,bottomright.y); dc.LineTo(bottomright.x,topleft.y); kreuz=false; } else //Kreis { oldpen = dc.SelectObject(&stdpen.blue5); dc.Ellipse(kreis_rechteck); kreuz=true; } } BOOL spiel::OnInitDialog() { CDialog::OnInitDialog(); rahmen.GetWindowRect(&frame); ScreenToClient(&frame); breite = frame.Width(); hoehe = frame.Height(); feldbreite = breite / 3; feldhoehe = hoehe / 3; return TRUE; // return TRUE unless you set the focus to a control // AUSNAHME: OCX-Eigenschaftenseite muss FALSE zurückgeben. } void spiel::OnLButtonDown(UINT nFlags, CPoint point) { UpdateData(TRUE); if(!frame.PtInRect(point)) return; int spalte=point.x/feldbreite; int zeile=point.y/feldhoehe; if(geklickt[zeile][spalte]) return; if(kreuz) { kreuz_rechteck.SetRect(felder[zeile][spalte].TopLeft(),felder[zeile][spalte].BottomRight()); inhalt[zeile][spalte]=KREUZ; gezeichnet[zeile][spalte]=kreuz_rechteck; Invalidate(); geklickt[zeile][spalte]=1; } else //Kreis { kreis_rechteck.SetRect(felder[zeile][spalte].TopLeft(),felder[zeile][spalte].BottomRight()); inhalt[zeile][spalte]=KREIS; gezeichnet[zeile][spalte]=kreis_rechteck; Invalidate(); geklickt[zeile][spalte]=1; } UpdateData(false); CDialog::OnLButtonDown(nFlags, point); } Und hier noch die dazugehörige Headerdatei. Ich habe noch zwei symbolische Konstanten KREUZ und KREIS hinzugefügt, die in der Abfrage des Arrays genutzt werden. #pragma once #include "afxwin.h" #define KREUZ 1 #define KREIS 2 // spiel-Dialogfeld class spiel : public CDialog { DECLARE_DYNAMIC(spiel) public: spiel(CWnd* pParent = NULL); // Standardkonstruktor virtual ~spiel(); CRect frame; CRect felder[3][3]; CRect feld; //int feld[3][3]; int breite; int hoehe; int abstand; int feldbreite; int feldhoehe; bool kreuz; bool kreis; CRect kreuz_rechteck; CRect kreis_rechteck; int geklickt[3][3]; CRect gezeichnet[3][3]; int inhalt[3][3]; // Dialogfelddaten enum { IDD = IDD_spiel }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-Unterstützung DECLARE_MESSAGE_MAP() public: CStatic rahmen; afx_msg void OnPaint(); virtual BOOL OnInitDialog(); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); }; Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.