Zum Inhalt springen
View in the app

A better way to browse. Learn more.

Fachinformatiker.de

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Empfohlene Antworten

Veröffentlicht

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?

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?

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.

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?

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.

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);

};

Erstelle ein Konto oder melde dich an, um einen Kommentar zu schreiben.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.