# Galgenmännchen



## emka81 (13. Mrz 2010)

Hallo Leute,

wollte mich mal an das berühmte Galgenmännchen rannschmeißen, funktioniert auch halbwegs, aber dennoch hat sich ein Fehler eingeschlichen den ich nicht finde !! Es sollte bei einem Fehler ein Image geladen werden mit einer Nummer 0-4 (0 ist der Hügel, 1 ist der Mast etc. ) Auch das funktioniert, aber wenn jemand was falsches eingibt und danach wieder was richtiges, verschwindet das Bild von meinem Panel. Macht man danach wieder einen Fehler kommt zwar das "richtige" Fehlerbild, aber beim nächsten Mal richtig raten verschwindet es schon wieder....

Ich hoffe ihr findet daran etwas, was darauf hinweisen könnte warum das bild verschwindet. 


```
package scramble;


import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Main  {

    /**
     * @param args the command line arguments
     */

    static String text = "Donauschifffahrt";
    static  char[] wort = new char[text.length()]; //Wort zerlegt in ein Array (Platzhalter)
    static  char[] gesWort = new char[text.length()]; //Wort mit Unterstriche "füttern" nur Anfangs und Endbuchstabe sollten erscheinen
    static  int[] stellen = new int[text.length()]; //zum testen an welcher Stelle ein Buchstabe ist (mittels indexOf)
    static  Image[] bilder = new Image[5]; // Array der Hangman BIlder
    static  int versuche = 0; // Anzahl der Versuche
    static  char[] rate; // Der geratene Buchstabe
    




    public static void main(String[] args) throws Exception {
        // TODO code application logic here

       Fenster fen =new Fenster();
        
       final JLabel label = fen.getWort();
       final JTextField buchstabe = fen.getEingabe();
       final JButton pruefung = fen.getBOk();
       final JPanel bild = fen.getpBild();

       text.getChars(0, text.length(), wort, 0); //Hier wird nun der String in das Array verfrachtet

       // Bilder werden in Array verfrachtet
        for (int i = 0; i < bilder.length; i++) {
            BufferedImage image = ImageIO.read(new File("bilder/bild" +i +".jpg"));
            bilder[i] = image;
        }

       System.out.println("Länge vom Text " +text.length());
        
         //Das Wort "verschlüsselt" ausgeben
           for (int i = 0; i < wort.length; i++) {
            if (i == 0 || i == wort.length-1 || i == wort[i]) {
              gesWort[i] = wort[i];
            }else{
             gesWort[i] = '_';
            }
        }
       
        label.setText(new String(gesWort)); // Im Label das Wort als String hineinschreiben

        // Action Lsitener hinzufügen
             pruefung.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent e) {
                    
                    rate = buchstabe.getText().toCharArray();
                    teste(rate, label,bild); //mitschicken vom Label und Panel und Ratebuchstaben
                }


            });

 
       
    }

    public static void teste(char[] buchi, JLabel label, JPanel bild){
        //
        //
        System.out.println("Anfang vom teste Methode " +buchi[0]);
        int vorhanden = text.indexOf(rate[0]);
        System.out.println("Der Buchstabe an Stelle " +vorhanden +" vorhanden");

           try{
                
                Graphics tmp = (Graphics2D) bild.getGraphics();

                if (vorhanden == -1){

                   
                tmp.drawImage(bilder[versuche], 0 , 0,bild.getWidth(),bild.getHeight(), bild);
                versuche++;
                } else {
                    if (versuche > 0)
                    tmp.drawImage(bilder[versuche-1], 0 , 0,bild.getWidth(),bild.getHeight(), bild);
                // Geratenen Buchstaben einsetzen und String umwandeln
                    for (int i = 0; i < wort.length; i++)
                      {
                         if (buchi[0] == wort[i]) {
                         gesWort[i] = buchi[0];
                         }
                      }

            String gesWortString = new String(gesWort);
            label.setText(gesWortString);
            System.out.println( "Versuch Nr. " +versuche);
            System.out.println("Gültiger Versuch ");
            int i = gesWortString.indexOf('_');
            if (i == -1){
            System.out.println("Spiel gewonnen  ");
            }
           }              
            } catch (Exception e) {
                e.printStackTrace();
            }         
  
       if (versuche >= 5)
        System.out.println("Spiel zu Ende - VERLOREN " + " Versuch Nr." +versuche);
          
    } 
    }
```


