Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   
Forentreff 2012     
Bücher-Shop mit Amazon (Buchkategorien)C++ : Referenzen zu C++ : C++ Builder : Visual C++ : C# : Java : Spieleprogrammierung : Systemprogrammierung Linux : Software-Entwicklung : .NET : Compilertechnik : Algorithmen & Datenstrukturen : Objektorientierung : Entwurfsmuster : UML : eXtreme Programming : Scrum : Projektmanagement : Software-Testing : Datenbanken : Tom DeMarco : Dilbert : User Friendly
C/C++ Forum :: Die Artikel ::  wxWidgets Tutorial Part II: Spiel mit mir     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
phlox81
Moderator

Benutzerprofil
Anmeldungsdatum: 21.04.2001
Beiträge: 7208
Beitrag phlox81 Moderator 22:38:15 12.03.2007   Titel:   wxWidgets Tutorial Part II: Spiel mit mir            Zitieren

1 Vorbemerkungen

Nachdem ich im ersten Artikel die Grundlagen von wxWidgets behandelt habe, möchte ich in diesem Artikel die Grundlagen etwas vertiefen, und an einer kleinen Beispielanwendung zeigen, was man mit wxWidgets so realisieren kann. Diese Beispielanwendung wird ein Tic-Tac-Toe Spiel sein. Im Gegensatz zum ersten Artikel verwende ich nun jedoch eine neue wxWidgets-Version(2.8.0), welche aber kompatibel zu 2.6 ist, somit sollte sich die Beispielanwendung auch mit einer älteren wxWidgets-Version kompilieren lassen.

1.1 wxWidgets 2.8.0

Bevor ich mit dem eigentlichen Tutorial anfange, möchte ich kurz noch auf einige Änderungen und Neuerungen hinweisen, die wxWidgets 2.8.0 mit sich bringt. wxWidgets verfügt nun über eine eigene RichTextCtrl-Library, für die Ein- bzw. Ausgabe von formatiertem Text (Allerdings kann diese Library noch keine Standard rtf-Dateien lesen).
Auch wurde eine Dockinglibrary in wxWidgets aufgenommen, mit wxAUI (Advanced User Interface) lassen sich Fenster erstellen, welche sich in der Anwendung dann verschieben und an/abdocken lassen. Alle Neuerungen finden sich in diesem Artikel.

Ein kleiner Hinweis noch an alle MinGW-Benutzer, die bisher die Library mit Msys gebaut haben:
Die mitgelieferten Builddateien scheinen fehlerhaft zu sein, ich konnte jedenfalls wxWidgets2.8.0 nicht mit Msys kompilieren. Alternativ geht es aber über die Windowskommandozeile, einfach in das Verzeichnis %wxDir%/build/msw wechseln, und mit "mingw32-make.exe -f makefile.gcc" den Buildprozess starten. Wer die Library als Releaseversion bauen will, muss in der config.gcc den Wert BUILD von debug auf release setzen.

2 Implementierung eines eigenen Steuerelementes

Beim Erstellen eines eigenen Steuerelementes ist vor allem das Eventhandling wichtig. Man muss in seinem Steuerelement bestimmte Events empfangen können, und auf diese dann entsprechend reagieren. Falls es schon ein Steuerelement gibt, welches einen Teil der Anforderungen abdeckt, empfiehlt es sich von diesem abzuleiten. Wenn dies nicht möglich ist, sollte man sein Steuerelement von wxPanel ableiten, oder falls man ein "scrollbares" Steuerelement will, von wxScrolledWindow.
Bei der Beispielanwendung ist es so, dass wir ein Steuerelement brauchen, welches als Spielfeld, bzw. Spielstein fungiert.
Dafür leiten wir von wxPanel ab, und richten für wxEVT_PAINT und wxEVT_LEFT_DOWN eigene Handler ein:

2.1 Selber zeichnen

