I'm working on an old game project called Lemmings, and the Principle Game Panel is working well and receiving the MouseEvents but not the KeyEvents, which is not very logic for me, so I copied down the Code of this file for you guys to see whats going on.
The GamePanel class extends JComponent SWING class
public class GameFrame {
private class GamePanel extends JComponent {
GamePanel(Dimension dim) {
setPreferredSize(dim);
//first version of the question was with the keyListner
/*addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
System.out.println(e.getKeyCode());
//nothing show up
}
});*/
//I tried using this, but it didn't work
//getInputMap().put(KeyStroke.getKeyStroke("A"), "action");
// this works cause we use the right inputMap not the one by default
getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("A"), "action");
getActionMap().put("action",new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("A is pressed");
//now it works
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
System.out.println(e.getPoint());
}
});
setVisible(true);
}
}
private JFrame window;
private GamePanel panel;
public GameFrame() {
window = new JFrame("Test");
window.setLocationRelativeTo(null);
panel = new GamePanel(new Dimension(400, 400));
window.setContentPane(panel);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
public static void main(String[] args) {
new GameFrame();
}
}
UPDATE WITH SOLUTION
I learned that JComponants are not focusable and so it doesn't receive KeyEvents so we have to use the Key Bindings method
I found out that every JComponent has three inputMaps referred to by WHEN_IN_FOCUSED_WINDOW, WHEN_FOCUSED, WHEN_ANCESTOR_OF_FOCUSED_COMPONENT and we have to make sure that we are using the right one for our work
for more informations look on How to use key Bindings and check the methods getInputMap() and getInputMap(int)
Key events are only dispatch to a focusable component.
By default a JPanel is not focusable so it does not receive key events.
If you are attempting to invoke some kind of Action based on a KeyEvent then you should be using Key Bindings, not a KeyListener. A key binding will allow you to listen for a KeyStroke even if the component doesn't have focus.
Read the section from the Swing tutorial on How to Use Key Bindings for more information and working examples.
the problem can be solved simply by adding a KeyListener to the JFrame in case we don't need to create Actions and stuff
this solution can only be possible if there are no other components focusable.
in the file GameFrame.java
in the function void init();
add
window.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed (KeyEvent e) {
super.keyPressed(e);
System.out.println("test "+e.getKeyChar());
}
});
Related
Currently stuck on how to create an executable jar file that would run in the background of my pc and detect if my mouse is down. I know JFrame is a one method of doing so, but that's visible on my screen, even though I set it to invisible it appears to disable it completely.
Here's my code so far, is there a another method I could use that isn't JFrame related?
public class MyFrame extends JFrame implements KeyListener {
MyFrame(){
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(500,500);
this.setLayout(null);
this.addKeyListener(this);
this.setVisible(true);
this.setAlwaysOnTop(true);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyChar() =='q'){
this.setVisible(false);
}
if(e.getKeyChar()=='l'){
this.setVisible(true);
}
}
}
You can download jNativeHook and hook the global listener to globalScreen.
you can use it as a normal swing listener.
Here is the link:
https://code.google.com/p/jnativehook/
By using this library you achieve a wide range of functions to control the mouse events!!
I had a problem while calling two mouse events, one into the other. I wanted to show a second frame (frame2) when the user clicks on a component (component1) from the first frame (frame1), then returns to the previous frame (frame1) if the component2 is clicked on. All this using one file.
This is what I wrote:
component1.addMouseListener(this on);
#Override
public void mouseClicked(MouseEvent e)
{
if(e.getSource() == component1)
{
frame1.dispose();
frame2.setVisible(true);
component2.addMouseListener(new MouseAdapter() {
public void mouseClicked() {
frame2.dispose();
frame1.setVisible(true);
}
});
}
}
The first event works, but not the second.
Thank you for answering.
Here is a fully functional example where there are 2 frames, each with a label that, when clicked, hides one frame and shows the other, done in Java 10. See if this works for you and explain how your code differs from this. Note that I only created 2 MouseListeners, one for each frame. I did not recreate the MouseListener in the other MouseListener's code. Also, I did not dispose the frame, which will likely cause problems. If I had disposed frame1, I would most likely have to create a new JFrame and assign it to the frame1 instance member.
Please note you have to click on the label itself, not somewhere else on the frame.
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class TwoFrames {
public static void main(String[] args) {
TwoFrames twoFrames = new TwoFrames();
twoFrames.start();
}
private void start() {
setupFrames();
}
JFrame frame1 = new JFrame("Frame 1"),
frame2 = new JFrame("Frame 2");
JLabel component1 = new JLabel("Click me 1"),
component2 = new JLabel("Click me 2");
private void setupFrames() {
frame1.getContentPane().add(component1);
frame2.getContentPane().add(component2);
component1.setOpaque(true);
component2.setOpaque(true);
component1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
frame1.setVisible(false);
frame2.setVisible(true);
}
});
component2.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
frame2.setVisible(false);
frame1.setVisible(true);
}
});
frame1.setSize(300, 300);
frame2.setSize(400, 400);
frame1.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame2.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
SwingUtilities.invokeLater(() -> frame1.setVisible(true));
}
}
The dispose() method actually destroys the window and so, frame1 should become null and you are most likely getting a null pointer exception.
Consider calling frame1.setVisible(false) and frame2.setVisible(false) instead of the dispose() method.
Also, you could consider using to separate mouse listener objects instead of adding a new mouse listener to component2 when component1 is clicked.
I am making KeyEvent Test program, but it doesn't work in Windows10.
this program works well in Windows7 and 8 version.. I don't know why..
KeyBoard Problem..? or others..?
class KeyFrame extends JFrame{
public KeyFrame(){
KeyTest t = new KeyTest();
setContentPane(t);
this.setSize(700, 700);
setSize(300,300);
setVisible(true);
t.requestFocus();
}
}
public class KeyTest extends JPanel{
JLabel la = new JLabel("Input");
public KeyTest(){
add(la);
this.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e){
String data = e.getKeyText(e.getKeyCode());
la.setText(data + "Pressed");
if(e.getKeyCode() == KeyEvent.VK_F1){
setBackground(Color.GREEN);
}
else if(e.getKeyChar() == '%'){
setBackground(Color.YELLOW);
}
}
});
}
public static void main(String[] ar){
new KeyFrame();
}
}
If you are adding KeyListener for JLabel.
Note:Some components aren't focusable like JLabel.
You can try that one.
Make sure the component's isFocusable method returns true. This state allows the component to receive the focus. For example, you can enable keyboard focus for a JLabel component by calling the setFocusable(true) method on the label.
I have a JFrame and a JPanel hierarchy inside it, i want to implement an inner panel that i can make it look "disabled"(while other panels dont change), that is, to cover it by a semi transparent gray layer and intercept all mouse and perhaps even keyboard events that are dispatched to this panel. ive been searching for a solution and didnt really find a good one yet.
The closest i got to a solution was when i used JRootPane, whenever i want it disabled i make its glasspane visible. the glasspane had been set to be opaque and with semi transparent background.
A simple example of my attempt :
public class Test extends JFrame {
private final JPanel jPanel;
public Test() {
jPanel = new JPanel();
final JButton jButton = new JButton("Hidden");
jButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("hidden is clicked!");
}
});
final JRootPane jRootPane = new JRootPane();
jPanel.add(jRootPane);
final JPanel glassPane = new JPanel();
final JButton jButton2 = new JButton();
jButton2.addActionListener(new ActionListener() {
private boolean visible = true;
#Override
public void actionPerformed(ActionEvent e) {
glassPane.setVisible(visible = !visible);
}
});
jPanel.add(jButton2);
jRootPane.getContentPane().add(new JScrollPane(jButton));
glassPane.setBackground(new Color(0.5f, 0.5f, 0.5f, 0.2f));
glassPane.setOpaque(true);
jRootPane.setGlassPane(glassPane);
glassPane.setVisible(true);
getContentPane().add(jPanel);
}
public static void main(String[] strings) {
final Test test = new Test();
test.pack();
test.setVisible(true);
}
}
But the problem is that even when the glass is visible on top of the content, it doesnt intercepts events from getting to the content as it should, as documented here.
In your test class your glasspane doesn't intercept events, because you didn't tell it to intercept events (intercepting events is not a default behavior).
In the documentation link, it says
The glass pane
The glass pane is useful when you want to be able to catch events or paint over an area that already contains one or more components. For example, you can deactivate mouse events for a multi-component region by having the glass pane intercept the events. Or you can display an image over multiple components using the glass pane.
You can intercept Mouse Events this way:
glassPane.addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
e.consume();
}
#Override
public void mousePressed(MouseEvent e)
{
e.consume();
}
});
You can intercept KeyBoard Events this way:
glassPane.setFocusable(true);
glassPane.addKeyListener(new KeyListener()
{
#Override
public void keyTyped(KeyEvent e)
{
e.consume();
}
#Override
public void keyReleased(KeyEvent e)
{
e.consume();
}
#Override
public void keyPressed(KeyEvent e)
{
e.consume();
}
});
Note: The JPanel has to be focasable to intercept the keyboard events.
Im making a game and Im having it so that when the user presses "I" in the game, the game panel is set to invisible while it adds the Inventory panel to the JFrame. Then when the user exits the Inventory it will remove the Inventory JPanel and then set back the game JPanel to visible.
Now this all sounds good, but whenever it removes the Inventory JPanel and goes back to the game JPanel, the KeyListener stops working. I even set back the setFocusable(true) property back on the game JPanel after I remove the Inventory JPanel but it still doesn't make the KeyListener work.
Here is my code for the game Jpanel:
package javavideogame;
public class Game extends JPanel implements ActionListener, Runnable
{
public Game(MainCharacter character)
{
TAdapter a = new TAdapter();
addKeyListener(a);
setFocusable(true);
setDoubleBuffered(true);
setFocusTraversalKeysEnabled(false);
}
public void getInventoryScreen()
{
Main.inv = new Inventory();
Main.inv.sayHello();
Main.mainGame.getContentPane().add(Main.inv);
Main.game.setVisible(false);
Main.mainGame.validate();
}
public void closeInventory()
{
Main.inv.setFocusable(false);
Main.mainGame.remove(Main.inv);
Main.game.setVisible(true);
Main.game.setFocusable(true);
}
public class TAdapter extends KeyAdapter
{
public void keyPressed(KeyEvent e)
{
character.keyPressed(e);
}
public void keyReleased(KeyEvent e)
{
character.keyReleased(e);
}
}
}
And here is the Inventory code:
package javavideogame;
public class Inventory extends JPanel implements KeyListener
{
public Inventory()
{
setBackground(Color.RED);
addKeyListener(this);
setFocusable(true);
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if(key == KeyEvent.VK_I)
{
Main.game.closeInventory();
}
}
public void keyReleased(KeyEvent e)
{
}
public void keyTyped(KeyEvent e)
{
}
}
And yes im having a hard time getting the code thing on here to work right :)
But is there something i can easily put into the code so that the KeyListener will actually work right once it goes back to the game JPanel?
I even set back the setFocusable(true) property back on the game JPanel after I remove the Inventory JPanel
Key events only go the the component that has focus. You need to invoke:
panel.requestFocusInWindow();
after swapping the panels to make sure the panel has focus again.
However, a better approach is to use Key Bindings itead of a KeyListener.
You could skip working with adding and removing panels to the content pane and just set the visibility. Then you should also skip setting the focusable property (KeyEvents won't be passed to an invisible component anyway) and your key listeners should be preserved and come into effect again when the component becomes visible.