I have a simple JFrame class with KeyListener and some method.
public class MyClass extends JFrame{
MyClass(){
//build window
addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == 32){
myMethod();
}
}
});
}
private void myMethod(){
//do something
}
}
MyMethod works correctly if I call it from main(). But from Listener it does nothing. Can I call methods from KeyListener at all? And if answer is no, how can I solve this problem?
It depends how do you expect to use your JFrame. You need to create window with it by instantiating it from the main() method:
public class Main {
public static void main(String[] args) {
// this is your frame instance
MyClass frame = new MyClass();
}
}
and you must implement all of the methods that KeyListener provides:
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
public class MyClass extends JFrame {
public MyClass() {
// "this." can be omitted, it is just for better understanding
// that each method applies to instance of JFrame
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(50, 50, 300, 300);
this.setVisible(true);
// add key listener
this.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
// call this method on key release
myMethod(e.getKeyCode());
}
#Override
public void keyTyped(KeyEvent e) {
}
});
}
private void myMethod(int key) {
this.setTitle("Key released: " + key);
}
}
KeyListener is a pain in the ... code. It relies on the component it is registered to be focusable AND have keyboard focus.
In general, a better solution is to use the key bindings API. It gives you finer control over when the binding should be triggered.
For example
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class MyClass extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MyClass myClass = new MyClass();
myClass.pack();
myClass.setLocationRelativeTo(null);
myClass.setVisible(true);
}
});
}
public MyClass() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// This is here because I don't like setSize or setPreferredSize
JPanel panel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
setContentPane(panel);
InputMap im = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap am = panel.getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "spaced");
am.put("spaced", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
myMethod();
}
});
}
private void myMethod() {
System.out.println("Pressed");
}
}
Related
I've created a series of classes to try and figure out Observer patterns and am having some trouble.
The two classes in the observer/observed relationship are ClockPanel, and TheTimer. TheTimer is a (swing) timer which keeps track of time from start in seconds. ClockPanel is a GUI (swing) which has a button to start the timer and a JLabel which I want to display the time.
The goal of my observer pattern: take the value being created in TheTimer and print it on my GUI.
The current problem: The timer is updating the time just fine, but I do not seem to understand how to update the value in my GUI.
I found a question similar to this one in a C# discussion, but the problem was more nuanced and way over my head.
Here are the five classes which comprise the program:
1. The GUI-ClockPanel
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ClockPanel implements Observer {
JFrame frame;
JPanel panel;
JButton sbutton;
JLabel label;
#Override
public void update(int counter) {
String clockval = String.valueOf(counter);
label.setText(clockval);
}
public ClockPanel() {
frame = new JFrame();
frame.setSize(100, 100);
panel = new JPanel();
label = new JLabel();
TheTimer myTimer = new TheTimer();
sbutton = new JButton("start");
sbutton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
myTimer.StartTimer();
}
});
frame.setLayout(new FlowLayout());
frame.add(panel);
frame.add(sbutton);
frame.add(label);
frame.setVisible(true);
}
}
2. The Swing Timer-TheTimer
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Timer;
public class TheTimer extends JPanel implements Subject {
private ActionListener action;
private Timer Time;
private int delay = 1000;
private ArrayList<Observer> observers = new ArrayList<Observer>();
private int counter = 0;
public TheTimer() {
action = new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(counter);
counter++;
setCounter(counter);
}
};
}
public void StartTimer() {
Time = new Timer(delay, action);
Time.setInitialDelay(0);
Time.start();
}
public int getCounter() {
return counter;
}
public void setCounter(int counter) {
this.counter = counter;
notifyObservers();
}
#Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
#Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
#Override
public void notifyObservers() {
for (Observer ob : observers) {
System.out.println("Notifying ClockPanel on change in counter value");
ob.update(this.counter);
}
}
}
3. The Observer-Observer
public interface Observer {
public void update(int counter);
}
4. The Observer-related methods-Subject
public interface Subject {
public void registerObserver(Observer observer);
public void removeObserver(Observer observer);
public void notifyObservers();
}
5. The Main-TestMain
import javax.swing.SwingUtilities;
public class TestMain {
public static void main(String args[]) {
ClockPanel panel = new ClockPanel();
TheTimer timer = new TheTimer();
timer.registerObserver(panel);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ClockPanel();
}
});
}
}
You have two TheTimer objects: one in ClockPanel, the other in TestMain#main().
You need to remove the timer from (say) main() and add:
myTimer.registerObserver(this);
to your ClockPanel constructor.
I am trying to make a game engine. I have made the Game class but the error resides in the KeyBoard class. Here I leave some code.
Class:: Game
package transfer2pc.co.cc.game.tileengine;
import java.awt.Graphics;
import java.util.HashMap;
import javax.swing.JPanel;
import transfer2pc.co.cc.game.tileengine.input.KeyBoard;
public abstract class Game extends JPanel implements Runnable {
/**
*
*/
private static final long serialVersionUID = 640206679500196209L;
HashMap<String, ?> maps = null;
KeyBoard keyBoard = null;
public Game(){
super();
keyBoard = new KeyBoard(this);
setKeyBoard(keyBoard);
Thread th = new Thread(this);
th.start();
}
public void run(){
while(true){
repaint();
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void paint(Graphics g){
}
public void addMap(){
}
public void setMap(){
}
public abstract void keyPressed(int code);
public abstract void keyReleased(int code);
public abstract void keyTyped(int code);
public void setKeyBoard(KeyBoard key){
addKeyListener(key);
}
}
Class:: KeyBoard
package transfer2pc.co.cc.game.tileengine.input;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import transfer2pc.co.cc.game.tileengine.Game;
public class KeyBoard extends KeyAdapter implements KeyListener {
Game game = null;
public KeyBoard(Game gm){
this.game = gm;
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("KeyPressed");
game.keyPressed(e.getKeyCode());
}
#Override
public void keyReleased(KeyEvent e) {
game.keyReleased(e.getKeyCode());
}
#Override
public void keyTyped(KeyEvent e) {
game.keyTyped(e.getKeyCode());
}
public static char getChar(int key){
return (char)key;
}
}
Class:: KeyTest
package transfer2pc.co.cc.game.tileengine.test;
import java.awt.Graphics;
import javax.swing.JFrame;
import transfer2pc.co.cc.game.tileengine.Game;
import transfer2pc.co.cc.game.tileengine.input.KeyBoard;
public class KeyTest extends Game {
/**
*
*/
private static final long serialVersionUID = 8557676950779023327L;
char pressed;
public KeyTest(){
super();
addKeyListener(new KeyBoard(this));
}
#Override
public void keyPressed(int code) {
pressed = KeyBoard.getChar(code);
}
#Override
public void keyReleased(int code) {
}
#Override
public void keyTyped(int code) {
}
#Override
public void paint(Graphics g){
g.drawString("You pressed: "+pressed, 20, 20);
}
public static void main(String[] args){
JFrame frame = new JFrame("KeyTest");
frame.setSize(640, 480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(new KeyTest());
frame.setVisible(true);
}
}
But the error was there was no exception thrown and the input isn't being read. Could anybody say me the correct way of doing this..
Simply, your panel needs to be focusable. Add in wherever you create the panel:
panel.setFocusable(true);
panel.requestFocusInWindow();
Here's a SSCCE (I suggest asking questions with one of these in the future):
import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SimpleKeyTest {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.getContentPane().add(panel);
panel.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyReleased(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Pressed " + e.getKeyChar());
}
});
panel.setFocusable(true);
panel.requestFocusInWindow();
frame.setSize(new Dimension(300, 300));
frame.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
Also, https://www.google.com/search?q=jpanel+keylistener
You can add the key listener to the JFrame, that's something I've done in the past.
It's probably not a good idea however if you have other components in the JFrame.
I customize my JComboBox as follow.
The program ran ok with default LAF, but whenever i changed the LAF to System LAF (another LAF, Nimbus, is ok), there was an infinite loop after the button was clicked. I saw that the actionPerformed method was called infinitely.
Please help me solving this problem. I use jdk 1.6.0_33
I'm so sorry if there is any unclear mean. My English is not good
Thanks in advance.
package sig.dw.ui;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ComboBoxEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
//import javax.swing.event.EventListenerList;
/**
*
* #author congnh
*/
public class ButtonableComboBox extends JComboBox{
private ButtonableComboBoxEditor comboBoxEditor;
public ButtonableComboBox(){
super();
comboBoxEditor = new ButtonableComboBoxEditor();
// eventListenerList = new EventListenerList();
setEditable(true);
setEditor(comboBoxEditor);
}
public ButtonableComboBox(Object[] items){
this();
setModel(new DefaultComboBoxModel(items));
}
public void addButtonListener(ActionListener listener){
comboBoxEditor.addActionListener(listener);
}
public void removeButtonListener(ActionListener listener){
comboBoxEditor.removeActionListener(listener);
}
class ButtonableComboBoxEditor implements ComboBoxEditor{
private JButton button;
public ButtonableComboBoxEditor(){
button = new JButton();
}
#Override
public Component getEditorComponent() {
return button;
}
#Override
public void setItem(Object anObject) {
if(anObject!=null){
button.setText(anObject.toString());
}
}
#Override
public Object getItem() {
return button.getText();
}
#Override
public void selectAll() {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public void addActionListener(ActionListener l) {
System.out.println("add new listener");
button.addActionListener(l);
}
#Override
public void removeActionListener(ActionListener l) {
button.removeActionListener(l);
}
}
public static void main(String args[]){
javax.swing.SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
String[] comboBoxItems = {"Browse","Explorer","Firefox","IE","Chrome","Opera"};
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
ButtonableComboBox bcb = new ButtonableComboBox(comboBoxItems);
bcb.addButtonListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.add(bcb);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
For reference, I see StackOverflowError for MotifLookAndFeel on Mac OS X / Java 1.6.0_37, but not MetalLookAndFeel, NimbusLookAndFeel, or AquaLookAndFeel. Using the example below and the L&F selector seen here, I get the follwing stack trace as the UI delegate recursively invokes doClick(). I don't see an obvious workaround.
Addendum: I see a similar StackOverflowError for MotifLookAndFeel on Ubuntu 12 / Java 1.6.0_24, but not MetalLookAndFeel, NimbusLookAndFeel, or GTKLookAndFeel.
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at sun.font.FontManager.getFont2D(Native Method)
at sun.java2d.SunGraphics2D.checkFontInfo(SunGraphics2D.java:780)
at sun.java2d.SunGraphics2D.getFontInfo(SunGraphics2D.java:941)
at sun.java2d.pipe.GlyphListPipe.drawString(GlyphListPipe.java:32)
at sun.java2d.SunGraphics2D.drawString(SunGraphics2D.java:3054)
at sun.swing.SwingUtilities2.drawString(SwingUtilities2.java:517)
at sun.swing.SwingUtilities2.drawStringUnderlineCharAt(SwingUtilities2.java:538)
at javax.swing.plaf.basic.BasicButtonUI.paintText(BasicButtonUI.java:294)
at javax.swing.plaf.basic.BasicButtonUI.paintText(BasicButtonUI.java:319)
at javax.swing.plaf.basic.BasicButtonUI.paint(BasicButtonUI.java:207)
at com.sun.java.swing.plaf.motif.MotifButtonUI.paint(MotifButtonUI.java:91)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:153)
at javax.swing.JComponent.paintComponent(JComponent.java:760)
at javax.swing.JComponent.paint(JComponent.java:1037)
at javax.swing.JComponent.paintChildren(JComponent.java:870)
at javax.swing.JComponent.paint(JComponent.java:1046)
at javax.swing.JComponent.paintChildren(JComponent.java:870)
at javax.swing.JComponent.paint(JComponent.java:1046)
at javax.swing.JComponent._paintImmediately(JComponent.java:5106)
at javax.swing.JComponent.paintImmediately(JComponent.java:4890)
at javax.swing.JComponent.paintImmediately(JComponent.java:4902)
at javax.swing.AbstractButton.doClick(AbstractButton.java:352)
at javax.swing.plaf.basic.BasicRootPaneUI$Actions.actionPerformed(BasicRootPaneUI.java:191)
at javax.swing.plaf.basic.BasicComboBoxUI$Actions.actionPerformed(BasicComboBoxUI.java:1575)
at javax.swing.plaf.basic.BasicComboBoxUI$Handler.actionPerformed(BasicComboBoxUI.java:1904)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2028)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2351)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.AbstractButton.doClick(AbstractButton.java:389)
...
at javax.swing.plaf.basic.BasicRootPaneUI$Actions.actionPerformed(BasicRootPaneUI.java:191)
at javax.swing.plaf.basic.BasicComboBoxUI$Actions.actionPerformed(BasicComboBoxUI.java:1575)
at javax.swing.plaf.basic.BasicComboBoxUI$Handler.actionPerformed(BasicComboBoxUI.java:1904)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2028)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2351)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.AbstractButton.doClick(AbstractButton.java:389)
at javax.swing.plaf.basic.BasicRootPaneUI$Actions.actionPerformed(BasicRootPaneUI.java:191)
at javax.swing.plaf.basic.BasicComboBoxUI$Actions.actionPerformed(BasicComboBoxUI.java:1575)
SSCCE:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ComboBoxEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class ButtonableComboBox extends JComboBox {
private ButtonableComboBoxEditor comboBoxEditor;
public ButtonableComboBox() {
comboBoxEditor = new ButtonableComboBoxEditor();
setEditor(comboBoxEditor);
setEditable(true);
}
public ButtonableComboBox(Object[] items) {
this();
setModel(new DefaultComboBoxModel(items));
}
public void addButtonListener(ActionListener listener) {
comboBoxEditor.addActionListener(listener);
}
public void removeButtonListener(ActionListener listener) {
comboBoxEditor.removeActionListener(listener);
}
class ButtonableComboBoxEditor implements ComboBoxEditor {
private JButton button = new JButton();
#Override
public Component getEditorComponent() {
return button;
}
#Override
public void setItem(Object anObject) {
if (anObject != null) {
button.setText(anObject.toString());
}
}
#Override
public Object getItem() {
return button.getText();
}
#Override
public void selectAll() {
System.out.println("select all");
button.requestFocus();
}
#Override
public void addActionListener(ActionListener l) {
System.out.println("add listener");
button.addActionListener(l);
}
#Override
public void removeActionListener(ActionListener l) {
System.out.println("remove listener");
button.removeActionListener(l);
}
}
public static void main(String args[]) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
String[] comboBoxItems = {
"Browse", "Explorer", "Firefox", "IE", "Chrome", "Opera"};
JFrame frame = new JFrame();
JPanel panel = new JPanel();
ButtonableComboBox bcb = new ButtonableComboBox(comboBoxItems);
bcb.addButtonListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
});
panel.add(bcb);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// https://stackoverflow.com/a/11949899/230513
frame.add(createToolBar(frame), BorderLayout.NORTH);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I want to have the user press a button to kick off a background thread.
While the thread is processing, I want two things to happen:
1) A WAIT_CURSOR should be displayed.
2) The application should not respond to mouse events.
As per the setCursor documentation "This cursor image is displayed when the contains method for this component returns true for the current cursor location, and this Component is visible, displayable, and enabled. ".
I want my application to be disabled while this background thread is processing.
Any ideas how to get the functionality I want?
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class WaitCursor extends JFrame
{
private static final long serialVersionUID = 1L;
public WaitCursor()
{
setResizable(false);
setName(getClass().getSimpleName());
setTitle("My Frame");
setSize(300, 300);
getContentPane().add(new MyButtonPanel());
}
private class MyButtonPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public MyButtonPanel()
{
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new BtnStartActionListener());
add(btnStart);
}
private class BtnStartActionListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
// Change to WAIT_CURSOR
Component root = SwingUtilities.getRoot((JButton) e.getSource());
JOptionPane.showMessageDialog(root, "Wait 10 seconds");
root.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// TODO: Disabling the root component prevents the WAIT_CURSOR from being displayed
root.setEnabled(false);
new Thread(new TimeKiller(root)).start();
}
}
}
private class TimeKiller implements Runnable
{
Component _root;
public TimeKiller(Component root)
{
_root = root;
}
public void run()
{
try
{
Thread.sleep(10 * 1000);
}
catch (InterruptedException e)
{
// Ignore it
}
// Change back to DEFAULT CURSOR
JOptionPane.showMessageDialog(_root, "Done waiting");
_root.setCursor(Cursor.getDefaultCursor());
_root.setEnabled(true);
}
}
private static void createAndShowGUI()
{
// Create and set up the window.
WaitCursor frame = new WaitCursor();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
try
{
createAndShowGUI();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(0);
}
}
});
}
}
One way to disable it is to use the glass pane to block mouse input.
For example:
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import javax.swing.*;
#SuppressWarnings("serial")
public class WaitCursor2 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private JComponent glassPane;
private JButton runBackgroundProcBtn;
private JTextArea textarea = new JTextArea(15, 30);
public WaitCursor2(JComponent glassPane) {
this.glassPane = glassPane;
glassPane.setFocusable(true);
glassPane.addMouseListener(new MouseAdapter() {
}); // so it will trap mouse events.
add(new JTextField(10));
add(runBackgroundProcBtn = new JButton(new AbstractAction(
"Run Background Process") {
#Override
public void actionPerformed(ActionEvent arg0) {
runBackgroundProcessAction();
}
}));
add(new JScrollPane(textarea));
}
private void runBackgroundProcessAction() {
disableSystem(true);
glassPane.setVisible(true);
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
long sleepTime = 5000;
Thread.sleep(sleepTime);
return null;
}
#Override
protected void done() {
disableSystem(false);
}
}.execute();
}
public void disableSystem(boolean disable) {
glassPane.setVisible(disable);
runBackgroundProcBtn.setEnabled(!disable);
if (disable) {
System.out.println("started");
glassPane.requestFocusInWindow(); // so can't add text to text components
glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
} else {
System.out.println("done");
glassPane.setCursor(Cursor.getDefaultCursor());
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("WaitCursor2");
WaitCursor2 mainPanel = new WaitCursor2((JComponent) frame.getGlassPane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
The glass pane will trap mouse events if it set visible and given a MouseListener. It will lose t his ability if it is set invisible. Likewise it will pull the caret from text components if you make it focusable and give it focus.
added a field current_active and at method actionPerformed, do a simple check. Albeit it is not perfect but for simple app, i think this do the trick. A crude way of solving your two requirement. :-) Hope it works for you too.
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class WaitCursor extends JFrame
{
private static boolean current_active = false;
public WaitCursor()
{
setResizable(false);
setName(getClass().getSimpleName());
setTitle("My Frame");
setSize(300, 300);
getContentPane().add(new MyButtonPanel());
}
private class MyButtonPanel extends JPanel
{
public MyButtonPanel()
{
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new BtnStartActionListener());
add(btnStart);
}
private class BtnStartActionListener implements ActionListener
{
// change to wait_cursor
public void actionPerformed(ActionEvent e)
{
if (!current_active)
{
Component root = SwingUtilities.getRoot((JButton) e.getSource());
JOptionPane.showMessageDialog(root, "Wait 10 seconds");
root.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// TODO: Disabling the root component prevents the WAIT_CURSOR from being displayed
//root.setEnabled(false);
current_active = true;
new Thread(new TimeKiller(root)).start();
}
}
}
}
private class TimeKiller implements Runnable
{
Component m_root;
public TimeKiller(Component p_root)
{
m_root = p_root;
}
#Override
public void run()
{
try
{
Thread.sleep(10 * 1000);
}
catch (InterruptedException e)
{
//Ignore it
}
// Change back to DEFAULT CURSOR
JOptionPane.showMessageDialog(m_root, "Done waiting");
m_root.setCursor(Cursor.getDefaultCursor());
current_active = false;
}
}
// create and setup the window.
public static void createAndShowGUI()
{
WaitCursor frame = new WaitCursor();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
try
{
createAndShowGUI();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(0);
}
}
});
}
}
I'm having trouble with a KeyListener. I add the KeyListener to the JPanel that I create, but the KeyListener isn't working.
My code for the main class is
package client;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class KeyTest {
public static KeyboardEvents keyEvents;
public static void main(String[] args) {
JFrame frame = new JFrame("KeyTest");
JPanel panel = new JPanel();
panel.setFocusable(true);
panel.requestFocus();
panel.addKeyListener(keyEvents);
frame.add(panel);
frame.setSize(new Dimension(640,480));
frame.setVisible(true);
}
}
My code for the KeyboardEvents class is
package client;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashMap;
import java.util.Map;
public class KeyboardEvents implements KeyListener {
Map<Integer, Integer> keyMap;
public KeyboardEvents() {
initiate();
}
public void initiate() {
keyMap = new HashMap<Integer, Integer>();
}
public void keyPressed(KeyEvent e) {
keyMap.put(new Integer(e.getKeyCode()), new Integer(keyMap.size()));
System.out.println(e.getKeyCode());
}
public void keyReleased(KeyEvent e) {
keyMap.remove(e.getKeyCode());
}
public void keyTyped(KeyEvent e) {
}
public boolean keyDown(int key) {
return keyMap.containsKey(key);
}
public Integer[] getKeys() {
Object[] keys;
keys = keyMap.keySet().toArray();
Integer[] c = new Integer[keys.length];
for(int i = 0; i < keys.length; i++)
{
c[i] = (Integer) keys[i];
}
return c;
}
}
My KeyboardEvents class has always worked for me. I can't figure out why it won't work now.
keyEvents is null. before you add it:
keyEvents= new KeyBoardEvents();