elitepvpers

elitepvpers (https://www.elitepvpers.com/forum/)
-   Java (https://www.elitepvpers.com/forum/java/)
-   -   Eine sich ändernde Variable holen (https://www.elitepvpers.com/forum/java/4090649-eine-sich-ndernde-variable-holen.html)

exceble 06/21/2016 13:52

Eine sich ändernde Variable holen
 
Nabend Dudes,

ich habe einen KeyListener für ein jTextField in der Klasse Game und möchte nun immer das aktuelle Wort, was gerade angezeigt wird, bei einem KeyRelease ausgeben. Um es mal simpel zu veranschaulichen (unwichtigen Code gelöscht):

Game.java:
Code:

public class Game extends JPanel{
    public String str = "boo";

    public void paintComponent(Graphics g) {

        if (xPos >= this.getWidth()) {
                str = declareWord();  // Setzt ein zufälliges Wort (!= "boo")
        }

    }
}

KeyEventListener.java:
Code:


public class KeyEventListener implements KeyListener {
    Game test = new Game();
    String word;

    public void keyReleased(KeyEvent e) {
        getKey(e);
    }

    private void getKey(KeyEvent released) {
        word = test.str;  // Bestimmt nicht die beste Lösung (Ist ja auch falsch)
        System.out.println(word);
    }
}

Mein Problem ist jetzt, dass egal wann ich eine Taste drücke (bzw. loslasse), mir immer nur "boo" ausgegeben wird. Also nicht das aktuelle Wort, was in der Paint-Komponente schon längst geändert wurde. Kann auch sein, dass es da eine ziemlich triviale Lösung zu gibt. Nur leider bin ich noch nicht drauf gekommen. Würde mich über einen kleinen Denkantoß freuen.

Mysthik 06/21/2016 16:12

Aus dem Beispiel werden einige Dinge nicht ganz klar.

Die paintComponent wird unteranderem dann aufgerufen, wenn:
  1. Die GUI initialisiert UND angezeigt wird
  2. ein update der Oberfläche aufgerufen wird
  3. die parent Komponente aktuallisiert wird
  4. Bei bestimmten events (resize usw.)

Wenn du aber jedesmal new Game().str aufrufst wird jedes mal ein neues Game-Object erzeugt. Bei dem erzeugen Object wird die paintComponent aber niemals aufgerufen also wird der String auch nicht gesetzt.

exceble 06/21/2016 16:23

Quote:

Originally Posted by Mysthik (Post 34709560)
Aus dem Beispiel werden einige Dinge nicht ganz klar.

Die paintComponent wird unteranderem dann aufgerufen, wenn:
  1. Die GUI initialisiert UND angezeigt wird
  2. ein update der Oberfläche aufgerufen wird
  3. die parent Komponente aktuallisiert wird
  4. Bei bestimmten events (resize usw.)

Wenn du aber jedesmal new Game().str aufrufst wird jedes mal ein neues Game-Object erzeugt. Bei dem erzeugen Object wird die paintComponent aber niemals aufgerufen also wird der String auch nicht gesetzt.

Die paintComponent wird aufgerufen und macht das was es soll, das ist garnicht das Problem. Ja auch wenn ich vorher ein Game-Objekt erstelle, macht das kein Unterschied, ich kriege weiterhin nur "boo" zurück. Ich will nur die aktuelle Variabel str, welche in der paintComponent geändert wird, aus der Game-Klasse kriegen. Aber er gibt mir die ganze Zeit str aus der Deklaration. Also "boo".

Zur Erläuterung: declareWord() ist eine Methode, die ein String zurück liefert, welcher vorher zufällig aus einer Liste gewählt wurde, welche nicht "boo"enthält.

.Scy 06/21/2016 18:25

also was ist das ziel? du möchtest wenn der benutzer in dem TextField fertig getippt hat was auch immer dadrinnen steht auswerten?

bei keyReleased bekommst du nach jedem einzelnen char schon ne rückmeldung, eher suboptimal mMn, kann man aber mit arbeiten.

zeig uns doch erstmal deinen Konstruktor von Game.

Zudem musst du um dein ziel zu erreichen nichts weiter als den konstruktor von Game anpassen, du brauchst die paintComponent nicht Overriden(was in deinem stück code auch fehlt).

exceble 06/21/2016 21:14

Quote:

Originally Posted by .Scy (Post 34710323)
(was in deinem stück code auch fehlt).

Quote:

Originally Posted by exceble (Post 34708726)
Um es mal simpel zu veranschaulichen (unwichtigen Code gelöscht)

Ich habe alles nötige oben angegeben. Ich versuch mich jetzt nochmal klar auszudrücken. Die String-Variabel str wird ständig geändert. Wenn ich vom KeyListener die Variabel holen will, bekomme ich aber nur "boo" zurück, wie ich str auch in der Game-Klasse initalisiert habe. Es hat absolut nichts mit der TextBox zu tun oder ob es jetzt nur released oder pressed ist. Es geht lediglich darum, dass sich die Variabel ändert und ich per Tastendruck (völlig irrelevant - aber dann wird der Code aufgerufen) mir die aktuelle Variabel str holen möchte.

.Scy 06/21/2016 23:23

wie schon gesagt, ist dein painComponent Schwachsinn. zu der zeit wo du das ding initialisierst hat es keine Größe. die Größe bekommt es erst vom frame, sobald es visible ist, dann zeichnest du zwar, aber nur ein mal und danach nie wieder außer du erzwingst einen repaint, was du in dem gezeigten code nicht tust. Zudem hast du eine Bedingung drinnen, welche man mit dem code nichtmal nachvollziehen kann.

natürlich falsch:
Code:

public class KeyEventListener implements KeyListener {
    String word;

    public void keyReleased(KeyEvent e) {
        getKey(e);
    }

    private void getKey(KeyEvent released) {
        word = new Game().str;
        System.out.println(word);
    }
}

Code:

public static void main(){
    Game test = new Game();
//Irgend ein frame aufbauen
//Mit deinem textfeld
textfeld.addKeyListener(new KeyListener() {
                        String word;
                  @ Override
                        public void keyTyped(KeyEvent e) {
                                // TODO Auto-generated method stub
                               
                        }
                       
                  @ Override
                        public void keyReleased(KeyEvent e) {
                                getKey(e);
                               
                        }
                       
                  @ Override
                        public void keyPressed(KeyEvent e) {
                                // TODO Auto-generated method stub
                               
                        }
                        private void getKey(KeyEvent released) {
        word = test.str;
        System.out.println(word);
    }
                });

}

du kannst nicht einfach beliebig häufig new Game().str rufen. du hast deinem Str fest den wert "boo" gegeben und du rufst eben kein paintComponent auf, da du ja nichtmal weißt, wann java es für nötig hält paintComponent aufzurufen. zudem finde ich es mehr als suboptimal abhängig von einer position ein wort auszuwählen.

exceble 06/21/2016 23:42

Quote:

Originally Posted by .Scy (Post 34712018)
wie schon gesagt, ist dein painComponent Schwachsinn. zu der zeit wo du das ding initialisierst hat es keine Größe. die Größe bekommt es erst vom frame, sobald es visible ist, dann zeichnest du zwar, aber nur ein mal und danach nie wieder außer du erzwingst einen repaint, was du in dem gezeigten code nicht tust. Zudem hast du eine Bedingung drinnen, welche man mit dem code nichtmal nachvollziehen kann.

natürlich falsch:
Code:

public class KeyEventListener implements KeyListener {
    String word;

    public void keyReleased(KeyEvent e) {
        getKey(e);
    }

    private void getKey(KeyEvent released) {
        word = new Game().str;
        System.out.println(word);
    }
}

Code:

public static void main(){
    Game test = new Game();
//Irgend ein frame aufbauen
//Mit deinem textfeld
textfeld.addKeyListener(new KeyListener() {
                        String word;
                  @ Override
                        public void keyTyped(KeyEvent e) {
                                // TODO Auto-generated method stub
                               
                        }
                       
                  @ Override
                        public void keyReleased(KeyEvent e) {
                                getKey(e);
                               
                        }
                       
                  @ Override
                        public void keyPressed(KeyEvent e) {
                                // TODO Auto-generated method stub
                               
                        }
                        private void getKey(KeyEvent released) {
        word = test.str;
        System.out.println(word);
    }
                });

}

du kannst nicht einfach beliebig häufig new Game().str rufen. du hast deinem Str fest den wert "boo" gegeben und du rufst eben kein paintComponent auf, da du ja nichtmal weißt, wann java es für nötig hält paintComponent aufzurufen. zudem finde ich es mehr als suboptimal abhängig von einer position ein wort auszuwählen.

Quote:

Originally Posted by exceble (Post 34709634)
Ja auch wenn ich vorher ein Game-Objekt erstelle, macht das kein Unterschied

Und wie auch bereits zwei mal erwähnt, habe ich unnötigen Code entfernt. Ich bin dir zwar dankbar, aber bitte lies dir doch alle Beiträge durch bevor du mir helfen möchtest.

Edit: Hab's mal geändert

.Scy 06/22/2016 09:14

du verstehst deinen code ja nichtmal, du erzeugst dir in deinem listener, was total schwachsinnig ist und was ich auch nicht gezeigt habe, weiterhin ein Game Objekt. Dieses zeichnet sich NIE! du hast es zwar, aber es liegt auf keinem frame.

bevor du hier weiter machst solltest du dir erstmal swing beibringen. du wirst immer boo heraus bekommen wenn du dein jpanel nicht in ein frame, welches visible ist, legst.

ich weiß nicht wo du dein frame erzeugst, aber dort MUSST du dein Game erzeugen UND Game deinem frame hinzufügen. so wie du es im moment zeigst ruft sich paintComponent nie auf, weil JPanel sich nur malt, wenn es vom frame dazu den Aufruf bekommt, oder du eben game.PaintComponent aufrufst, aber da du keinen gültigen Graphics hast wird das nicht klappen.

exceble 06/22/2016 09:27

Quote:

Originally Posted by .Scy (Post 34713176)
du verstehst deinen code ja nichtmal, du erzeugst dir in deinem listener, was total schwachsinnig ist und was ich auch nicht gezeigt habe, weiterhin ein Game Objekt. Dieses zeichnet sich NIE! du hast es zwar, aber es liegt auf keinem frame.

bevor du hier weiter machst solltest du dir erstmal swing beibringen. du wirst immer boo heraus bekommen wenn du dein jpanel nicht in ein frame, welches visible ist, legst.

ich weiß nicht wo du dein frame erzeugst, aber dort MUSST du dein Game erzeugen UND Game deinem frame hinzufügen. so wie du es im moment zeigst ruft sich paintComponent nie auf, weil JPanel sich nur malt, wenn es vom frame dazu den Aufruf bekommt, oder du eben game.PaintComponent aufrufst, aber da du keinen gültigen Graphics hast wird das nicht klappen.

Okay, tut mir Leid. Hatte versucht es so einfach wie möglich darzustellen, aber anscheinend greift das nur mehr Probleme auf. Den Listener habe ich erstellt, weil es mir so gesagt wurde. Dort wird noch einiger Code hinzukommen, weswegen ich den outsourcen sollte.

Hier mal den kompletten Quellcode:

Game.java (Spoiler):
Code:

package typewords.ui;

import typewords.data.DataException;
import typewords.data.WordInterface;
import typewords.data.WordManager;

import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.util.concurrent.ThreadLocalRandom;

public class Game extends JPanel{

    JFrame game = new JFrame("Typing-Words");

    public int points = 0, lives = 10;

    JPanel subPanel = new JPanel();
    JTextField jf = new JTextField("Hello", 42);
    JLabel jPoints = new JLabel("Points: " + points);
    JLabel jLives = new JLabel("Lives: " + lives);

    public String  str = "boo";

    private WordInterface wordProvider;
    int xPos = -50, yPos = 75, ms = 4;

    public Game() {
        wordProvider = new WordManager();
        game.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        game.setPreferredSize(new Dimension(600,300));
    }

    public void startGame() throws IOException {
        game.add(new Game());

        jPoints.setBackground(Color.GREEN);
        jLives.setBackground(Color.RED);
        jPoints.setOpaque(true);
        jLives.setOpaque(true);

        subPanel.add(jf, 0);
        subPanel.add(jPoints, 1);
        subPanel.add(jLives, 2);
        subPanel.setBorder(BorderFactory.createLineBorder(Color.black));
        game.getContentPane().add(BorderLayout.PAGE_END, subPanel);

        game.pack();
        game.setVisible(true);

        System.out.println(jf.getText());
        System.out.println(jPoints.getText());

        jf.addKeyListener(new KeyEventListener());
    }

      [MENTION=295804]Override[/MENTION]
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        g2.setFont(new Font("Times Roman", Font.PLAIN, 18));

        try { Thread.sleep(ms); } catch (InterruptedException e) { e.printStackTrace(); }
        xPos += 1;

        if (xPos >= this.getWidth()) {
            lives-=1;
            jLives.setText("Lives: " + lives);
            System.out.println(jLives.getText());

            xPos = -50;
            yPos = ThreadLocalRandom.current().nextInt(25, 240);
            try {
                str = wordProvider.declareWord();
            } catch (DataException e) {
                e.printStackTrace();
            }
        }

        g2.drawString(str, xPos, yPos);
        repaint();
    }
}


KeyEventListener.java (Spoiler):
Code:

package typewords.ui;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class KeyEventListener implements KeyListener {
    String word;
    private Game game = new Game();

      [MENTION=295804]Override[/MENTION]
    public void keyTyped(KeyEvent e) { }
      [MENTION=295804]Override[/MENTION]
    public void keyPressed(KeyEvent e) { }


      [MENTION=295804]Override[/MENTION]
    public void keyReleased(KeyEvent e) {
        getKey(e);
    }


    private void getKey(KeyEvent released) {
        char k = released.getKeyChar();
        System.out.println(released.getKeyChar());
        word = game.str;

        System.out.println(word);

        if(word.charAt(0) == k) {System.out.println("First char released");}
        if(word.charAt(1) == k) {System.out.println("Second char released");}
    }
}


Habe in deinem Vorschlag übersehen, dass du das Game-Objekt in der Main-Methode erstellst. Meine Main-Methode ruft die startGame()-Methode der Game-Klasse auf. Ich weiß nicht so ganz, wie ich das jetzt umsetzen soll.

.Scy 06/22/2016 09:59

das erste problem ist, dass du bei startGame
Code:

game.add(new Game());
machst, dadurch hast du zwar ein game Objekt aber darauf hast du keinen zugriff, weil es anonym ist.
Code:

Game something = new Game();
game.add(something);

//viel zeug
//keylistener hinzufügen
jf.addKeyListener(new KeyListener(){
                        String word;
                  @ Override
                        public void keyTyped(KeyEvent e) {
                                // TODO Auto-generated method stub
                               
                        }
                       
                  @ Override
                        public void keyReleased(KeyEvent e) {
                                getKey(e);
                               
                        }
                       
                  @ Override
                        public void keyPressed(KeyEvent e) {
                                // TODO Auto-generated method stub
                               
                        }
                        private void getKey(KeyEvent released) {
        word = something.str;
        System.out.println(word);
    }
                });

den keyListener wirst du nicht auf diese weise häufiger verwenden, also baut man sich einen anonymen keyListener, in diesem kannst du dann auf something zugreifen.

listener würde man so oder so entweder als innere class oder direkt als anonyme class bauen, damit sie eben zugriff auf alles in der klasse haben. dein problem mit der extra class für den KeyListener ist, dass du dein Objekt von Game public setzen musst, dies kann man durch innere oder anonyme klassen umgehen.

du hast genau 1 Game-Objekt welches gezeichnet wird, dies liegt in deiner startGame, deswegen musst du auch auf das Objekt zugreifen und kein neues erstellen, weil die anderen nicht gezeichnet werden. hoffe soweit verständlich

exceble 06/22/2016 10:07

Quote:

Originally Posted by .Scy (Post 34713288)
das erste problem ist, dass du bei startGame
Code:

game.add(new Game());
machst, dadurch hast du zwar ein game Objekt aber darauf hast du keinen zugriff, weil es anonym ist.

den keyListener wirst du nicht auf diese weise häufiger verwenden, also baut man sich einen anonymen keyListener, in diesem kannst du dann auf something zugreifen.

listener würde man so oder so entweder als innere class oder direkt als anonyme class bauen, damit sie eben zugriff auf alles in der klasse haben. dein problem mit der extra class für den KeyListener ist, dass du dein Objekt von Game public setzen musst, dies kann man durch innere oder anonyme klassen umgehen.

du hast genau 1 Game-Objekt welches gezeichnet wird, dies liegt in deiner startGame, deswegen musst du auch auf das Objekt zugreifen und kein neues erstellen, weil die anderen nicht gezeichnet werden. hoffe soweit verständlich

Wunderbar, Problem gelöst. Ich danke dir vielmals für deine Hilfe und vorallem deine Geduld! Leider habe ich grad kein e*gold rumfliegen, um meine Dankbarkeit auszudrücken. :P

Cheers

Devsome 06/23/2016 10:57

#closed on request
problem solved


All times are GMT +2. The time now is 14:28.

Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.