Niedziałający KeyListener

0

Witam, robię symulator samochodu i chciałbym, aby po wciśnięciu klawisza "W" zwiększała się prędkość, lecz nic się nie dzieje... Mógłby ktoś doradzić?

import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.Color;

@SuppressWarnings("serial")
public class CarSimulator extends JPanel {
	int predkosc;
	int obroty;
	int bieg;
	boolean silnikOdpalony = false;
	Timer timer;
	int delay = 33;
	private JTextField txtPredkosc;
	private JTextField txtBieg;
	private JTextField txtObroty;

	public CarSimulator() {
		setBackground(Color.LIGHT_GRAY);
		setLayout(null);
		JPanel panel = new JPanel();
        add(panel);
		panel.setLayout(null);
		panel.addKeyListener(new SpeedListener());
		
		JLabel lblPredkosc = new JLabel("Predkosc:");
		lblPredkosc.setHorizontalAlignment(SwingConstants.RIGHT);
		lblPredkosc.setBounds(217, 29, 68, 14);
		add(lblPredkosc);
		
		JLabel lblBieg = new JLabel("Bieg:");
		lblBieg.setHorizontalAlignment(SwingConstants.RIGHT);
		lblBieg.setBounds(217, 60, 68, 14);
		add(lblBieg);
		
		JLabel lblObroty = new JLabel("Obroty:");
		lblObroty.setHorizontalAlignment(SwingConstants.RIGHT);
		lblObroty.setBounds(217, 91, 68, 14);
		add(lblObroty);
		
		JButton btnStart = new JButton("START");
		btnStart.setBounds(232, 183, 135, 70);
		add(btnStart);
		
		txtPredkosc = new JTextField();
		txtPredkosc.setText("0");
		txtPredkosc.setHorizontalAlignment(SwingConstants.CENTER);
		txtPredkosc.setColumns(10);
		txtPredkosc.setBounds(297, 26, 86, 20);
		txtPredkosc.setEditable(false);
		add(txtPredkosc);
		
		
		txtBieg = new JTextField();
		txtBieg.setText("N");
		txtBieg.setHorizontalAlignment(SwingConstants.CENTER);
		txtBieg.setColumns(10);
		txtBieg.setBounds(297, 57, 86, 20);
		txtBieg.setEditable(false);
		add(txtBieg);
		
		txtObroty = new JTextField();
		txtObroty.setText("0");
		txtObroty.setHorizontalAlignment(SwingConstants.CENTER);
		txtObroty.setColumns(10);
		txtObroty.setBounds(297, 88, 86, 20);
		txtObroty.setEditable(false);
		add(txtObroty);

	}
	
	public class SpeedListener implements KeyListener {
		@Override
		public void keyPressed(KeyEvent e) {
			if (e.getKeyCode() == KeyEvent.VK_W) {
				setPredkosc(1);
				txtPredkosc.setText(Integer.toString(getPredkosc()));
			}
		}

		@Override
		public void keyReleased(KeyEvent e) {
			if(e.getKeyCode() == KeyEvent.VK_W) {
				setPredkosc(-1);
				txtPredkosc.setText(Integer.toString(getPredkosc()));
			}
		}

		@Override
		public void keyTyped(KeyEvent arg0) {
			// TODO Auto-generated method stub

		}
	}

	public void setPredkosc(int predkosc) {
		this.predkosc += predkosc;
	}

	public int getPredkosc() {
		return predkosc;
	}
}

0

