JApplet & KeyListener

Posted

技术标签:

【中文标题】JApplet & KeyListener【英文标题】: 【发布时间】:2012-11-02 00:39:29 【问题描述】:

我正在为我的计算机科学课程开发一个应用程序。任务是编写一个计算器,但不使用JTextFields 或JTextAreas。我想出了一个实现KeyListener 的想法,它在appletviewer 和JFrame 中都很好用,但在Google Chrome 中根本不起作用(可能还有其他浏览器)。

这是我的代码 sn-ps。

//- BinaryCalc.java
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;

public class BinaryCalc extends JApplet implements KeyListener 

    private JPanel panel;

    public BinaryCalc() 
        super();

        panel = new JPanel();
        this.add(panel);

        panel.addKeyListener(this);
        panel.requestFocusInWindow();
    

    @Override
    public void init() 
        JOptionPane.showMessageDialog(this, "applet");
        panel.setFocusable(true);
        panel.requestFocus();
    

    public void keyPressed(KeyEvent e) 
        JOptionPane.showMessageDialog(this, (char) e.getKeyCode());
    

    public void keyReleased(KeyEvent e) 

    public void keyTyped(KeyEvent e) 

    public JPanel getPanel()  return panel; 

    public static void main(String args[]) 
        JFrame frame = new JFrame("Binary Calculator");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setMinimumSize(new Dimension(320, 240));

        BinaryCalc kalkulator = new BinaryCalc();
        frame.add(kalkulator);

        frame.pack();
        frame.setVisible(true);
        kalkulator.getPanel().requestFocusInWindow();
    


还有包含我的小程序的 html 文件。

<!doctype html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel="stylesheet" type="text/css" href="style.css">
    <title>Kalkulator binarny</title>
</head>

<body>
    <div style="text-align: center; border-bottom: 1px solid black">
        <h1>Kalkulator Binarny</h1>
    </div>

    <br/>
    <object style="display: block; margin: auto;" type="application/x-java-applet"  >
    <param name="code" value="BinaryCalc.class" />
    <!--- <param name="archive" value="Liczba.jar" /> -->
        What a terrible failure: applet failed to load!
    </object>   
    <br/>
</body>

</html>

有什么想法吗?

【问题讨论】:

@DavidKroukamp 只是“应该”还是“必须”?顺便说一句,我的 sn-ps 是 SSCCE :) 必须! KeyListener 很旧,并且在焦点等方面存在问题。我建议仅在您期望键盘上的任何键发生事件时才使用 KeyListener,甚至始终确保您要求关注 keylistener 所在的组件附上以避免更多问题 @DavidKroukamp 你的想法和我的 KeyListener 一样,意味着它在浏览器中不起作用。 你看到我的回答了吗?导致您的 sn-ps anamolies 的代码有很多问题 如果你把JPanel换成JFrame看看效果会更好。 【参考方案1】:

使用KeyBindings 而不是KeyListener

不要为JApplet 创建自己的JFrame,只需在applet 实例上调用getContentPane() 并将所有组件添加到那里。

所有组件都应在 JApplet 覆盖 init() 方法中创建,并包裹在 SwingUtilities#invokeAndWait(..) 块中

JApplets 和 Applets 没有 main(..) 方法(除了测试目的)

使用requestFocusInWindow() 而不是requestFocus()

我强烈建议您阅读:

How to Make Applets JApplet tutorial

这是一个适合我的例子。它只是将不可编辑的JTextField 添加到JPanel,然后将KeyBindings 添加到KeyEvent.VK_0KeyEvent.VK_1JPanel。如果用户键入 01,它将显示在不可编辑的 JTextField:

import java.awt.BorderLayout;
import java.awt.event.*;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

