What is the best way to listen for keyboard input in a Java Applet?
I have an applet which opens a JFrame and I am using a KeyListener to listen for keyboard input. This works fine in my development environment (eclipse), but when I run the applet through a browser (I have tried Firefox and IE) it does not respond to keyboard events.
However, if I run the applet and then minimize and maximize the frame, it works.
I have tried setting focus to the JFrame in many different ways and also programmatically minimizing and maximizing it, but to no effect.
I have also tried key bindings, but with the same problem.
I have trimmed my code down to the barest essentials of the problem and pasted it below.
Can someone see what I am doing wrong or suggest a better solution?
public class AppletTest extends Applet
{
private GuiTest guiTest;
public void init() {
guiTest = new GuiTest();
final AppletTest at = this;
guiTest.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent ke) {
at.keyPressed(ke);
}
public void keyReleased(KeyEvent ke) {}
public void keyTyped(KeyEvent e) {}
});
}
private void keyPressed(KeyEvent ke)
{
System.out.println("keyPressed "+KeyEvent.getKeyText(ke.getKeyCode()));
getGuiTest().test(KeyEvent.getKeyText(ke.getKeyCode()));
}
}
public class GuiTest extends JFrame {
String teststring = "?";
public GuiTest()
{
setSize(100,100);
setEnabled(true);
setVisible(true);
setFocusable(true);
requestFocus();
requestFocusInWindow();
toFront();
}
public void test(String t)
{
teststring = t;
repaint();
}
public void paint(Graphics g)
{
g.setColor(Color.white);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.black);
g.drawString(teststring, 50, 50);
}
}
I solved the problem. If I create the JFrame following a button press or mouse event on the applet, the key listener on the JFrame works. Apparently, creating the frame from Applet.init() means that key listeners do not function correctly when opened through a browser.
However, the question remains - why? If someone can explain this, I would greatly appreciate it.
I thought it might be because the frame should be created on the event dispatch thread, but using SwingUtilities.invokeLater or invokeAndWait did not work.
I think you are running into the plugin focus issue: in many modern browser a plugin only gains focus through either the user clicking on it or using Javascript. This typically affects Flash but it might be that it also affects applets. Try Adobe's recommendations at http://kb2.adobe.com/cps/155/tn_15586.html.
Let me know if that works for you.
Related
I am following code I found on geeksforgeeks but the mouse listener isn't firing. I suspect that somehow the implementation of runnable is locking access to my board object, but I'm not sure. I'm in a similar boat to the OP of this post.
public class Game extends Canvas implements MouseListener {
JFrame jf = new JFrame();
Game() {
jf.getContentPane().add(this, BorderLayout.CENTER);
jf.setSize(new Dimension(500,500+30));
jf.setVisible(true);
jf.addMouseListener(this);
}
public void mouseClicked(MouseEvent e){
System.out.println("Hello World!");
}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public static void main(String[] args){
Game game = new Game();
}
}
I suspect but doubt that the mouse listener may not be functioning properly due to it being created in a non-static method, but I doubt that that is the problem. I've tried moving the declaration to the beginning of the constructor, but that didn't help.
The events will only register on the component which has focus. Which, in your program is your main panel, the Game class. So a quick fix would be just to change:
jf.addMouseListener(this);
to
addMouseListener(this);
But you should add the listener to any component you might want to get the events on, i.e. your main panel, the content pane, and jframe too.
The problem was with using Canvas instead of JPanel as the superclass. When I switched, the mouse listener started firing.
I created one JFrame with JDesktopPane, in which I am calling JInternalFrame. Now I want to close that internal frame by pressing escape key.
I tried 2-3 ways, but no output.
I did that by using code given below:
public static void closeWindow(JInternalFrame ji){
ActionListener close=New ActionListener(){
public void actionPerformed(ActionEvent e){
ji.dispose();
}
};
When I called above method from my intern frame class constructor by supplying its object , I was able to close it. But when there I write some other lines of code to the constructor. The above method call doesn't work. Please help me. I unable to find the problem in the code.
Also I tried to add KeyListener to internal frame, so I able to work with key strokes,but it also doesn't work.
Again I tried to setMnemonic to button as escape as below:
jButton1.setMnemonic(KeyEvent.VK_ESCAPE);
But also gives no output.
You need to implement the KeyListener interface, or add one that is Anonymous. In this example, I just implemented it.
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
public class JInternalFrame extends JFrame implements KeyListener {
public JInternalFrame()
{
super();
// other stuff to add to frame
this.setSize(400, 400);
this.setVisible(true);
this.addKeyListener( this );
}
#Override
public void keyTyped(KeyEvent e) {
// Don't need to implement this
}
#Override
public void keyPressed(KeyEvent e) {
if( e.getKeyCode() == KeyEvent.VK_ESCAPE ) {
System.exit(0); //Change this to dispose or whatever you want to do with the frame
}
}
#Override
public void keyReleased(KeyEvent e) {
//Dont need to implement anything here
}
public static void main(String[] args)
{
JInternalFrame frame = new JInternalFrame();
}
}
Now if this is an internal jframe as mentioned, it is probably better to implement the keylistener in the JDesktopPane and call the dispose method on the JInternalFrame after pressing escape instead of implementing keylistener in this frame. It all depends on which GUI component has focus of input.
This issue is old now but I recently got stuck on a similar problem. Adding the key listener to the content pane of the internal frame instead of the internal frame itself did the job for me.
this.getContentPane().addKeyListener(this);
I have a JFrame which needs to be always on top of the other application. For this I am using setAlwaysOnTop() method of Window class.
Here is my code :
class Test1 extends JFrame {
public Test1() {
initComponents();
setTitle("Top Window");
setAlwaysOnTop(true);
}
private void initComponents() {
jLabel1 = new JLabel();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jLabel1.setHorizontalAlignment(SwingConstants.CENTER);
jLabel1.setText("I am a top most window");
getContentPane().add(jLabel1, BorderLayout.CENTER);
pack();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Test1().setVisible(true);
}
});
}
private javax.swing.JLabel jLabel1;
}
This works fine with some of the other application such as notepad, explorer etc, i.e. when my application is above notepad everything works fine.
But when my java application goes above any application that is already on top such as task manager. Then the method setAlwaysOnTop() doesn't works.
What I need is any way through which I can make my application always on top.
I have also searched many other related posts on stackoverflow but none seems to answer my question. I have also tried other ways such as overriding the windowDeactivated(WindowEvent e) method
addWindowListener(new WindowAdapter(){
#Override
public void windowDeactivated(WindowEvent e) {
toFront();
//requestFocus();
//requestFocusInWindow();
}
});
but this also doesn't worked.
Is there any other way through which I can may my JFrame always on top of every other application except in case of full screen applications.
It depends on the operating system. In general, you can't guarantee that your window will always be on top when it comes to native windows, nor should you. The task manager is always-on-top for good reasons.
I remember that some versions of Vista and older Windows systems allowed that and the native and Java windows ended up fighting for focus.
I don't get how can I employ this code:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
to close the program with the x button.
You need the line
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Because the default behaviour for the JFrame when you press the X button is the equivalent to
frame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
So almost all the times you'll need to add that line manually when creating your JFrame
I am currently referring to constants in WindowConstants like WindowConstants.EXIT_ON_CLOSE instead of the same constants declared directly in JFrame as the prior reflect better the intent.
If you don't have it, the JFrame will just be disposed. The frame will close, but the app will continue to run.
Calling setDefaultCloseOperation(EXIT_ON_CLOSE) does exactly this. It causes the application to exit when the application receives a close window event from the operating system. Pressing the close (X) button on your window causes the operating system to generate a close window event and send it to your Java application. The close window event is processed by the AWT event loop in your Java application which will exit the application in response to the event.
If you do not call this method the AWT event loop may not exit the application in response to the close window event but leave it running in the background.
I spent quite a bit of time spelunking through the internet for an elegant solution to this. As is usually the case, I found a lot of conflicting information.
I finally ended with:
Do not use EXIT_ON_CLOSE as this can leave resources behind;
Do use something like the following in the JFrame initialization:
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
The real discovery was how to actually dispatch a window message to the JFrame. As an example, as part of your JMenuItem for exiting the application, use the following, where the function getFrame() returns a reference to the JFrame:
public class AppMenuFileExit extends JMenuItem implements ActionListener
{
// do your normal menu item code here
#Override
public void actionPerformed(ActionEvent e)
{
WindowEvent we;
we = new WindowEvent((Window) App.getFrame(), WindowEvent.WINDOW_CLOSING);
App.getFrame().dispatchEvent(we);
}
}
JFrame is a subclass of Window so may be cast to Window for this purpose.
And, have the following in your JFrame class to handle Window messages:
public class AppFrame extends JFrame implements WindowListener
{
// Do all the things you need to for the class
#Override
public void windowOpened(WindowEvent e)
{}
#Override
public void windowClosing(WindowEvent e)
{/* can do cleanup here if necessary */}
#Override
public void windowClosed(WindowEvent e)
{
dispose();
System.exit(0);
}
#Override
public void windowActivated(WindowEvent e)
{}
#Override
public void windowDeactivated(WindowEvent e)
{}
#Override
public void windowDeiconified(WindowEvent e)
{}
#Override
public void windowIconified(WindowEvent e)
{}
}
If you're using a Frame (Class Extends Frame) you'll not get the
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
If you don't extend JFrame and use JFrame itself in variable, you can use:
frame.dispose();
System.exit(0);
The following code works for me:
System.exit(home.EXIT_ON_CLOSE);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this worked for me in case of Class Extends Frame
What code is called when a JFrame is minimized? Is it hooked up to a listener? I just want to know what happens internally when the frame is minimized.
EDIT:
Im actually looking for the code that is called when the frame is minimized. For example, the code for the actual windowListener. Ive been searching through JFrame, Frame, and Window searching for windowIconified but have been unable to find the actual code.
Reason being, when my program runs, it has a small defect with one of the Panels, but when I minimize and maximize the JFrame, the problem goes away. I wanted to see what was going on so that I can apply whatever is going on to my Panel so it paints right.
you can listening by using WindowListener
for example
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JFrame;
public class WinStateListener implements WindowListener {
static JFrame window = new JFrame("Window State Listener");
public WinStateListener() {
window.setBounds(30, 30, 300, 300);
window.addWindowListener(this);
window.setVisible(true);
}
public static void main(String[] args) {
WinStateListener winStateListener = new WinStateListener();
}
public void windowClosing(WindowEvent e) {
System.out.println("Closing");
window.dispose();
System.exit(0);
}
public void windowOpened(WindowEvent e) {
System.out.println("Opened");
}
public void windowClosed(WindowEvent e) {
System.out.println("Closed");
}
public void windowIconified(WindowEvent e) {
System.out.println("Iconified");
}
public void windowDeiconified(WindowEvent e) {
System.out.println("Deiconified");
}
public void windowActivated(WindowEvent e) {
System.out.println("Activated");
}
public void windowDeactivated(WindowEvent e) {
System.out.println("Deactivated");
}
}
You want to read about WindowListeners and WindowEvents. The event you are talking about is called Iconifying the window. Read more here:
http://download.oracle.com/javase/tutorial/uiswing/events/windowlistener.html
EDIT:
Use revalidate() then repaint() on the JPanel that is acting up.
When minimizing the JFrame application a window event windowIconified is called. If you want to process such window events by your own then either implement WindowListener interface or use WindowAdapter abstract class.
What code is called when a JFrame is minimized?
As noted in How to Make Frames: Specifying Window Decorations, "window decorations are supplied by the native window system." The article goes on to describe some changes you can make to the host platform's default.
Addendum: Reading your update, note that restoring an iconified window repaints it. As #Andrew Thompson points out, you may need to verify that you're building on the event dispatch thread. You may also need to schedule a repaint(). An sscce might clarify things.