Ja to się na takich cudach to zbytnio nie znam ale... Uruchamiałeś to w debugu? Postaw breakpointa na wysokości linijki if (e.getKeyCode() == KeyEvent.VK_W) { i zobacz czy po kliknięciu w klawisz wpada Ci tutaj. Potem sprawdź co zwraca Ci e.getKeyCode() czy to na pewno jest ten klawisz który oczekujesz... Na końcu sprawdź jeszcze czy ten warunek e.getKeyCode() == KeyEvent.VK_W zwraca oczekiwaną wartość. Najlepiej zrobić tak że w debugu zaznacz sobie ten fragment kodu, kliknij PPM i wybierz Evaluate Expression. Potem Kliknij evaluate i powinnieś zobaczyć wynik. Jeśli wcisnąłeś W to powinno być true. Tutaj masz więcej na ten temat

A tak poza tym to ten kod wydaje mi się być trochę bezsensu...
Masz KeyListenera który ma 2 metody zaimplementowane:

  @Override
        public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_W) {
                setPredkosc(1);
                txtPredkosc.setText(Integer.toString(getPredkosc()));
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {
            if(e.getKeyCode() == KeyEvent.VK_W) {
                setPredkosc(-1);
                txtPredkosc.setText(Integer.toString(getPredkosc()));
            }
        }

Jeśli dobrze rozumiem to przyciśnięcie W spowoduje setPredkosc(1); natomiast puszczenie klawisza wywołuje setPredkosc(-1); czyli tak naprawdę nic się nie zmienia. To nie będzie działało tak że jak będziesz trzymał to będzie cały czas +1 +1 +1 +1 +1 tylko raz zrobi +1 a za chwile jak puścisz to -1.

Kolejna sprawa że nazywanie zmiennej setPredkosc wskazuje na to że będziesz prędkość ustawiał na wartość którą przekażesz czyli setPredkosc(1); spowoduje ustawienie prędkości = 1 a tym czasem jak się spojrzy na implementację tej metody to jest niespodzianka:

    public void setPredkosc(int predkosc) {
        this.predkosc += predkosc;
    }

Nie idź tą drogą :O

Ps. Zmienne w klasie (prędkośc, obroty itd itd) ustaw na private.

0

Z tego co pamietam, żeby swingowy JComponent rejestrował eventy klawiatury, to musi być focused. Sprawdź sobie, czy faktycznie twój komponent ma ten focus (są od tego metody w stylu isFocused

0
Tyvrel napisał(a):

Z tego co pamietam, żeby swingowy JComponent rejestrował eventy klawiatury, to musi być focused. Sprawdź sobie, czy faktycznie twój komponent ma ten focus (są od tego metody w stylu isFocused

Mimo tego, że dodałem na końcu kostruktora panel.requestFocus(), to i tak nic nie daje. Mógłby ktoś coś doradzić? :/

0

Masz w kodzie dwa obiekty typu JPanel, na jednym z nich umieszczasz wszystkie komponenty, do drugiego podpinasz KeyListenera, Usuń jeden z tych obiektów.
A konkretnie, to zamień

JPanel panel = new JPanel();
add(panel);
panel.setLayout(null);
panel.addKeyListener(new SpeedListener());

na

addKeyListener(new SpeedListener());
0
bogdans napisał(a):

Masz w kodzie dwa obiekty typu JPanel, na jednym z nich umieszczasz wszystkie komponenty, do drugiego podpinasz KeyListenera, Usuń jeden z tych obiektów.
A konkretnie, to zamień

JPanel panel = new JPanel();
add(panel);
panel.setLayout(null);
panel.addKeyListener(new SpeedListener());

na

addKeyListener(new SpeedListener());

Po tak długim czasie, wracam do tego, lecz wciąż to nie działa. Pomimo usunięcia tego panela, wciąż nie przyśpiesza.

0
leicer131 napisał(a):
Tyvrel napisał(a):

Z tego co pamietam, żeby swingowy JComponent rejestrował eventy klawiatury, to musi być focused. Sprawdź sobie, czy faktycznie twój komponent ma ten focus (są od tego metody w stylu isFocused

Mimo tego, że dodałem na końcu kostruktora panel.requestFocus(), to i tak nic nie daje. Mógłby ktoś coś doradzić? :/
To musi być dodane po pokazaniu JFrame.

0
Krwawy Kaczor napisał(a):
leicer131 napisał(a):
Tyvrel napisał(a):

Z tego co pamietam, żeby swingowy JComponent rejestrował eventy klawiatury, to musi być focused. Sprawdź sobie, czy faktycznie twój komponent ma ten focus (są od tego metody w stylu isFocused

Mimo tego, że dodałem na końcu kostruktora panel.requestFocus(), to i tak nic nie daje. Mógłby ktoś coś doradzić? :/
To musi być dodane po pokazaniu JFrame.

Czyli gdzie powinienem to wklepać?

0

Czyli gdzie powinienem to wklepać?
Po metodzie jframe.setVisible(true);

0
Krwawy Kaczor napisał(a):

Czyli gdzie powinienem to wklepać?
Po metodzie jframe.setVisible(true);

public static void main(String[] args) {
		JFrame frame = new JFrame("Car Simulatori");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(new SamSymulator());
		frame.setSize(new Dimension(600,400));
		frame.setVisible(true);
		frame.getContentPane().requestFocus();
	}

Wciąż to samo, nic sie nie dzieje, po wcisnieciu klawisza W.

0
leicer131 napisał(a):
Krwawy Kaczor napisał(a):

Czyli gdzie powinienem to wklepać?
Po metodzie jframe.setVisible(true);

public static void main(String[] args) {
		JFrame frame = new JFrame("Car Simulatori");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(new SamSymulator());
		frame.setSize(new Dimension(600,400));
		frame.setVisible(true);
		frame.getContentPane().requestFocus();
	}

Wciąż to samo, nic sie nie dzieje, po wcisnieciu klawisza W.

A poprawiłeś wszystko, na co inni zwrócili Ci uwagę?
Dodatkowo, skoro ustawiasz listener na panelu to kliknięcie na przycisk lub pole textowe powoduje, że już Ci ten kod nie zadziała bo panel straci focus i na nowo już go nie odzyska

0
Krwawy Kaczor napisał(a):

A poprawiłeś wszystko, na co inni zwrócili Ci uwagę?
Dodatkowo, skoro ustawiasz listener na panelu to kliknięcie na przycisk lub pole textowe powoduje, że już Ci ten kod nie zadziała bo panel straci focus i na nowo już go nie odzyska

Tak, wszystko zostało poprawione, zmieniłem już koncepcje, po prostu wszystko opiera się na przycisku START, który trzeba nacisnąć, aby samochód odpalił, dzięki temu ma już focus i można bawić sie klawiszami.

Teraz mam inny problem. Chciałbym, aby sytuacja wyglądała tak: Gdy naciskam W - samochód zyskuje obroty, gdy jest wrzucony bieg, samochód przyśpiesza - Tą funkcję posiadam. Gdy PUSZCZAM klawisz W, to chciałbym aby te obroty malały, co za tym idzie również prędkość. Wiem, że trzeba zastosować tu Thread.sleep(n), gdzie n to ms(1000 = 1 sekunda), ale gdy posiadam taki kod:

		public void keyReleased(KeyEvent e) {
			if (e.getKeyCode() == KeyEvent.VK_W) {
				while (obroty > 10) {
					try {
						obroty--;
						txtObroty.setText(Integer.toString(getObroty()));
						Thread.sleep(100);
					} catch (InterruptedException e1) {}
				}
			}
		}

To wtedy obroty nie aktualizują się na bieżąco, lecz program czeka, aż obroty spadną do 10, dopiero wtedy wyświetla, że obroty to 10 na ekranie. Stąd moje pytanie, dlaczego tak się dzieje?

0
leicer131 napisał(a):

To wtedy obroty nie aktualizują się na bieżąco, lecz program czeka, aż obroty spadną do 10, dopiero wtedy wyświetla, że obroty to 10 na ekranie. Stąd moje pytanie, dlaczego tak się dzieje?

Aby obroty miały szansę się odświeżyć metoda keyReleased() musi się zakończyć. U Ciebie natomiast jest w tej metodzie pętla i usypianie głównego wątku aplikacji dlatego odświeżenie stanu obrotów jest wykonywane dopiero gdy spadną poniżej 10.

0
Krwawy Kaczor napisał(a):
leicer131 napisał(a):

To wtedy obroty nie aktualizują się na bieżąco, lecz program czeka, aż obroty spadną do 10, dopiero wtedy wyświetla, że obroty to 10 na ekranie. Stąd moje pytanie, dlaczego tak się dzieje?

Aby obroty miały szansę się odświeżyć metoda keyReleased() musi się zakończyć. U Ciebie natomiast jest w tej metodzie pętla i usypianie głównego wątku aplikacji dlatego odświeżenie stanu obrotów jest wykonywane dopiero gdy spadną poniżej 10.

Masz jakiś fajny pomysł rozwiązania?

1 użytkowników online, w tym zalogowanych: 0, gości: 1