# Thread per Button starten



## Java xyrse123 (20. Feb 2018)

Hallo,
ich habe eine Klasse GameThread, wo ein Ball bewegt wird und Tastaturabfragen mit einem KeyListener gemacht werden. Wenn ich jetzt den gamethread im Konstruktor von ButtonEreignisse aufrufe, funktioniert alles richtig, aber wenn ich den Thread in der ActionPerformed Methode(also bei Buttonklick starten) bewegt sich nur der Ball und auf Tastaturdrücke wird nicht mehr reagiert.

Schonmal danke im Vorraus.


```
class ButtonEreignisse extends JPanel implements ActionListener { // ButtonEreignisse
        JButton button1 = new JButton("Pause");
        JButton button2 = new JButton("Start Computer");
        JButton button3 = new JButton("Start ");
        JButton button4 = new JButton("Beenden");
       
        ButtonEreignisse() {       
            setPreferredSize(new Dimension(100, 100));
            setBackground(Color.YELLOW);
            setLayout(new FlowLayout());           
            setFocusable(true);
            gamethread = new GameThread(); // funktioiert
            gamethread.start();   
           
            button1.addActionListener(this);
            button2.addActionListener(this);
            button3.addActionListener(this);
            button4.addActionListener(this);
                                 
            add(button1);
            add(button2);
            add(button3);
            add(button4);
        }
        @Override
        public void actionPerformed(ActionEvent e) {
            if(button3==e.getSource()) {
                  // Hier soll der Thread gestartet werden, nur Ball bewegt sich              
            }
            button3.setEnabled(false);
        }
   
       
    }
```


----------



## Blender3D (20. Feb 2018)

Der KeyListener sendet nur an Steuerelemente die den Focus haben. Durch den Klick auf den Button erhält dieser den Fokus und das Fenster, dass den Fokus hatte verliert diesen. --> Keine Meldungen an das ursprüngliche  Fenster.


----------



## Java xyrse123 (20. Feb 2018)

OK, danke.
Ich habe jetzt versucht dem Gamepanel den Fokus zurückzugeben mit gamepanel.requestFocus(), aber die Schläger bewegen sich immer noch nicht


----------



## Blender3D (21. Feb 2018)

Du verwendest wahrscheinlich einen JFrame als Hauptfenster.
Gib diesen den KeyListener.
JFrame f;
f.setFocusable(true);
f.addKeyListerner( game );


----------



## Java xyrse123 (21. Feb 2018)

Mein Konstruktor von der Hauptklasse sieht jetzt so aus(Pong ist von JFrame abgeleitet, sonst hätte ich an anderer Stelle nicht repaint() aufrufen können), aber die Schläger lassen sich immer noch nicht bewegen:


```
public Pong() {                             
            setSize(800, 800);                               
            setLayout(new FlowLayout());                           
            add(buttons);
            add(gamepanel);
            setFocusable(true);
            addKeyListener(gamethread);
            setVisible(true);        
    }
```


----------



## Blender3D (21. Feb 2018)

Du addest Buttons in Deinen gamepanel. Wenn Du auf diese Klickst bekommen die den Fokus wie oben beschrieben.


----------



## Java xyrse123 (21. Feb 2018)

Also muss das gamepanel den Fokus haben. Aber wie bekommt das gamepanel den Fokus zurück wenn der Buttton gedrückt wurde?


----------



## Blender3D (23. Feb 2018)

```
import javax.swing.JFrame;

public class start {
    public static void main(String[] args) {
        JFrame f = new JFrame();
        GamePanel game = new GamePanel(500, 500);
        f.getContentPane().add(game);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setResizable(false);
        f.setTitle("KeyListener");
        f.setVisible(true);
        game.startGame();
    }
}
```


```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;

public class Racket {
    public static enum DIRECTION {
        LEFT, RIGHT, UP, DOWN
    };

    private float x = 0;
    private float y = 0;
    private int width = 0;
    private int height = 0;
    private float speed = 1;
    private Color color = Color.RED;

    public Racket(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public void draw(Graphics g) {
        Color old = g.getColor();
        g.setColor(color);
        g.fillRect((int) x, (int) y, width, height);
        g.setColor(old);
    }

    public Rectangle getColissonRect() {
        return new Rectangle((int) x, (int) y, width, height);
    }

    public int getHeight() {
        return height;
    }

    public Point getPosition() {
        return new Point((int) x, (int) y);
    }

    public float getSpeed() {
        return speed;
    }

    public int getWidth() {
        return width;
    }

    public void move(DIRECTION dir) {
        switch (dir) {
        case DOWN:
            y += speed;
            break;
        case LEFT:
            x -= speed;
            break;
        case RIGHT:
            x += speed;
            break;
        case UP:
            y -= speed;
            break;
        }
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public void setPosition(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void setSpeed(float speed) {
        this.speed = speed;
    }

}
```