Für den Spielstein ist es wichtig, anhand seines Stati ein X oder ein O zu zeichnen. Wenn man den wxPaintEvent überschreibt, muss man in der OnPaint-Methode einen wxPaintDC anlegen, damit wxWidgets weiß, dass das Fenster neugezeichnet wurde, ansonsten würde wxWidgets weiter Paintevents an das Fenster schicken.

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void FieldPanel::OnPaint(wxPaintEvent& event)
{
    wxPaintDC dc(this);
    dc.DrawRectangle(2,2,GetSize().GetWidth()-2,GetSize().GetHeight()-2);
    int abstand = 10;
    if(status == GameLogic::X)
    {
        wxPen pen = *wxRED_PEN;
        pen.SetStyle(wxSOLID);
        pen.SetWidth(4);
        dc.SetPen(pen);
        dc.DrawLine(abstand,abstand,GetSize().GetWidth()-abstand,GetSize().GetHeight()-abstand);
        dc.DrawLine(GetSize().GetWidth()-abstand,abstand,abstand,GetSize().GetHeight()-abstand);
    }
    else if(status == GameLogic::O)
    {
        wxPen pen(wxColour(0,0,250),4);
        dc.SetPen(pen);
        int x = GetSize().GetWidth()/2;
        int y = GetSize().GetHeight()/2;
        if( x < y )
            dc.DrawCircle(x,y,x - abstand);
        else
            dc.DrawCircle(x,y,y - abstand);
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void FieldPanel::OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
dc.DrawRectangle(2,2,GetSize().GetWidth()-2,GetSize().GetHeight()-2);
int abstand = 10;
if(status == GameLogic::X)
{
wxPen pen = *wxRED_PEN;
pen.SetStyle(wxSOLID);
pen.SetWidth(4);
dc.SetPen(pen);
dc.DrawLine(abstand,abstand,GetSize().GetWidth()-abstand,GetSize().GetHeight()-abstand);
dc.DrawLine(GetSize().GetWidth()-abstand,abstand,abstand,GetSize().GetHeight()-abstand);
}
else if(status == GameLogic::O)
{
wxPen pen(wxColour(0,0,250),4);
dc.SetPen(pen);
int x = GetSize().GetWidth()/2;
int y = GetSize().GetHeight()/2;
if( x < y )
dc.DrawCircle(x,y,x - abstand);
else
dc.DrawCircle(x,y,y - abstand);
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void FieldPanel::OnPaint(wxPaintEvent& event)
{
    wxPaintDC dc(this);
    dc.DrawRectangle(2,2,GetSize().GetWidth()-2,GetSize().GetHeight()-2);
    int abstand = 10;
    if(status == GameLogic::X)
    {
        wxPen pen = *wxRED_PEN;
        pen.SetStyle(wxSOLID);
        pen.SetWidth(4);
        dc.SetPen(pen);
        dc.DrawLine(abstand,abstand,GetSize().GetWidth()-abstand,GetSize().GetHeight()-abstand);
        dc.DrawLine(GetSize().GetWidth()-abstand,abstand,abstand,GetSize().GetHeight()-abstand);
    }
    else if(status == GameLogic::O)
    {
        wxPen pen(wxColour(0,0,250),4);
        dc.SetPen(pen);
        int x = GetSize().GetWidth()/2;
        int y = GetSize().GetHeight()/2;
        if( x < y )
            dc.DrawCircle(x,y,x - abstand);
        else
            dc.DrawCircle(x,y,y - abstand);
    }
}


2.2 Mausevent

Da nur der Linksklick als Mausevent registriert wurde, reagiert auch das Steuerelement nur auf diesen.
In diesem Fall muss geprüft werden, ob der aktuelle Status noch den Anfangswert ist, und dann ein neuer Wert gesetzt werden:
C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
void FieldPanel::OnLeftClick(wxMouseEvent& event)
{
    if(status == GameLogic::EMPTY)
    {
        status = GameLogic::X;// Der Spieler hat den X Stein.
        Refresh();// Panel aktualisieren
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
void FieldPanel::OnLeftClick(wxMouseEvent& event)
{
if(status == GameLogic::EMPTY)
{
status = GameLogic::X;// Der Spieler hat den X Stein.
Refresh();// Panel aktualisieren
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
void FieldPanel::OnLeftClick(wxMouseEvent& event)
{
    if(status == GameLogic::EMPTY)
    {
        status = GameLogic::X;// Der Spieler hat den X Stein.
        Refresh();// Panel aktualisieren
    }
}


Jetzt stellt das Panel zwar den Zug dar, aber außerhalb von dieser Panelinstanz hat niemand etwas von diesen Event wahrgenommen. Wenn wir davon ausgehen, das jeder Spielstein einem Spielfeld liegt, so müsste dieses Spielfeld das Parent des Steuerelementes sein. Man könnte also mittels eines Casts den Parentzeiger auf die Spielfeldklasse casten, und dort dann eine Methode aufrufen. Für den aktuellen Fall würde dies gehen, solange bis das Control eine andere Parentklasse hätte.
Es wäre also eleganter wenn das Steuerelement einen Event an sein Parentfenster senden könnte.

2.3 Ein eigener Notifyevent

Die Implementierung unseres eigenen Events sieht so aus:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
class TurnEvent : public wxNotifyEvent
{
    int status;
    int field;
public:
    TurnEvent(int status, int field, wxEventType eventType = wxEVT_NULL, int id = 0);
    TurnEvent(const TurnEvent& copy);
    virtual ~TurnEvent();
    virtual TurnEvent* Clone()const {return new TurnEvent(*this);};
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
class TurnEvent : public wxNotifyEvent
{
int status;
int field;
public:
TurnEvent(int status, int field, wxEventType eventType = wxEVT_NULL, int id = 0);
TurnEvent(const TurnEvent& copy);
virtual ~TurnEvent();
virtual TurnEvent* Clone()const {return new TurnEvent(*this);};
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
class TurnEvent : public wxNotifyEvent
{
    int status;
    int field;
public:
    TurnEvent(int status, int field, wxEventType eventType = wxEVT_NULL, int id = 0);
    TurnEvent(const TurnEvent& copy);
    virtual ~TurnEvent();
    virtual TurnEvent* Clone()const {return new TurnEvent(*this);};
};


Über die Variablen status und field wird übergeben welches Spielfeld den Event auslöst, und welcher Spielstein dort gesetzt werden soll.
Damit wxWidgets die Eventklasse auch kennt, und den Event entsprechend weiterleiten kann, sind noch einige Makros nötig:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// in der TurnEvent.hpp (nach der Klassendeklaration)

// ein Typedef auf die entsprechenden EventHandler

typedef void(wxEvtHandler::*TurnEventFunction)(TurnEvent&);

// wxWidgets den neuen Event mitteilen
BEGIN_DECLARE_EVENT_TYPES()
  DECLARE_EVENT_TYPE(EVT_TURN_CHANGE, -1)
END_DECLARE_EVENT_TYPES()

// dieses #define sorgt dafür das man den Event über den Makro EventTable einbinden kann
#define
EVT_TURN_CHANGE_MACRO(id, fn) DECLARE_EVENT_TABLE_ENTRY(               \
        EVT_TURN_CHANGE, id, -1, (wxObjectEventFunction)               \
        (wxEventFunction)(TurnEventFunction) & fn,                             \
        (wxObject*) NULL),

// dieses #define sorgt dafür das man den Event auch über Connect verbinden kann
#define
TurnEventHandler(func)                                                 \
        (wxObjectEventFunction)                                                \
        (wxEventFunction)wxStaticCastEvent(TurnEventFunction, &func)

// in der TurnEvent.cpp muss nun 'nur' noch der Event Definiert werden:
DEFINE_EVENT_TYPE(EVT_TURN_CHANGE)
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// in der TurnEvent.hpp (nach der Klassendeklaration)

// ein Typedef auf die entsprechenden EventHandler

typedef void(wxEvtHandler::*TurnEventFunction)(TurnEvent&);

// wxWidgets den neuen Event mitteilen
BEGIN_DECLARE_EVENT_TYPES()
DECLARE_EVENT_TYPE(EVT_TURN_CHANGE, -1)
END_DECLARE_EVENT_TYPES()

// dieses #define sorgt dafür das man den Event über den Makro EventTable einbinden kann
#define
EVT_TURN_CHANGE_MACRO(id, fn) DECLARE_EVENT_TABLE_ENTRY( \
EVT_TURN_CHANGE, id, -1, (wxObjectEventFunction) \
(wxEventFunction)(TurnEventFunction) & fn, \
(wxObject*) NULL),

// dieses #define sorgt dafür das man den Event auch über Connect verbinden kann
#define
TurnEventHandler(func) \
(wxObjectEventFunction) \
(wxEventFunction)wxStaticCastEvent(TurnEventFunction, &func)

// in der TurnEvent.cpp muss nun 'nur' noch der Event Definiert werden:
DEFINE_EVENT_TYPE(EVT_TURN_CHANGE)
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// in der TurnEvent.hpp (nach der Klassendeklaration)

// ein Typedef auf die entsprechenden EventHandler

typedef void(wxEvtHandler::*TurnEventFunction)(TurnEvent&);

// wxWidgets den neuen Event mitteilen
BEGIN_DECLARE_EVENT_TYPES()
  DECLARE_EVENT_TYPE(EVT_TURN_CHANGE, -1)
END_DECLARE_EVENT_TYPES()

// dieses #define sorgt dafür das man den Event über den Makro EventTable einbinden kann
#define
EVT_TURN_CHANGE_MACRO(id, fn) DECLARE_EVENT_TABLE_ENTRY(               \
        EVT_TURN_CHANGE, id, -1, (wxObjectEventFunction)               \
        (wxEventFunction)(TurnEventFunction) & fn,                             \
        (wxObject*) NULL),

// dieses #define sorgt dafür das man den Event auch über Connect verbinden kann
#define
TurnEventHandler(func)                                                 \
        (wxObjectEventFunction)                                                \
        (wxEventFunction)wxStaticCastEvent(TurnEventFunction, &func)

// in der TurnEvent.cpp muss nun 'nur' noch der Event Definiert werden:
DEFINE_EVENT_TYPE(EVT_TURN_CHANGE)


Nun ist der Event fertig implementiert, und kann nun von FieldPanel in der OnLeftClick Methode gesendet werden:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
void FieldPanel::OnLeftClick(wxMouseEvent& event)
{
    if(status == GameLogic::EMPTY)
    {
        status = GameLogic::X;
        Refresh();// Panel aktualisieren
        TurnEvent myevent(GameLogic::X,id,EVT_TURN_CHANGE);
        GetParent()->AddPendingEvent(myevent);
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
void FieldPanel::OnLeftClick(wxMouseEvent& event)
{
if(status == GameLogic::EMPTY)
{
status = GameLogic::X;
Refresh();// Panel aktualisieren
TurnEvent myevent(GameLogic::X,id,EVT_TURN_CHANGE);
GetParent()->AddPendingEvent(myevent);
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
void FieldPanel::OnLeftClick(wxMouseEvent& event)
{
    if(status == GameLogic::EMPTY)
    {
        status = GameLogic::X;
        Refresh();// Panel aktualisieren
        TurnEvent myevent(GameLogic::X,id,EVT_TURN_CHANGE);
        GetParent()->AddPendingEvent(myevent);
    }
}


... und wird in der Klasse GamePanel empfangen:
C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
// im Konstruktor wird Connect aufgerufen
Connect(EVT_TURN_CHANGE,TurnEventHandler(GamePanel::OnTurnChange));

// Und in der GamePanel.cpp entsprechend die Event Methode definiert:
void GamePanel::OnTurnChange(TurnEvent& event)
{
    wxMessageBox("TurnChange Event!");
}
C/C++ Code:
1
2
3
4
5
6
7
8
// im Konstruktor wird Connect aufgerufen
Connect(EVT_TURN_CHANGE,TurnEventHandler(GamePanel::OnTurnChange));

// Und in der GamePanel.cpp entsprechend die Event Methode definiert:
void GamePanel::OnTurnChange(TurnEvent& event)
{
wxMessageBox("TurnChange Event!");
}
C/C++ Code:
1
2
3
4
5
6
7
8
// im Konstruktor wird Connect aufgerufen
Connect(EVT_TURN_CHANGE,TurnEventHandler(GamePanel::OnTurnChange));

// Und in der GamePanel.cpp entsprechend die Event Methode definiert:
void GamePanel::OnTurnChange(TurnEvent& event)
{
    wxMessageBox("TurnChange Event!");
}


Nun ist unser eigenes Steuerelement fertig.

3 Das Programm

Mit Fieldpanel verfügt die Anwendung nun über ein Steuerelement welches als Spielstein fungieren kann. Das Programm hat einen recht einfachen Aufbau, als Basisgerüst dient eine von wxFrame abgeleitete Klasse, welches ja schon aus dem ersten Teil des Tutorials bekannt ist. In unserer Anwendung ist die Klasse MyFrame aber eher ein Nebendarsteller, abgesehen von ihren Standardaufgaben (Exit, Infotext anzeigen, Menuhandling) werden ihr die restlichen Aufgaben von GamePanel abgenommen. Das ist ganz bewusst so gewählt, es bietet einige Vorteile, zum einen kann man später das Aussehen der Applikation leicht verändern, falls man z.B. ein MDI Tic Tac Toe Spiel umsetzen will, oder aber auch die Klasse MyFrame kopieren, und wo anders wieder als Basis für z.b. ein 4 Gewinnt Spiel nutzen.
Die Klasse GamePanel kümmert sich nun um das eigentliche Spielgeschehen, und empfängt auch die Events unseres Steuerelementes FieldPanel:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class GamePanel : public wxPanel
{
    GameLogic gamelogic;// die eigentliche Spiellogik wurde (teilweise) ausgelagert
    std::vector<FieldPanel*> panels;// das Spielfeld
    int freefields;// Hilfsvariable
    wxStaticText* player1;// Damit es netter aussieht
    wxStaticText* player2;// Damit es netter aussieht Vol2
    int player1_won;// Counter zum zählen wer wann gewonnen hat
    int player2_won;
    wxString playername;
protected:
public:
    GamePanel(wxWindow* parent, int id);
    virtual ~GamePanel();
    void OnTurnChange(TurnEvent& event);// Die Eventmethode
    void Clear();
};
// GamePanel Constructor
GamePanel::GamePanel(wxWindow* parent, int id): wxPanel(parent,id)
{
    wxFlexGridSizer* flexgridsizer= new wxFlexGridSizer(1,2,0,0);
    flexgridsizer->AddGrowableRow(0);
    flexgridsizer->AddGrowableCol(0);
    wxGridSizer *gSizer1;
    gSizer1 = new wxGridSizer(3, 3, 0, 0);// Spielfeldsizer
    for(int i =0; i < 9; i++)// füllen des Spielfeldes mit Spielsteinen
    {
        panels.push_back(new FieldPanel(this,i));
        gSizer1->Add(panels.back(), 0, wxEXPAND | wxALL, 5);
    }
    flexgridsizer->Add(gSizer1,0, wxEXPAND | wxALL, 5);
    wxBoxSizer* box= new wxBoxSizer(wxVERTICAL);
    playername = wxT("Player1");
    player1_won =0;
    player2_won=0;
    // Zum Anzeigen wer wie oft gewonnen hat
    player1 = new wxStaticText(this,-1,playername + wxString::Format(" wins %i games",player1_won));
    box->Add(player1,0, wxALL, 5);
    player2 = new wxStaticText(this,-1,wxString::Format("Computer wins %i games",player2_won));
    box->Add(player2,0, wxALL, 5);
    flexgridsizer->Add(box,0, wxALL, 5);
    this->SetSizer(flexgridsizer);
    this->SetAutoLayout(true);
    this->Layout();
    // Der Event für den nächsten Spielzug
    Connect(EVT_TURN_CHANGE,TurnEventHandler(GamePanel::OnTurnChange));
   
    freefields = 9;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class GamePanel : public wxPanel
{
GameLogic gamelogic;// die eigentliche Spiellogik wurde (teilweise) ausgelagert
std::vector<FieldPanel*> panels;// das Spielfeld
int freefields;// Hilfsvariable
wxStaticText* player1;// Damit es netter aussieht
wxStaticText* player2;// Damit es netter aussieht Vol2
int player1_won;// Counter zum zählen wer wann gewonnen hat
int player2_won;
wxString playername;
protected:
public:
GamePanel(wxWindow* parent, int id);
virtual ~GamePanel();
void OnTurnChange(TurnEvent& event);// Die Eventmethode
void Clear();
};
// GamePanel Constructor
GamePanel::GamePanel(wxWindow* parent, int id): wxPanel(parent,id)
{
wxFlexGridSizer* flexgridsizer= new wxFlexGridSizer(1,2,0,0);
flexgridsizer->AddGrowableRow(0);
flexgridsizer->AddGrowableCol(0);
wxGridSizer *gSizer1;
gSizer1 = new wxGridSizer(3, 3, 0, 0);// Spielfeldsizer
for(int i =0; i < 9; i++)// füllen des Spielfeldes mit Spielsteinen
{
panels.push_back(new FieldPanel(this,i));
gSizer1->Add(panels.back(), 0, wxEXPAND | wxALL, 5);
}
flexgridsizer->Add(gSizer1,0, wxEXPAND | wxALL, 5);
wxBoxSizer* box= new wxBoxSizer(wxVERTICAL);
playername = wxT("Player1");
player1_won =0;
player2_won=0;
// Zum Anzeigen wer wie oft gewonnen hat
player1 = new wxStaticText(this,-1,playername + wxString::Format(" wins %i games",player1_won));
box->Add(player1,0, wxALL, 5);
player2 = new wxStaticText(this,-1,wxString::Format("Computer wins %i games",player2_won));
box->Add(player2,0, wxALL, 5);
flexgridsizer->Add(box,0, wxALL, 5);
this->SetSizer(flexgridsizer);
this->SetAutoLayout(true);
this->Layout();
// Der Event für den nächsten Spielzug
Connect(EVT_TURN_CHANGE,TurnEventHandler(GamePanel::OnTurnChange));

freefields = 9;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class GamePanel : public wxPanel
{
    GameLogic gamelogic;// die eigentliche Spiellogik wurde (teilweise) ausgelagert
    std::vector<FieldPanel*> panels;// das Spielfeld
    int freefields;// Hilfsvariable
    wxStaticText* player1;// Damit es netter aussieht
    wxStaticText* player2;// Damit es netter aussieht Vol2
    int player1_won;// Counter zum zählen wer wann gewonnen hat
    int player2_won;
    wxString playername;
protected:
public:
    GamePanel(wxWindow* parent, int id);
    virtual ~GamePanel();
    void OnTurnChange(TurnEvent& event);// Die Eventmethode
    void Clear();
};
// GamePanel Constructor
GamePanel::GamePanel(wxWindow* parent, int id): wxPanel(parent,id)
{
    wxFlexGridSizer* flexgridsizer= new wxFlexGridSizer(1,2,0,0);
    flexgridsizer->AddGrowableRow(0);
    flexgridsizer->AddGrowableCol(0);
    wxGridSizer *gSizer1;
    gSizer1 = new wxGridSizer(3, 3, 0, 0);// Spielfeldsizer
    for(int i =0; i < 9; i++)// füllen des Spielfeldes mit Spielsteinen
    {
        panels.push_back(new FieldPanel(this,i));
        gSizer1->Add(panels.back(), 0, wxEXPAND | wxALL, 5);
    }
    flexgridsizer->Add(gSizer1,0, wxEXPAND | wxALL, 5);
    wxBoxSizer* box= new wxBoxSizer(wxVERTICAL);
    playername = wxT("Player1");
    player1_won =0;
    player2_won=0;
    // Zum Anzeigen wer wie oft gewonnen hat
    player1 = new wxStaticText(this,-1,playername + wxString::Format(" wins %i games",player1_won));
    box->Add(player1,0, wxALL, 5);
    player2 = new wxStaticText(this,-1,wxString::Format("Computer wins %i games",player2_won));
    box->Add(player2,0, wxALL, 5);
    flexgridsizer->Add(box,0, wxALL, 5);
    this->SetSizer(flexgridsizer);
    this->SetAutoLayout(true);
    this->Layout();
    // Der Event für den nächsten Spielzug
    Connect(EVT_TURN_CHANGE,TurnEventHandler(GamePanel::OnTurnChange));
   
    freefields = 9;
}


Ich habe mich entschlossen die eigentliche Spiellogik nicht in diesem Tutorial zu behandeln, da sie im eigentlichen Sinne nichts mit wxWidgets zu tun hat, dennoch ist sie vollständig in der Beispielanwendung implementiert, den Link zum vollständigen Code der Anwendung befindet sich am Ende des Tutorials.

Die Anwendung sieht nun so aus:




4 Ein eigener Dialog


Wie man auf dem obigen Bild und im GamePanel Konstruktor sieht, ist der Standardname für den Spieler "Player1". Als Programmierer kann man den Namen des Spielers nicht wissen, folglich sollte man dem Spieler eine Möglichkeit geben, diesen zu ändern, ebenfalls kann man in diesem Settingsdialog die Farben von X und O ändern:



Die Klasse SettingsDlg ist von wxDialog abgeleitet, und hat neben einem Konstruktor jeweils Handler für die X und O Buttons:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class SettingsDlg : public wxDialog
{
    wxColour xcolor;
    wxColour ocolor;
    wxButton* btn_xcolor;
    wxButton* btn_ocolor;
    // Diese Panel dienen der Darstellung der Farbe
    wxPanel* xpanel;
    wxPanel* opanel;
    wxTextCtrl* txt_name;
protected:
public:
    SettingsDlg(wxString playername, wxWindow* parent, int id);
    virtual ~SettingsDlg();
    void OnXColor(wxCommandEvent& event);
    void OnOColor(wxCommandEvent& event);
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class SettingsDlg : public wxDialog
{
wxColour xcolor;
wxColour ocolor;
wxButton* btn_xcolor;
wxButton* btn_ocolor;
// Diese Panel dienen der Darstellung der Farbe
wxPanel* xpanel;
wxPanel* opanel;
wxTextCtrl* txt_name;
protected:
public:
SettingsDlg(wxString playername, wxWindow* parent, int id);
virtual ~SettingsDlg();
void OnXColor(wxCommandEvent& event);
void OnOColor(wxCommandEvent& event);
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class SettingsDlg : public wxDialog
{
    wxColour xcolor;
    wxColour ocolor;
    wxButton* btn_xcolor;
    wxButton* btn_ocolor;
    // Diese Panel dienen der Darstellung der Farbe
    wxPanel* xpanel;
    wxPanel* opanel;
    wxTextCtrl* txt_name;
protected:
public:
    SettingsDlg(wxString playername, wxWindow* parent, int id);
    virtual ~SettingsDlg();
    void OnXColor(wxCommandEvent& event);
    void OnOColor(wxCommandEvent& event);
};


Der Konstruktor:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
SettingsDlg::SettingsDlg(wxString playername, wxWindow* parent, int id):
    wxDialog(parent,wxT("Application Settings"),id), xcolor(FieldPanel::xcolor), ocolor(FieldPanel::ocolor)
{
    wxBoxSizer* mainbox = new wxBoxSizer(wxVERTICAL);
   
    // xcolor Settings
    wxStaticBoxSizer* xcolorbox = new wxStaticBoxSizer(wxHORIZONTAL,this,wxT("X Colorsettings"));
   
    xpanel = new wxPanel(this,-1);
    xpanel->SetBackgroundColour(xcolor);
    xcolorbox->Add(xpanel,0,wxALL|wxEXPAND,5);
    btn_xcolor = new wxButton(this,wxNewId(),wxT("Change Color"));
    xcolorbox->Add(btn_xcolor,0,wxALL,5);
   
    mainbox->Add(xcolorbox,0,wxALL|wxEXPAND,5);
   
    // ocolor Settings
    wxStaticBoxSizer* ocolorbox = new wxStaticBoxSizer(wxHORIZONTAL,this,wxT("O Colorsettings"));
   
    opanel = new wxPanel(this,-1);
    opanel->SetBackgroundColour(ocolor);
    ocolorbox->Add(opanel,0,wxALL|wxEXPAND,5);
    btn_ocolor = new wxButton(this,wxNewId(),wxT("Change Color"));
    ocolorbox->Add(btn_ocolor,0,wxALL,5);
   
    mainbox->Add(ocolorbox,0,wxALL|wxEXPAND,5);
   
    // name Settings
    wxBoxSizer* namebox = new wxBoxSizer(wxHORIZONTAL);
   
    namebox->Add(new wxStaticText(this,-1,wxT("Playername: ")),0,wxALL,5);
    txt_name = new wxTextCtrl(this,wxNewId(),playername);
    namebox->Add(txt_name,0,wxALL,5);
   
    mainbox->Add(namebox,0,wxALL,5);
    // Ok und Cancel Buttons hinzufügen
    mainbox->Add(CreateStdDialogButtonSizer(wxOK|wxCANCEL),0,wxALL,5);
    SetSizer(mainbox);
    SetAutoLayout(true);
    Layout();
    Fit();
   
    // Eventhandler
    Connect(btn_xcolor->GetId(),wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(SettingsDlg::OnXColor));
    Connect(btn_ocolor->GetId(),wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(SettingsDlg::OnOColor));
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
SettingsDlg::SettingsDlg(wxString playername, wxWindow* parent, int id):
wxDialog(parent,wxT("Application Settings"),id), xcolor(FieldPanel::xcolor), ocolor(FieldPanel::ocolor)
{
wxBoxSizer* mainbox = new wxBoxSizer(wxVERTICAL);

// xcolor Settings
wxStaticBoxSizer* xcolorbox = new wxStaticBoxSizer(wxHORIZONTAL,this,wxT("X Colorsettings"));

xpanel = new wxPanel(this,-1);
xpanel->SetBackgroundColour(xcolor);
xcolorbox->Add(xpanel,0,wxALL|wxEXPAND,5);
btn_xcolor = new wxButton(this,wxNewId(),wxT("Change Color"));
xcolorbox->Add(btn_xcolor,0,wxALL,5);

mainbox->Add(xcolorbox,0,wxALL|wxEXPAND,5);

// ocolor Settings
wxStaticBoxSizer* ocolorbox = new wxStaticBoxSizer(wxHORIZONTAL,this,wxT("O Colorsettings"));

opanel = new wxPanel(this,-1);
opanel->SetBackgroundColour(ocolor);
ocolorbox->Add(opanel,0,wxALL|wxEXPAND,5);
btn_ocolor = new wxButton(this,wxNewId(),wxT("Change Color"));
ocolorbox->Add(btn_ocolor,0,wxALL,5);

mainbox->Add(ocolorbox,0,wxALL|wxEXPAND,5);

// name Settings
wxBoxSizer* namebox = new wxBoxSizer(wxHORIZONTAL);

namebox->Add(new wxStaticText(this,-1,wxT("Playername: ")),0,wxALL,5);
txt_name = new wxTextCtrl(this,wxNewId(),playername);
namebox->Add(txt_name,0,wxALL,5);

mainbox->Add(namebox,0,wxALL,5);
// Ok und Cancel Buttons hinzufügen
mainbox->Add(CreateStdDialogButtonSizer(wxOK|wxCANCEL),0,wxALL,5);
SetSizer(mainbox);
SetAutoLayout(true);
Layout();
Fit();

// Eventhandler
Connect(btn_xcolor->GetId(),wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(SettingsDlg::OnXColor));
Connect(btn_ocolor->GetId(),wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(SettingsDlg::OnOColor));
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
SettingsDlg::SettingsDlg(wxString playername, wxWindow* parent, int id):
    wxDialog(parent,wxT("Application Settings"),id), xcolor(FieldPanel::xcolor), ocolor(FieldPanel::ocolor)
{
    wxBoxSizer* mainbox = new wxBoxSizer(wxVERTICAL);
   
    // xcolor Settings
    wxStaticBoxSizer* xcolorbox = new wxStaticBoxSizer(wxHORIZONTAL,this,wxT("X Colorsettings"));
   
    xpanel = new wxPanel(this,-1);
    xpanel->SetBackgroundColour(xcolor);
    xcolorbox->Add(xpanel,0,wxALL|wxEXPAND,5);
    btn_xcolor = new wxButton(this,wxNewId(),wxT("Change Color"));
    xcolorbox->Add(btn_xcolor,0,wxALL,5);
   
    mainbox->Add(xcolorbox,0,wxALL|wxEXPAND,5);
   
    // ocolor Settings
    wxStaticBoxSizer* ocolorbox = new wxStaticBoxSizer(wxHORIZONTAL,this,wxT("O Colorsettings"));
   
    opanel = new wxPanel(this,-1);
    opanel->SetBackgroundColour(ocolor);
    ocolorbox->Add(opanel,0,wxALL|wxEXPAND,5);
    btn_ocolor = new wxButton(this,wxNewId(),wxT("Change Color"));
    ocolorbox->Add(btn_ocolor,0,wxALL,5);
   
    mainbox->Add(ocolorbox,0,wxALL|wxEXPAND,5);
   
    // name Settings
    wxBoxSizer* namebox = new wxBoxSizer(wxHORIZONTAL);
   
    namebox->Add(new wxStaticText(this,-1,wxT("Playername: ")),0,wxALL,5);
    txt_name = new wxTextCtrl(this,wxNewId(),playername);
    namebox->Add(txt_name,0,wxALL,5);
   
    mainbox->Add(namebox,0,wxALL,5);
    // Ok und Cancel Buttons hinzufügen
    mainbox->Add(CreateStdDialogButtonSizer(wxOK|wxCANCEL),0,wxALL,5);
    SetSizer(mainbox);
    SetAutoLayout(true);
    Layout();
    Fit();
   
    // Eventhandler
    Connect(btn_xcolor->GetId(),wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(SettingsDlg::OnXColor));
    Connect(btn_ocolor->GetId(),wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(SettingsDlg::OnOColor));
}


4.1 wxWidgets Standarddialoge

wxWidgets bietet für verschiedene Aufgaben Standarddialoge an (z.B. Datei- oder Verzeichnisauswahl, Passwortabfragen, Textabfragen etc.), welche dann den jeweiligen Standarddialogen auf der jeweiligen Plattform entsprechen. Als Beispiel für Standarddialoge verwende ich aber nun wxColourDialog, da wir ja dem Benutzer ermöglichen wollen für das X und O eigene Farben zu vergeben:

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// direkter Aufruf des Standarddialoges
void SettingsDlg::OnXColor(wxCommandEvent& event)
{
    wxColourData data;
    data.SetChooseFull(true);
    // der ColourDialog bietet 16 "Standardfarben" an.
    for (int i = 0; i < 16; i++)
    {
        wxColour colour(i*16, i*16, i*16);
        data.SetCustomColour(i, colour);
    }
    // Die vorausgewählte Farbe, Standard ist Schwarz
    data.SetColour(xcolor);
    wxColourDialog dialog(this,&data);
    if (dialog.ShowModal() == wxID_OK)
    {
        wxColourData retData = dialog.GetColourData();
        xcolor = retData.GetColour();
        xpanel->SetBackgroundColour(xcolor);
        xpanel->Refresh();
    }
}
// wxWidgets bietet auch vorgefertigte Funktionen, mit denen man die Standarddialoge aufrufen kann:
void SettingsDlg::OnOColor(wxCommandEvent& event)
{
    wxColour col = wxGetColourFromUser(this, ocolor);
    // mit col.Ok() wird der Returnwert des Dialoges überprüft
    if(col.Ok())
    {
        ocolor = col;
        opanel->SetBackgroundColour(ocolor);
        opanel->Refresh();
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// direkter Aufruf des Standarddialoges
void SettingsDlg::OnXColor(wxCommandEvent& event)
{
wxColourData data;
data.SetChooseFull(true);
// der ColourDialog bietet 16 "Standardfarben" an.
for (int i = 0; i < 16; i++)
{
wxColour colour(i*16, i*16, i*16);
data.SetCustomColour(i, colour);
}
// Die vorausgewählte Farbe, Standard ist Schwarz
data.SetColour(xcolor);
wxColourDialog dialog(this,&data);
if (dialog.ShowModal() == wxID_OK)
{
wxColourData retData = dialog.GetColourData();
xcolor = retData.GetColour();
xpanel->SetBackgroundColour(xcolor);
xpanel->Refresh();
}
}
// wxWidgets bietet auch vorgefertigte Funktionen, mit denen man die Standarddialoge aufrufen kann:
void SettingsDlg::OnOColor(wxCommandEvent& event)
{
wxColour col = wxGetColourFromUser(this, ocolor);
// mit col.Ok() wird der Returnwert des Dialoges überprüft
if(col.Ok())
{
ocolor = col;
opanel->SetBackgroundColour(ocolor);
opanel->Refresh();
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// direkter Aufruf des Standarddialoges
void SettingsDlg::OnXColor(wxCommandEvent& event)
{
    wxColourData data;
    data.SetChooseFull(true);
    // der ColourDialog bietet 16 "Standardfarben" an.
    for (int i = 0; i < 16; i++)
    {
        wxColour colour(i*16, i*16, i*16);
        data.SetCustomColour(i, colour);
    }
    // Die vorausgewählte Farbe, Standard ist Schwarz
    data.SetColour(xcolor);
    wxColourDialog dialog(this,&data);
    if (dialog.ShowModal() == wxID_OK)
    {
        wxColourData retData = dialog.GetColourData();
        xcolor = retData.GetColour();
        xpanel->SetBackgroundColour(xcolor);
        xpanel->Refresh();
    }
}
// wxWidgets bietet auch vorgefertigte Funktionen, mit denen man die Standarddialoge aufrufen kann:
void SettingsDlg::OnOColor(wxCommandEvent& event)
{
    wxColour col = wxGetColourFromUser(this, ocolor);
    // mit col.Ok() wird der Returnwert des Dialoges überprüft
    if(col.Ok())
    {
        ocolor = col;
        opanel->SetBackgroundColour(ocolor);
        opanel->Refresh();
    }
}


In der Klasse GamePanel wird der Dialog aufgerufen:

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
void GamePanel::ShowSettings()
{
    SettingsDlg dlg(playername,this,-1);
    if(dlg.ShowModal() == wxID_OK)
    {
        FieldPanel::xcolor = dlg.Getxcolor();
        FieldPanel::ocolor = dlg.Getocolor();
        playername = dlg.Getplayername();
        Refresh();
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
void GamePanel::ShowSettings()
{
SettingsDlg dlg(playername,this,-1);
if(dlg.ShowModal() == wxID_OK)
{
FieldPanel::xcolor = dlg.Getxcolor();
FieldPanel::ocolor = dlg.Getocolor();
playername = dlg.Getplayername();
Refresh();
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
void GamePanel::ShowSettings()
{
    SettingsDlg dlg(playername,this,-1);
    if(dlg.ShowModal() == wxID_OK)
    {
        FieldPanel::xcolor = dlg.Getxcolor();
        FieldPanel::ocolor = dlg.Getocolor();
        playername = dlg.Getplayername();
        Refresh();
    }
}


5. Dateien speichern und laden

Jetzt fehlt nur noch dass die Anwendung die Einstellungen auch speichern kann. Man kann problemlos unter wxWidgets die STL nutzen, und mittels <fstream> Dateien schreiben und lesen. wxWidgets bietet jedoch auch eigene Streamklassen an, welche auch Support für Zipstreams oder Sockets bieten.
Für die Beispielanwendung jedoch reicht ein simpler wxFileStream aus:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Die Einstellungen in einer Datei speichern
void GamePanel::SaveSettings()
{
    wxFileOutputStream file("settings");
    if(file.Ok())
    {
        wxTextOutputStream out(file);
        out << FieldPanel::xcolor.Red() << ' ' << FieldPanel::xcolor.Green() << ' '<< FieldPanel::xcolor.Blue() << endl;

        out << FieldPanel::ocolor.Red() << ' '<< FieldPanel::ocolor.Green() << ' '<< FieldPanel::ocolor.Blue() << endl;

        out << playername;
    }
}

// Die Einstellungen aus einer Datei laden
void GamePanel::LoadSettings()
{
    wxFileInputStream file("settings");
    if(file.Ok())
    {
        wxTextInputStream in(file);
        int r,g,b;
        in >> r >> g >> b;
        FieldPanel::xcolor.Set(r,g,b);
        in >> r >> g >> b;
        FieldPanel::ocolor.Set(r,g,b);
        playername = in.ReadLine();
    }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Die Einstellungen in einer Datei speichern
void GamePanel::SaveSettings()
{
wxFileOutputStream file("settings");
if(file.Ok())
{
wxTextOutputStream out(file);
out << FieldPanel::xcolor.Red() << ' ' << FieldPanel::xcolor.Green() << ' '<< FieldPanel::xcolor.Blue() << endl;

out << FieldPanel::ocolor.Red() << ' '<< FieldPanel::ocolor.Green() << ' '<< FieldPanel::ocolor.Blue() << endl;

out << playername;
}
}

// Die Einstellungen aus einer Datei laden
void GamePanel::LoadSettings()
{
wxFileInputStream file("settings");
if(file.Ok())
{
wxTextInputStream in(file);
int r,g,b;
in >> r >> g >> b;
FieldPanel::xcolor.Set(r,g,b);
in >> r >> g >> b;
FieldPanel::ocolor.Set(r,g,b);
playername = in.ReadLine();
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Die Einstellungen in einer Datei speichern
void GamePanel::SaveSettings()
{
    wxFileOutputStream file("settings");
    if(file.Ok())
    {
        wxTextOutputStream out(file);
        out << FieldPanel::xcolor.Red() << ' ' << FieldPanel::xcolor.Green() << ' '<< FieldPanel::xcolor.Blue() << endl;

        out << FieldPanel::ocolor.Red() << ' '<< FieldPanel::ocolor.Green() << ' '<< FieldPanel::ocolor.Blue() << endl;

        out << playername;
    }
}

// Die Einstellungen aus einer Datei laden
void GamePanel::LoadSettings()
{
    wxFileInputStream file("settings");
    if(file.Ok())
    {
        wxTextInputStream in(file);
        int r,g,b;
        in >> r >> g >> b;
        FieldPanel::xcolor.Set(r,g,b);
        in >> r >> g >> b;
        FieldPanel::ocolor.Set(r,g,b);
        playername = in.ReadLine();
    }
}


Den Code der Beispielanwendung findet sich hier.

Weitere Links zum Thema wxWidgest:
http://www.wxwidgets.org
Die offizielle wxWidgets Klassenliste (englisch)
Das offizielle wxWidgets Forum (englisch)

_________________
Intelligenz ist eine Illusion des Menschen

phlox81.de | The Black Board | Code Node | Xing | Blog | Twitter


Zuletzt bearbeitet von estartu am 08:43:58 04.04.2007, insgesamt 3-mal bearbeitet
Ben04
Autor

Benutzerprofil
Anmeldungsdatum: 10.10.2004
Beiträge: 1635
Beitrag Ben04 Autor 00:02:33 20.05.2007   Titel:              Zitieren

Gute Einführung in das Zeichnen mit wxWidgets. :) :live:

Ist es mit wxWidgets eigentlich irgendwie möglich auf ähnliche Zeichenfunktionen zuzugreifen wie sie beispielsweise GDI+ bietet? Damit meine ich zum Beispiel das Antialiasing von Linien oder Alphablending von Bitmaps.
phlox81
Moderator

Benutzerprofil
Anmeldungsdatum: 21.04.2001
Beiträge: 7208
Beitrag phlox81 Moderator 14:26:10 20.05.2007   Titel:              Zitieren

Ich mein es gäbe mittlerweile dafür Klassen, aber ich finds jetzt gerade nicht in der Doku. Gesehen hab ich das aber mal.
Evtl. wirst du auch auf wxCode fündig. wxCairo gibts glaub ich da auch noch.

_________________
Intelligenz ist eine Illusion des Menschen

phlox81.de | The Black Board | Code Node | Xing | Blog | Twitter
Dummie
Mitglied

Benutzerprofil
Anmeldungsdatum: 19.06.2004
Beiträge: 416
Beitrag Dummie Mitglied 14:39:42 20.05.2007   Titel:              Zitieren

Hi :)

Erstmal muss ich auch sagen: Gute Einführung :)

Aber was mich interessiert:

Heißt es tatsächlich:
"Player X wins 4 games"

Vielleicht ist mein Sprachgefühl ja wieder kaputt jetzt sogar im Englischen :D

Aber ich würde schreiben: Player X won 4 games

Was ist nun richtig?

Danke im Voraus

Gruß Patrick
phlox81
Moderator

Benutzerprofil
Anmeldungsdatum: 21.04.2001
Beiträge: 7208
Beitrag phlox81 Moderator 14:44:48 20.05.2007   Titel:              Zitieren

Ich würde sagen beides ;)
Das eine ist halt die Vergangenheitsform, wobei ich noch nicht so lange gespielt habe, das sie sinnvoll wäre ;)

_________________
Intelligenz ist eine Illusion des Menschen

phlox81.de | The Black Board | Code Node | Xing | Blog | Twitter
bloodycross
Mitglied

Benutzerprofil
Anmeldungsdatum: 16.04.2007
Beiträge: 44
Beitrag bloodycross Mitglied 21:55:32 03.06.2007   Titel:              Zitieren

[klugscheiß]Ich würde eher sagen "Player has won 4 games" da er die Spiele zwar schon gewonnen hat, aber derzeit noch spielt.[/klugscheiß]

Zum Tutorial selbst: Gut struktiert und auch der Code ist gut lesbar, auch für diejenigen die wxWidgets nicht kenne. :live:

lg, bloodycross
Lurnon
Mitglied

Benutzerprofil
Anmeldungsdatum: 21.05.2008
Beiträge: 37
Beitrag Lurnon Mitglied 23:02:15 30.12.2008   Titel:              Zitieren

Schönes Tut (hat mir schon gut geholfen), nur leider kommt beim kompilieren (Build) der Dateien folgender Fehler:

undefined reference to `__imp__EVT_TURN_CHANGE

Woran kann dies liegen?

Edit: Als Programm nutze ich Code::Blocks mit MinGW


Zuletzt bearbeitet von Lurnon am 23:02:56 30.12.2008, insgesamt 1-mal bearbeitet
phlox81
Moderator

Benutzerprofil
Anmeldungsdatum: 21.04.2001
Beiträge: 7208
Beitrag phlox81 Moderator 00:23:43 31.12.2008   Titel:              Zitieren

Klingt nach einem Linkerfehler. Sind die Dateien auch korrekt im Projekt eingetragen?

_________________
Intelligenz ist eine Illusion des Menschen

phlox81.de | The Black Board | Code Node | Xing | Blog | Twitter
Lurnon
Mitglied

Benutzerprofil
Anmeldungsdatum: 21.05.2008
Beiträge: 37
Beitrag Lurnon Mitglied 12:44:20 31.12.2008   Titel:              Zitieren

@phlox81
Meiner Meinung ja.
Wenn es dir nichts ausmacht, wärest du bereit mal selbst einen Blick drauf zuwerfen:
http://rapidshare.com/files/178409139/TTT.rar.html


Gruß
Lurnon
phlox81
Moderator

Benutzerprofil
Anmeldungsdatum: 21.04.2001
Beiträge: 7208
Beitrag phlox81 Moderator 14:43:41 31.12.2008   Titel:              Zitieren

Also ich hab gerade das Zipfile im Original runter geladen, und das kompiliert hier ohne Probleme.

_________________
Intelligenz ist eine Illusion des Menschen

phlox81.de | The Black Board | Code Node | Xing | Blog | Twitter
Lurnon
Mitglied

Benutzerprofil
Anmeldungsdatum: 21.05.2008
Beiträge: 37
Beitrag Lurnon Mitglied 11:23:06 10.01.2009   Titel:              Zitieren

Problem gelöst (siehe:hier 1. Post)
GreenDelta
Unregistrierter




Beitrag GreenDelta Unregistrierter 14:13:22 08.04.2009   Titel:              Zitieren

Ich verstehe grade nicht so ganz wie ich das Programm compilieren soll (also den runtergeladenen Beispielcode) steh da total auf dem Schlauch.

Ich benutzte Linux (Ubuntu Intrepid) und den g++ compiler.
tree in meinem tictactoe ordner gibt:
.
|-- Game
| |-- FieldPanel.cpp
| |-- FieldPanel.hpp
| |-- GameLogic.cpp
| |-- GameLogic.hpp
| |-- GamePanel.cpp
| |-- GamePanel.hpp
| |-- SettingsDlg.cpp
| `-- SettingsDlg.hpp
|-- TurnEvent.cpp
|-- TurnEvent.hpp
|-- app.cpp
|-- app.h
|-- main.cpp
|-- main.h
|-- settings
|-- tictactoe.cbp
|-- tictactoe.depend
|-- tictactoe.layout
`-- wx_pch.h

Sind also alle Dateien da.
Compilieren tue ich mit:
g++ main.cpp `wx-config --libs` `wx-config --cxxflags` -o prog

aber er sagt er könne die GamePanel.hpp nicht finden, obwohl sie doch da ist??
was ist falsch?
BBBB
Unregistrierter




Beitrag BBBB Unregistrierter 00:25:10 10.04.2009   Titel:              Zitieren

Vielleicht müssen sich alle Datein im selben Ordner befinden?
Tollmer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.09.2010
Beiträge: 3
Beitrag Tollmer Mitglied 17:39:41 26.10.2010   Titel:   Linkerfehler            Zitieren

Also entweder ist ein Fehler im Programm selbst was ich mir allerdings bei einem Tutorial nicht vorstellen möchte oder es liegt an dem folgenden Fehler...

Codeblocks couldnt parse wxs file because wxsmith is disabled...

Nach diesem Fehler hab ich mich jetzt schon durch etliche Foren gekämpft aber nichts gefunden. Es wäre schön wenn von euch vll einer Rat wüsste achja die Fehler post ich auch mal

||=== TICTACTOE, Debug ===|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp||In member function 'void Game::FieldPanel::OnPaint(wxPaintEvent&)':|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|21|error: 'wxPaintDC' was not declared in this scope|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|21|error: expected ';' before 'dc'|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|22|error: 'dc' was not declared in this scope|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|26|error: variable 'wxPen pen' has initializer but incomplete type|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|35|error: variable 'wxPen pen' has initializer but incomplete type|
||=== Build finished: 5 errors, 0 warnings ===|

Muss dazu sagen das ich noch nicht allzuviel Erfahrung mit wxwidgets habe da wir das Thema gerade begonnen haben. Aber auf diesen Fehler weiss unserer Programmierlehrer auch keinen Rat.

Mit freundlichen Grüßen
Tollmer


Zuletzt bearbeitet von Tollmer am 18:12:21 26.10.2010, insgesamt 1-mal bearbeitet
flopsty
Unregistrierter




Beitrag flopsty Unregistrierter 00:55:49 27.10.2010   Titel:              Zitieren

Konnte es auch problemlos kompilieren. Sieht gut aus! :)
phlox81
Moderator

Benutzerprofil
Anmeldungsdatum: 21.04.2001
Beiträge: 7208
Beitrag phlox81 Moderator 10:30:04 27.10.2010   Titel:   Re: Linkerfehler            Zitieren

Tollmer schrieb:
Also entweder ist ein Fehler im Programm selbst was ich mir allerdings bei einem Tutorial nicht vorstellen möchte oder es liegt an dem folgenden Fehler...

Codeblocks couldnt parse wxs file because wxsmith is disabled...

Nach diesem Fehler hab ich mich jetzt schon durch etliche Foren gekämpft aber nichts gefunden. Es wäre schön wenn von euch vll einer Rat wüsste achja die Fehler post ich auch mal

||=== TICTACTOE, Debug ===|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp||In member function 'void Game::FieldPanel::OnPaint(wxPaintEvent&)':|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|21|error: 'wxPaintDC' was not declared in this scope|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|21|error: expected ';' before 'dc'|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|22|error: 'dc' was not declared in this scope|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|26|error: variable 'wxPen pen' has initializer but incomplete type|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|35|error: variable 'wxPen pen' has initializer but incomplete type|
||=== Build finished: 5 errors, 0 warnings ===|

Muss dazu sagen das ich noch nicht allzuviel Erfahrung mit wxwidgets habe da wir das Thema gerade begonnen haben. Aber auf diesen Fehler weiss unserer Programmierlehrer auch keinen Rat.



Also das sieht nach einem Problem mit den Pfaden aus.
Überprüfe doch bitte ob deine Pfade zu wx korrekt sind.

_________________
Intelligenz ist eine Illusion des Menschen

phlox81.de | The Black Board | Code Node | Xing | Blog | Twitter
Tollmer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.09.2010
Beiträge: 3
Beitrag Tollmer Mitglied 16:30:44 30.10.2010   Titel:   Wxsmith fehler            Zitieren

Heyho leute also mit dem Pfaden müsste das ja eig stimmen weil einfache Proejekte funktionieren ja auch.Das Testprojekt von wxSmith funktioniert übrigens auch.Das ist iwie komisch^^

aber dennohc einmal die Pfade die ich eingestellt habe:

Settings->Compiler und Debuggersettings->Linker Settings->C:\Program Files\CodeBlocks\wxWidgets2.8\lib\gcc_dll

Settings->Compiler und Debuggersettings->Search Directories->C:\Program Files\CodeBlocks\wxWidgets2.8\lib\gcc_dll

Settings->Compiler und Debuggersettings->Toolchain Executables->Additional Paths->C:\Program Files\CodeBlocks\wxWidgets2.8\lib\gcc_dll

Mit freundlichen Grüßen
Tollmer
,,,,
Unregistrierter




Beitrag ,,,, Unregistrierter 18:24:20 03.11.2010   Titel:              Zitieren

Und das Include Verzeichnis?
Jordanis
Unregistrierter




Beitrag Jordanis Unregistrierter 20:16:50 24.01.2011   Titel:              Zitieren

Zitat:
Also entweder ist ein Fehler im Programm selbst was ich mir allerdings bei einem Tutorial nicht vorstellen möchte oder es liegt an dem folgenden Fehler...

Codeblocks couldnt parse wxs file because wxsmith is disabled...

Nach diesem Fehler hab ich mich jetzt schon durch etliche Foren gekämpft aber nichts gefunden. Es wäre schön wenn von euch vll einer Rat wüsste achja die Fehler post ich auch mal

||=== TICTACTOE, Debug ===|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp||In member function 'void Game::FieldPanel::OnPaint(wxPaintEvent&)':|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|21|error: 'wxPaintDC' was not declared in this scope|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|21|error: expected ';' before 'dc'|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|22|error: 'dc' was not declared in this scope|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|26|error: variable 'wxPen pen' has initializer but incomplete type|
C:\Users\Marcel\Desktop\Schule\Programmieren\WxWidgets\tictactoe\Game\FieldPanel.cpp|35|error: variable 'wxPen pen' has initializer but incomplete type|
||=== Build finished: 5 errors, 0 warnings ===|

Muss dazu sagen das ich noch nicht allzuviel Erfahrung mit wxwidgets habe da wir das Thema gerade begonnen haben. Aber auf diesen Fehler weiss unserer Programmierlehrer auch keinen Rat.

Mit freundlichen Grüßen
Tollmer

Hab mit wxDevC++ die gleiche Fehlermeldungen gehabt.
Folgende Nachtrag in FieldPanel.cpp hat das problem gelöscht.

.....
#include "../TurnEvent.hpp"
#include <wx/wx.h>
namespace Game
.......

Gruß
Jordan
nt0r
Mitglied

Benutzerprofil
Anmeldungsdatum: 08.09.2011
Beiträge: 20
Beitrag nt0r Mitglied 16:41:29 30.10.2011   Titel:              Zitieren

Ich hab n kleines Problem
Ih kompiliere zwar mit der 2.8er , aber mein minGW wirft folgendes raus
Zitat:

ld.exe||cannot find -lwx_msw_core-2.6|


Da ich aber keine Ahnung hab, warum er die 2.6er benutzen will , obwohl ich 2.8 eingestellt hab ist mir das fragwürdig.

Herzliche Grüße
nt0r


PS: C++0x weg hilft vorallem bei "strdup" einiges ;)

EDIT: Hat sich... mehr oder weniger... erledigt. Hab einfach neues Projekt mit 2.8 gemacht und alles reingezogen.

_________________
A..a..aber ich hab doch nur was ganz kleines geändert.


Zuletzt bearbeitet von nt0r am 13:44:43 02.11.2011, insgesamt 2-mal bearbeitet
C/C++ Forum :: Die Artikel ::  wxWidgets Tutorial Part II: Spiel mit mir   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können keine Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info, www.c-sar.de, www.c-plusplus.net und www.baeckmann.de enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.