----------



## Marco13 (13. Mrz 2010)

Auf einer Component "getGraphics" aufrufen ist fast immer falsch. Für diesen Fall könnte man das Zeichnen der Bilder ganz grob so machen:

```
class GalgenPanel extends JPanel
{
    private Image images[] = ... die bilder
    private int anzahlFehler = 0; // Dafür noch set/get-Methoden einbauen...

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        // Sinngemäß(!) so: (das könnte man eleganter machen, nur zur Vedeutlichung!!!)
        if (anzahlFehler == 1) 
        {
            g.drawImage(images[0], 0, 0, this);
        }
        if (anzahlFehler == 2) 
        {
            g.drawImage(images[0], 0, 0, this);
            g.drawImage(images[1], 0, 0, this);
        }
        ...
    }

}
```

Etwas pauschal, als "Daumenregel": ALLES, was gezeichnet werden soll, muss bei jedem Aufruf von paintComponent neu gezeichnet werden. Man darf NUR in der paintComponent (und NUR in das dort übergebene "Graphics") zeichnen.


----------



## emka81 (13. Mrz 2010)

vielen Dank einmal für die schnelle Antwort,

müsste ich dann in der teste Methode ein Objekt bilden mit der Klasse GalgenPanel und diese dann meinem "normalen" Panel zuweisen ? und nach einem Fehler die Methode .paintComponent(null); aufrufen ?

Muss gestehen, dass mir der Zusammenhang noch nicht ganz klar ist. Ich muss ja der paintComponent Methode ein Grafikobjekt mitschicken oder . 

Grüße MArtin


----------



## Marco13 (13. Mrz 2010)

Dieses GalgenPanel würde dort hinkommen, wo im Moment in der Klasse "Fenster" (wie auch immer die aussieht) das "bild"-Panel liegt. Ungefähr sowas wie

```
class Fenster extends JFrame
{
    // private JPanel bild; // Weg
    private GalgenPanel galgenPanel; // Hin

    private void baueGUI()
    {
        ...
        // Weg
        //bild = new JPanel();
        //somewhere.add(bild);

        // Hin
        galgenPanel = new GalgenPanel();
        somewhere.add(galgenPanel);
        ...
    }

    // public JPanel getpBild() { return bild; } // Weg

    public GalgenPanel getGalgenPanel() { return galgenPanel; } // Hin

}
```


Dann müssen in der main-Klasse, dort wo jetzt die Bilder geladen werden, diese Bilder noch ans GalgenPanel übergeben werden (die sind dann der "images[]"-Array in der GalgenPanel-Klasse). Dazu könnte es in der GalgenPanel eine Methode geben wie

```
public void setzeBilder(Image bilder[])
{
    this.images = bilder;
}
```

Wenn man dann falsch rät, macht man sowas wie

```
int alteAnzahlFehler= galgenPanel.getAnzahlFehler();
int neueAnzahlFehler = alteAnzahlFehler+1;
galgenPanel.setAnzahlFehler(neueAnzahlFehler);
galgenPanel.repaint();
```
Man ruft nicht paintComponent auf, sondern nur "repaint()" - das sorgt dafür, dass "so bald wie möglich" paintComponent ausgeführt wird, und der neue Zustand gezeichnet wird. Also je nachdem, wie die fehlerAnzahl ist, werden 0,1,2 oder 3 der Bilder gezeichnet, die oben ans GalgenPanel übergeben wurden.

Das könnte man ggf. alles noch anders (und schöner) strukturieren und so... das wichtigste ist eben, dass alles, was gezeichnet wird, von der paintComponent aus gezeichnet wird.


----------