```
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;

import javax.swing.JButton;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class GamePanel extends JPanel implements ActionListener, Runnable, KeyListener {
    private JButton left = new JButton("left");
    private JButton right = new JButton("right");
    private final GraphicsConfiguration gfxConf = GraphicsEnvironment.getLocalGraphicsEnvironment()
            .getDefaultScreenDevice().getDefaultConfiguration(); // used to create image for drawing
    private BufferedImage imageBuffer = null; // used to draw graphics
    private boolean running = false; // @see running
    private Thread animator = null; // thread for game ticks
    private Racket racket = new Racket(50, 15);

    public GamePanel(int width, int height) {
        setPreferredSize(new Dimension(width, height));
        add(left);
        add(right);
        right.addActionListener(this);
        left.addActionListener(this);
        racket.setPosition((width - racket.getWidth()) / 2, height - racket.getHeight());
        racket.setSpeed(2.5f);
        left.addKeyListener(this);
        right.addKeyListener(this);
        addKeyListener(this);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); // TODO
        if (imageBuffer == null || imageBuffer.getWidth() != getWidth() || imageBuffer.getHeight() != getHeight()) {
            imageBuffer = gfxConf.createCompatibleImage(getWidth(), getHeight());
        }
        if (imageBuffer != null)
            g.drawImage(imageBuffer, 0, 0, this);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Object src = e.getSource();
        if (src == left)
            racket.move(Racket.DIRECTION.LEFT);
        if (src == right)
            racket.move(Racket.DIRECTION.RIGHT);
        repaint();
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_Y)
            racket.move(Racket.DIRECTION.LEFT);
        if (e.getKeyCode() == KeyEvent.VK_X)
            racket.move(Racket.DIRECTION.RIGHT);
        repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void run() {
        while (running) { // false -> stops game
            try {

                updateGraphics(); // draw graphics
                Thread.sleep(5); // 1000 / 5 update game every 200 millisecond
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void startGame() {
        stopGame();
        while (animator != null && animator.isAlive())
            ;
        animator = new Thread(this);
        running = true;
        animator.start();

    }

    public void stopGame() {
        running = false;
    }

    public void updateGraphics() {
        if (imageBuffer != null) {
            Graphics g = imageBuffer.createGraphics();
            g.setColor(Color.black);
            g.fillRect(0, 0, getWidth(), getHeight());
            racket.draw(g);
        }
        repaint();
    }

}
```
Hier ein Beispiel wie Du es hinbekommst. Ein Schläger wird mittels der Tasten 'y' und 'x' oder mittels 2 Buttons bewegt.


----------



## Java xyrse123 (23. Feb 2018)

Ok, danke. Ich habe mir gerade eine kleine Testklasse geschrieben um es besser zuverstehen.
 Bei mir sind Buttons und die KeyEvents auf bei unterschiedlichen Panels hinzugefügt, bei dir sind die KeyEvents und ButtonEreignisse ja auf einem Panel. Musst du dewegen nicht den Fokus mit requestFokus() ändern?

Bei diesem kleinen Beispiel geht es nur mit requestFokus():

```
public class FokusTest implements KeyListener {
    Buttonereignis b = new Buttonereignis();
    JFrame f = new JFrame();
 
    FokusTest() {
     
        f.setSize(300,300);
        f.setLayout(new FlowLayout());
        f.add(b);
        f.setFocusable(true);
        f.setVisible(true);
        f.addKeyListener(this);
     
 
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) {
            System.out.println("W Taste gedrüctk"); 
            }
     
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // TODO Auto-generated method stub
     
    }

    @Override
    public void keyTyped(KeyEvent e) {
        // TODO Auto-generated method stub
     
    }
 
    class Buttonereignis extends JPanel implements ActionListener{
        JButton button = new JButton("Fokus");
     
        Buttonereignis() {
        setPreferredSize(new Dimension(100,100))    ;
        setBackground(Color.YELLOW);
        button.addActionListener(this);
        add(button);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if(button==e.getSource()) {
                System.out.println("Ich habe Fokus");
                f.requestFocus(); // Fokuswechsel
            System.out.println("Fokus zum Frame");
}
         
        }
    }
         
    public static void main(String[] args) {
        new FokusTest();
    }
}
```


----------



## Blender3D (23. Feb 2018)

Java xyrse123 hat gesagt.:


> Ok, danke. Ich habe mir gerade eine kleine Testklasse geschrieben um es besser zuverstehen.
> Bei mir sind Buttons und die KeyEvents auf bei unterschiedlichen Panels hinzugefügt, bei dir sind die KeyEvents und ButtonEreignisse ja auf einem Panel. Musst du dewegen nicht den Fokus mit requestFokus() ändern


Welche Klasse ( oder auch mehrere Klassen ) die Events verarbeitet spielt da keine Rolle.


Blender3D hat gesagt.:


> left.addKeyListener(this);
> right.addKeyListener(this);
> addKeyListener(this);


Bei meinem Beispiel habe ich die zwei Buttons und den GamePanel als Listener eingetragen. Das bedeutet, wenn man auf einen Button klickt erhält dieser zwar den Focus. Da er aber auch als KeyListener registriert ist werden die KeyEvents trotzdem verarbeitet.
Wenn du so etwas wie ein Spiel machen möchtest. Solltest Du nur einen JPanel verwenden. Alle grafischen Ausgaben werden in ein Image gezeichnet und das wird dann als Ganzes ausgegeben. (Siehe obigen Code).
Außerdem ist es keine gute Idee einen JFrame in ein Klasse zu packen. Der JFrame sollte die benötigen Klassen beinhalten und nicht umgekehrt.


----------



## Java xyrse123 (24. Feb 2018)

OK, danke. Ich habe bisher immer mehrere Panels genommen, also für Buttons und Spielfeld damit ich es besser anordnen kann.
Was meinst du mit JFrame in eine Klasse packen?
Achso, nochmal zu deinem Spiel, mir wurde gesagt das man statt Threads besser Timer verwendet.


----------

