I have been trying to create a 'catch me if you can' game: when I start it, it randomly chooses where to allocate a 'click me' button. I am not supposed to be able to click the button, the text should be re-assigned to another button before I am able to do that.
It works for a while but then it throws the following error: "java.awt.AWTEventMulticaster.mouseMoved".
I have been trying to fix the problem with removeListener() method but I don't seem to be able to find a solution. Any comments?
Here's my code:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.lang.*;
public class Game extends JFrame {
//Panels
private JPanel mainPanel = new JPanel();
// Buttons
private JButton[] buttons = new JButton[9];
private JButton theChosenButton = new JButton();
// other
private int random = 0;
public Game() {
this.setTitle("Catch me if you can");
mainPanel.setLayout(new GridLayout(3, 3));
// creates buttons
for(int i = 0; i < 9 ; i++) {
buttons[i] = new JButton();
mainPanel.add(buttons[i]);
}
// Add everything to frame
this.getContentPane().add(mainPanel);
this.setSize(400, 400);
this.setVisible(true);
}
// generates random number between 1 and 9 to be used
public int clickMeGenerator(){
random = (int) Math.floor(Math.random() * 9);
return random;
}
// randomly assigns clickMeGenerator to a button
// add mouseMoved listener to the chosen button
public void assign(){
int randomButton = this.clickMeGenerator();
theChosenButton = buttons[randomButton];
theChosenButton.addMouseMotionListener(new MouseHover());
theChosenButton.setText("Click me");
}
public void removeListener() {
theChosenButton.removeMouseMotionListener(new MouseHover());
//}
}
// inner class
class MouseHover implements MouseMotionListener {
public void mouseMoved(MouseEvent e) {
theChosenButton.setText("");
Game.this.assign();
}
public void mouseDragged(MouseEvent e) {
}
}
} // end of class
Test class:
public class GameTest {
public static void main (String args[]) {
Game myGame = new Game();
myGame.assign();
}
}
Thank you so much for your help!
Just for clarity, the "actual" error is ...
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at java.desktop/java.awt.AWTEventMulticaster.mouseMoved(AWTEventMulticaster.java:337)
at java.desktop/java.awt.AWTEventMulticaster.mouseMoved(AWTEventMulticaster.java:337)
So looking through the code...
public void assign() {
int randomButton = this.clickMeGenerator();
theChosenButton = buttons[randomButton];
theChosenButton.addMouseMotionListener(new MouseHover());
theChosenButton.setText("Click me");
}
You are repeatedly add a new MouseMotionListener to you buttons, over and over again, and...
public void removeListener() {
theChosenButton.removeMouseMotionListener(new MouseHover());
//}
}
is pointless, as you're trying to remove a new instance of MouseHover from the button, but it will never have been applied in the first place.
The first thing I would do is create an instance of MouseHover as an instance field in Game
private MouseHover mouseHover = new MouseHover();
and use it when calling addMouseMotionListener and removeMouseMotionListener.
I would then, remove the listener from the "currently" active button before adding it to the next one.
Personally, I would do this in the assign method
public void assign() {
int randomButton = this.clickMeGenerator();
if (theChosenButton != null) {
theChosenButton.removeMouseMotionListener(mouseHover);
}
theChosenButton = buttons[randomButton];
theChosenButton.addMouseMotionListener(mouseHover);
theChosenButton.setText("Click me");
}
I would also ensure that assign is called from within the Event Dispatching Thread when the class is first created, as the UI has been realised by the end of the constructor of Game, meaning the first call to assign is outside of the context of the EDT, which is not recommended.
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Game myGame = new Game();
myGame.assign();
}
});
}
Related
I want to have titlescreen and open a game by clicking a button. When i call the play()-method of my project normally, it draws the first level. But when i call it with a button, a white screen appeares and I dont know why. Here is a code snippet:
package com.company;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Game implements ActionListener {
private String csvFile;
private JFrame titlescreen;
private JButton startButton;
public Game(String csvFile){
this.csvFile = csvFile;
}
public void prepare(){
titlescreen = new JFrame("Titlescreen");
titlescreen.setSize(100,100);
startButton = new JButton("Start Game");
startButton.addActionListener(this);
titlescreen.add(startButton);
titlescreen.setVisible(true);
}
public void play(){
titlescreen.setVisible(false);
if(csvFile!= null) {
LevelBuilder levelBuilder = new LevelBuilder(csvFile, ";", ",");
AllObstacles ao = new AllObstacles();
ao.addObstaclesOfString(levelBuilder.getLvlString(), ";", ",");
Goal g = new Goal(125, 125, 250, 250);
PlayGame c = new PlayGame(ao, g, levelBuilder);
c.create();
c.play();
}
}
#Override
public void actionPerformed(ActionEvent e) {
startButton.dispatchEvent(e);
play();
}
}
Can someone help me with my problem?
Please see you have play() method used inside of play() method. Please try to change ones name. Maybe you are just calling wrong method inside of actionPerformed() method.
If that won't work, you can try deleting whole play(){...} and actionPerformed(){...} methods from your snippet and delete line:
startButton.addActionListener(this);
Then you can just add this into your prepare() function:
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(csvFile!= null) {
titlescreen.dispose();
LevelBuilder levelBuilder = new LevelBuilder(csvFile, ";", ",");
AllObstacles ao = new AllObstacles();
ao.addObstaclesOfString(levelBuilder.getLvlString(), ";", ",");
Goal g = new Goal(125, 125, 250, 250);
SwingUtilities.invokeLater(() -> new PlayGame(ao, g, levelBuilder);
}
});
It will add to your button new ActionListener that:
disposes titlescreen (you do not need it running in background)
runs new PlayGame object in new thread (to avoid lags especially if you have any timer in your game)
Moreover:
c.create()
c.play()
you are using those two methods everytime you create new PlayGame object, so you should put them into constructor of PlayGame class, so:
public PlayGame(){
//your current code
create();
play();
}
I am trying to develop a very basic "Simon says" simulator using Java GUI. I have a method that generates and returns an int[] array; for each element in the array, the Timer computer should start, call the doClick() method for the specified JButton, and wait for 1/2 a second. Each JButton is connected to an ActionListener() that changes the color of the specific button to white, activates another Timer timer, and changes the button back to its original color.
Every time I call computer.start(); within the for-loop it runs the code within ComputerListener(), but it repeats endlessly. I have added print statements so that I can see what is going on via the output on Netbeans. I have looked at similar issues on the forum, but nothing has provided a viable solution.
My question: why is my ComputerListener class repeating when computer.start(); is called within the for-loop?
package simon;
// #jagged_prospect
import java.util.Random;
import java.util.Arrays;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.basic.BasicButtonUI;
public class SIMONPanel extends JPanel{
private static final int PANEL_W=300,PANEL_H=300;
private static final int PREF_W=500,PREF_H=500;
private static final String[] CARD_LABELS={"main","info","game"};
private final JPanel gameCard,infoCard,splashCard;
private final JButton rButton,yButton,gButton,bButton;
private final int lives=3;
private CardLayout cardlayout=new CardLayout();
private JPanel cards=new JPanel(cardlayout);
private Action[] actions={new ShowMainAction(),new ShowInfoAction(),
new ShowGameAction()};
private Object source;
private Timer timer,computer;
public SIMONPanel(){
setBackground(Color.BLACK);
setLayout(new BorderLayout());
gameCard=new JPanel();
infoCard=new JPanel();
splashCard=new JPanel();
// game card panel
gameCard.setLayout(new BorderLayout());
gameCard.setPreferredSize(new Dimension(PANEL_W,PANEL_H));
JPanel gameButtonPanel=new JPanel();
gameButtonPanel.setLayout(new GridLayout(2,2));
JButton startButton=new JButton("Start");
startButton.addActionListener(new StartListener());
rButton=new JButton("red");
rButton.addActionListener(new ColorButtonListener());
rButton.setSize(50,50);
rButton.setUI((ButtonUI)BasicButtonUI.createUI(rButton));
rButton.setBackground(Color.RED);
rButton.setForeground(Color.WHITE);
yButton=new JButton("yellow");
yButton.addActionListener(new ColorButtonListener());
yButton.setSize(50,50);
yButton.setUI((ButtonUI)BasicButtonUI.createUI(yButton));
yButton.setBackground(Color.YELLOW);
gButton=new JButton("green");
gButton.addActionListener(new ColorButtonListener());
gButton.setSize(50,50);
gButton.setUI((ButtonUI)BasicButtonUI.createUI(gButton));
gButton.setBackground(Color.GREEN);
bButton=new JButton("blue");
bButton.addActionListener(new ColorButtonListener());
bButton.setSize(50,50);
bButton.setUI((ButtonUI)BasicButtonUI.createUI(bButton));
bButton.setBackground(Color.BLUE);
bButton.setForeground(Color.WHITE);
gameButtonPanel.add(gButton);
gameButtonPanel.add(rButton);
gameButtonPanel.add(yButton);
gameButtonPanel.add(bButton);
gameCard.add(gameButtonPanel,BorderLayout.CENTER);
gameCard.add(startButton,BorderLayout.SOUTH);
// splash card panel
splashCard.setLayout(new BorderLayout());
splashCard.setPreferredSize(new Dimension(PANEL_W,PANEL_H));
splashCard.setBackground(Color.BLACK);
JLabel titleLabel=new JLabel("S I M O N",SwingConstants.CENTER);
titleLabel.setFont(new Font("Niagara Solid",Font.BOLD,84));
titleLabel.setForeground(Color.WHITE);
splashCard.add(titleLabel,BorderLayout.CENTER);
// info card panel
// nothing here yet
JPanel buttonPanel=new JPanel(new GridLayout(1,0,5,0));
for(Action action : actions){
buttonPanel.add(new JButton(action));
buttonPanel.setBackground(Color.BLACK);
}
cards.add(splashCard,CARD_LABELS[0]);
cards.add(infoCard,CARD_LABELS[1]);
cards.add(gameCard,CARD_LABELS[2]);
add(cards,BorderLayout.CENTER);
add(buttonPanel,BorderLayout.SOUTH);
}
// sets uniform panel size
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
// shows the Main Menu card
private class ShowMainAction extends AbstractAction {
public ShowMainAction() {
super("Main");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(cards,CARD_LABELS[0]);
}
}
// shows the Info card
private class ShowInfoAction extends AbstractAction {
public ShowInfoAction() {
super("Info");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(cards,CARD_LABELS[1]);
}
}
// show the Game card
private class ShowGameAction extends AbstractAction {
public ShowGameAction() {
super("Game");
}
#Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(cards,CARD_LABELS[2]);
}
}
private class TimerListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent event){
if(source==gButton){
gButton.setBackground(Color.GREEN);
}
else if(source==rButton){
rButton.setBackground(Color.RED);
rButton.setForeground(Color.WHITE);
}
else if(source==yButton){
yButton.setBackground(Color.YELLOW);
}
else if(source==bButton){
bButton.setBackground(Color.BLUE);
bButton.setForeground(Color.WHITE);
}
}
}
private class ColorButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent event){
source=event.getSource();
int delay=300;
timer=new Timer(delay,new TimerListener());
if(source==gButton){
gButton.setBackground(Color.WHITE);
timer.setRepeats(false);
timer.start();
}
else if(source==rButton){
rButton.setBackground(Color.WHITE);
rButton.setForeground(Color.BLACK);
timer.setRepeats(false);
timer.start();
}
else if(source==yButton){
yButton.setBackground(Color.WHITE);
timer.setRepeats(false);
timer.start();
}
else if(source==bButton){
bButton.setBackground(Color.WHITE);
bButton.setForeground(Color.BLACK);
timer.setRepeats(false);
timer.start();
}
}
}
private class StartListener implements ActionListener{
public void actionPerformed(ActionEvent event){
// calls generateSequence() to make pattern for player to replicate
// for debugging in output
System.out.println(Arrays.toString(generateSequence()));
}
}
public int[] generateSequence(){
Random ran=new Random();
ComputerListener cpu=new ComputerListener();
computer=new javax.swing.Timer(500,cpu);
int seqLen=4;
int[] gameSequence=new int[seqLen];
for(int x=0;x<seqLen;x++){
int assign=ran.nextInt(4)+1;
gameSequence[x]=assign;
}
for(int y=0;y<seqLen;y++){ // print and wait 1/2 second, repeat 3 times
computer.start();
}
//computer.stop(); // should stop ComputerListener()???
return gameSequence;
}
private class ComputerListener implements ActionListener{
public void actionPerformed(ActionEvent event){
// for debugging in output
System.out.println("it worked");
}
}
}
You're calling the computer Swing Timer's start button multiple times in a for loop, and that is not what you want to do, and in fact, the whole purpose of the timer is to help you get rid of the for loop. Instead the Timer repeats an action, and changes a state, and keeps going until its done. Consider using an int array or better an ArrayList to hold the colors that the timer should iterate through, and within that ActionListener, do the action and advance a pointer to the next position in the array or List, using that pointer to decide what action to do next. Then when the pointer is completely through the collection, stop the Timer.
For an example of exactly what I'm describing, please check out my Timer's ActionListener for an incomplete Simon game here: Method keeps window from closing
The Timer's ActionListener, annotated, is below:
private class TimerListener implements ActionListener {
private SimonPanel simonPanel; // the Simon JPanel
private int colorListIndex = 0; // index into the ArrayList of MyColor objects
private int sliceCount = 0;
private List<MyColor> myColorList; // the MyColor ArrayList -- the random colors to press
private int maxCount;
public TimerListener(SimonPanel simonPanel, List<MyColor> myColorList) {
// pass in the key fields into the program via constructor parameter
this.simonPanel = simonPanel;
this.myColorList = myColorList; // again the ArrayList that holds random MyColor objects
maxCount = myColorList.size(); // size of my list
}
#Override
public void actionPerformed(ActionEvent evt) {
// if index at the end of the list -- get out and clean up
if (colorListIndex == maxCount) {
// clear the display of "pressed" colors
for (MyColor myColor : MyColor.values()) {
simonPanel.setMyColorPressed(myColor, false);
}
// stop this timer
((Timer) evt.getSource()).stop();
return;
}
// the listener is a little complex since it must turn on colors and turn them off
// which is why I use a sliceCount int counter variable here
if (sliceCount == 0) {
// turn on the next color in the list (using the index)
MyColor myColor = myColorList.get(colorListIndex);
simonPanel.setMyColorPressed(myColor, true);
sliceCount++;
} else if (sliceCount < TIME_SLICES - 1) {
sliceCount++;
return;
} else if (sliceCount == TIME_SLICES - 1) {
sliceCount = 0;
MyColor myColor = myColorList.get(colorListIndex);
simonPanel.setMyColorPressed(myColor, false); // turn off the color
colorListIndex++; // and increment the index
return;
}
}
}
I've created 2 JButtons.One of them has the function of a button and the other handles an image.I want that image to change when this button is clicked.So inserted the method repaint() and added a listener to the first JButton to change the image.When trying to add the listener or the event handler to the first JButton nothing happens.So the image doesn't change.Can anyone show me how can I insert this listener in a way that it works(changes the image when the button is clicked)?Here is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import javax.swing.*;
import java.util.Random;
public class Back extends JFrame{
private Random ran;
private int value;
private JButton r;
private JButton c;
public Back(){
super("title");
ran = new Random();
value = nextValue();
setLayout(new FlowLayout());
r=new JButton("ROLL");
add(r);
Icon i=new ImageIcon(getClass().getResource("1.png"));
Icon img=new ImageIcon(getClass().getResource("2.png"));
c= new JButton(i);
if (value==1){
c= new JButton(i);
}
else if(value==2){
c= new JButton(img);
}
add(c);
thehandler hand=new thehandler(this);//konstruktori i handler merr nje instance te Background
r.addActionListener(hand);
c.addActionListener(hand);
}
private int nextValue() {
return Math.abs(ran.nextInt()) % 6 + 1 ;
}
public void roll() {
value = nextValue() ;
repaint() ;
}
public int getValue() {
return value ;
}
private class thehandler implements ActionListener{
private Back d;
thehandler(Back thisone) {
d = thisone ; }
public void actionPerformed(ActionEvent event) {
d.roll() ;
}
}
public static void main(String[] args) {
Back d = new Back() ;
d.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
d.getContentPane().setBackground(Color.GREEN);
d.setSize(700,500);
d.setVisible(true);
}
}
So, basically, all your code comes down to here...
public void roll() {
value = nextValue();
repaint();
}
This calculates a new random value and calls repaint. But nothing in your code is effected by value at the point in time it's called.
Instead, you need to update the state of some control, maybe something more like...
public void roll() {
value = nextValue();
Icon i = new ImageIcon(getClass().getResource("1.png"));
Icon img = new ImageIcon(getClass().getResource("2.png"));
if (value == 1) {
c.setIcon(i);
} else if (value == 2) {
c.setIcon(img);
}
}
The next thing I would do is store all your images in some kind of array or List to make it easier to access, then you could simply do something
like...
public void roll() {
value = nextValue();
c.setIcon(listOfImages.get(value - 1));
}
Maybe have a look at Java Swing Timer and Animation: how to put it together for a more detailed example
Ok, so the program I want to build is simple. There are five buttons named from 0 to 4. If any of the buttons are pressed, then the number 0 to 4 is printed in console.
I have used a GridLayout to place the buttons in the frame. And to set up each button I have created a method, inicializarIG().
This inicializarIG() method creates an array of 5 buttons and inside a for loop it does:
Create an instance of a button for each cell in the array of buttons.
Set up a mouseListener for each button. The value to print in each Listener is different, it is determined by the index of the loop (AND I WANT TO DO IT BY USING THE INDEX!).
Add The button to the main frame.
Surprisingly, This simple program doesn´t work properly. It always print the number "5" no matter what button is pressed:
NOTE: I had to put the index var outside the inicializarIG() method in order to fulfill the var scope for the Listeners. I don't know if the problem is related, just saying in cause it might help.
THE CODE:
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
public class IGrafica {
private JFrame frame;
public int index=0;
public IGrafica(){
frame = new JFrame();
configureFrame();
inicializarIG();
}
public void configureFrame(){
frame.setBounds(100,100,400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridLayout(1,5)); //
}
public void inicializarIG(){
//Buttons
JButton [] botones = new JButton [5];
//Loop to set up buttons and add the mouseListener
for (index = 0; index < botones.length; index++) {
botones[index] = new JButton(Integer.toString(index));
//Set up each listener
botones[index].addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
System.out.println(index);
//texto.setBackground(colores[index]);
}
});
//Add the button
frame.getContentPane().add(botones[index]);
}
}
public void visualizate(){
frame.setVisible(true);
}
public static void main(String[] args) {
IGrafica window = new IGrafica();
EventQueue.invokeLater(new Runnable() {
public void run() {
window.visualizate();
}
});
}
}
Thank you in advance. Any idea will be welcomed.
Jesús
First of all, don't use a MouseListener for this, but rather use an ActionListener, since this works best for buttons. Next of all, you need to remember that your listener is a class of its own, and it needs a variable of its own to store its own index, else it uses the final value of the loop index which is not what you want. Either this or use the ActionEvent's actionCommand property, a value which will match the text of the button. So:
botones[index].addActionListener(new MyActionListener(index));
and
// a private inner class
private class MyActionListener implements ActionListener {
private int index;
public MyActionListener(int index) {
this.index = index;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("index is: " + index);
System.out.println("Action Command is: " + e.getActionCommand());
}
}
Or if you want to use an anonymous inner class:
botones[index].addActionListener(new ActionListener() {
private int myIndex;
{
this.myIndex = index;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("index is: " + myIndex);
}
});
I have two frames (One main and one popup). On the main frame key & mouse listeners are added. Both work just fine. On the pop up there are 50 buttons. I have one action listener for all of them. It works fine. I also have key & mouse listeners. Mouse works. Key is flaky.
The same keyListener class used in main frame is added to the pop-up frame too.
As soon as the pop up shows, key listener works, once mouse click happens (Action listener kicks in) keylistener stops working. Please help. The code attached is a simplified version
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class key {
private static class toolsAction implements ActionListener {
public void actionPerformed (ActionEvent ae) {
log("Command " + Integer.parseInt(ae.getActionCommand()));
}
}
private static void log(String s) { System.out.println(s); }
private static class keyboardHandler implements KeyListener {
public void keyPressed( KeyEvent e) { log("KB Press called "); }
public void keyReleased(KeyEvent e) { log("KB Release called "); }
public void keyTyped (KeyEvent e) { log("KB Typed called "); }
}
public static void main(String [] args) {
JFrame pFrame = new JFrame("Frame");
pFrame.addKeyListener(new keyboardHandler());
Container pane = pFrame.getContentPane();
pane.setLayout(null);
pane.setVisible(true);
pFrame.setSize(650, 300);
pFrame.setVisible(true);
JButton[] buttons = new JButton[50];
toolsAction action = new toolsAction();
for (int i = 0; i < 50; i++) {
buttons[i] = new JButton("" + i);
buttons[i].setActionCommand("" + i);
buttons[i].addActionListener(action);
pane.add(buttons[i]);
buttons[i].setBounds(((i % 10) * 60), ((i / 10) * 40), 60, 40);
}
}
}
An alternative approach uses Action and key bindings. The example below binds 10 buttons to the number keys, also using the numbers as the MNEMONIC_KEY of each.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/** #see http://stackoverflow.com/a/14182227/230513 */
public class Key {
public static final int SIZE = 10;
private static class ToolAction extends AbstractAction {
public ToolAction(int i) {
super(String.valueOf(i));
putValue(MNEMONIC_KEY, KeyEvent.VK_0 + i);
}
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println(ae.getActionCommand());
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("Frame");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(0, SIZE / 2));
for (int i = 0; i < SIZE; i++) {
final ToolAction toolAction = new ToolAction(i);
JButton b = new JButton(toolAction);
String name = b.getText();
b.getInputMap(JButton.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent.VK_0 + i, 0), name);
b.getActionMap().put(name, toolAction);
f.add(b);
}
f.pack();
f.setVisible(true);
}
});
}
}
The KeyListener will only be executed if the component, to which the listener is added, has the (keyboard) focus. If you click on another component, that component will become the focus and the keyboard events will be sent to its KeyListeners.
Not sure if that is the problem without seeing the code of the popup, but it's the problem in the posted code...
EDIT
you can add an AWTEventListener to the Toolkit to intercept all events independently of the focused component:
private static class AWTListener implements AWTEventListener {
#Override
public void eventDispatched(AWTEvent event) {
log("AWT: " + event);
}
};
...
Toolkit toolkit = Toolkit.getDefaultToolkit();
toolkit.addAWTEventListener(new AWTListener(), AWTEvent.KEY_EVENT_MASK);
I solved this problem by adding MouseMotionListener and in the mouseMoved method calling pFrame.requestFocusInWindow() & also adding focus request in the button's actionPerformed method.
Even with just one button in a frame as long as the ActionListener is added to the button, KeyListener does not work.
This is kludgy at best, but works for me. I would still love to hear from the community why my original code does not work.