public class BinaryCalc extends JApplet 

    private JTextField jtf;

    @Override
    public void init() 
        try 
            SwingUtilities.invokeAndWait(new Runnable() 
                @Override
                public void run() 

                    JPanel panel = new JPanel();
                    setKeyBindings(panel);
                    jtf = new JTextField(10);
                    //so we cant edited it without pressing a key
                    jtf.setEditable(false);

                    panel.add(jtf);
                    getContentPane().add(panel, BorderLayout.CENTER);
                    panel.requestFocusInWindow();//incase we lost focus
                
            );
         catch (InterruptedException ex) 
            Logger.getLogger(BinaryCalc.class.getName()).log(Level.SEVERE, null, ex);
         catch (InvocationTargetException ex) 
            Logger.getLogger(BinaryCalc.class.getName()).log(Level.SEVERE, null, ex);
        
    

    private void setKeyBindings(final JPanel panel) 
        panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_0,0), "0");
        panel.getActionMap().put("0", new AbstractAction() 
            @Override
            public void actionPerformed(ActionEvent ae) 
                String tmp = jtf.getText();
                jtf.setText(tmp + "0");
            
        );
        panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_1,0), "1");
        panel.getActionMap().put("1", new AbstractAction() 
            @Override
            public void actionPerformed(ActionEvent ae) 
                String tmp = jtf.getText();
                jtf.setText(tmp + "1");
            
        );
    

【讨论】:

如果您将 JTextField(我不能使用)更改为 JLabel,上面的代码似乎不起作用。此外,即使使用 JTextField 它也不起作用。 @Robin92 不确定问题出在哪里,编辑了我的代码 sn-p。前面的观点仍然存在 +1 用于键绑定; hybrid 在开发过程中可能会更容易。 问题似乎是由 IcedTea 造成的。无论如何感谢您的帮助:) @Robin92:David 的代码似乎适用于JLabel,如here 所示。你得到了不同的结果吗?【参考方案2】:

我冒昧地将@David 的有用示例转换为使用标签和数字键盘。

更新:这个hybrid 在 Ubuntu/OpenJDK 上工作,它可以通过Java Web Start 部署。

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.*;
import javax.swing.*;

/**
 * @see https://***.com/a/13363349/230513
 */
public class BinaryCalc extends JApplet 

    private static BinaryCalc bc = new BinaryCalc();
    private JLabel label = new JLabel("0000000000");

    public static void main(String[] args) 
        EventQueue.invokeLater(new Runnable() 

            @Override
            public void run() 
                JFrame frame = new JFrame();
                frame.setTitle("BinaryCalc");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                initContainer(frame);
                frame.pack();
                bc.label.setText("");
                frame.setVisible(true);
            
        );
    

    // Common initialization for either JApplet or JFrame
    private static void initContainer(Container container) 
        JPanel panel = new JPanel();
        bc.setKeyBindings(panel);
        panel.add(bc.label);
        container.add(panel, BorderLayout.CENTER);
        panel.requestFocusInWindow();
    

    @Override
    public void init() 
        SwingUtilities.invokeLater(new Runnable() 

            @Override
            public void run() 
                initContainer(BinaryCalc.this);
            
        );
    

    private void setKeyBindings(final JPanel panel) 
        panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
            .put(KeyStroke.getKeyStroke(KeyEvent.VK_0, 0), "0");
        panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
            .put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD0, 0), "0");
        panel.getActionMap().put("0", new AbstractAction() 

            @Override
            public void actionPerformed(ActionEvent ae) 
                String tmp = label.getText();
                label.setText(tmp + "0");
            
        );
        panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
            .put(KeyStroke.getKeyStroke(KeyEvent.VK_1, 0), "1");
        panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
            .put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD1, 0), "1");
        panel.getActionMap().put("1", new AbstractAction() 

            @Override
            public void actionPerformed(ActionEvent ae) 
                String tmp = label.getText();
                label.setText(tmp + "1");
            
        );
    

【讨论】:

请考虑accepting @David Kroukamp 的answer,因为它先于我自己的。 +1 很棒,我不知何故无法让标签工作,只有 JTextField,因为我忘了打电话给requestFocusInWindow()。感谢您修复它,我已经绞尽脑汁好几个小时了 :) JApplet - init() 的覆盖方法应将其代码包装在 invokeAndWait 块中。 (请参阅我的回答)

以上是关于JApplet & KeyListener的主要内容,如果未能解决你的问题,请参考以下文章

一道Java编程题

第十三周学习总结&实验报告

查找JApplet的宽度和高度

JApplet:设置框架的大小

无法设置 JApplet 背景颜色

在具有不断重绘的 JPanel 的 JApplet 中使用组件