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?
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?
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.
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?
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.
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); };
Empfohlene Beiträge
Erstelle ein Benutzerkonto oder melde Dich an, um zu kommentieren
Du musst ein Benutzerkonto haben, um einen Kommentar verfassen zu können
Benutzerkonto erstellen
Neues Benutzerkonto für unsere Community erstellen. Es ist einfach!
Neues Benutzerkonto erstellenAnmelden
Du hast bereits ein Benutzerkonto? Melde Dich hier an.
Jetzt anmelden