JApplet и KeyListener

Я разрабатываю приложение для моих занятий по информатике. Задача состоит в том, чтобы написать калькулятор, но без использования JTextFields или JTextAreas. Мне пришла в голову идея реализовать KeyListener, который хорошо работает как в appletviewer, так и в JFrame, но совсем не работает в Google Chrome (и, возможно, в других браузерах).

Вот мои фрагменты кода.

//- 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" width="320" height="240">
    <param name="code" value="BinaryCalc.class" />
    <!--- <param name="archive" value="Liczba.jar" /> -->
        What a terrible failure: applet failed to load!
    </object>   
    <br/>
</body>

</html>

Есть идеи?


person Robin92    schedule 13.11.2012    source источник
comment
@DavidKroukamp это просто должно или должно? Кстати, мои фрагменты SSCCE :)   -  person Robin92    schedule 13.11.2012
comment
должен! KeyListener устарел и имеет проблемы с фокусом и т. д. Я бы предложил использовать KeyListener только тогда, когда вы ожидаете события от любой клавиши на клавиатуре, и даже всегда убедитесь, что вы вызываете фокус на компоненте, к которому подключен keylistener, чтобы избежать больше проблем   -  person David Kroukamp    schedule 13.11.2012
comment
@DavidKroukamp Ваша идея работает так же, как мой KeyListener, то есть не работает в браузере.   -  person Robin92    schedule 13.11.2012
comment
Вы видели мой ответ? есть много вещей, которые не так с кодом, способствующим анамолии ваших фрагментов   -  person David Kroukamp    schedule 13.11.2012
comment
Было бы лучше, если бы вы заменили JPanel на JFrame и посмотрели, как это работает.   -  person Roman C    schedule 13.11.2012


Ответы (2)


Я настоятельно рекомендую вам прочитать:

Вот пример работает для меня. Он просто добавляет нередактируемый JTextField к JPanel, а затем добавляет KeyBindings к KeyEvent.VK_0 и KeyEvent.VK_1 к JPanel. Если пользователь введет 0 или 1, он будет отображаться в нередактируемом формате 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");
            }
        });
    }
}
person David Kroukamp    schedule 13.11.2012
comment
если вы измените JTextField (который я не могу использовать) на JLabel, приведенный выше код, похоже, не работает. Более того, даже с JTextField это не работает. - person Robin92; 13.11.2012
comment
@Robin92 Робин92 не уверен, в чем проблема, отредактировал мой фрагмент кода. Предыдущие пункты остаются в силе - person David Kroukamp; 13.11.2012
comment
+1 за привязки клавиш; гибрид может быть проще во время разработки. - person trashgod; 13.11.2012
comment
похоже, что проблема создана IcedTea. Спасибо за помощь в любом случае :) - person Robin92; 13.11.2012
comment
@Robin92: Код Дэвида, похоже, работал с JLabel, как показано здесь. Вы получаете другой результат? - person trashgod; 13.11.2012
comment
@trashgod Да, мой код (в вопросе) отлично работает в Windows, но в Linux он не работает в браузере. Однако, что касается этого фрагмента кода, он не работает в Linux и не тестировался в Windows. Я полагаю, что есть проблема с IcedTea... - person Robin92; 14.11.2012
comment
@Robin92: я отказался от апплета в пользу приложения и javawebstart, как предлагается в этом вариант. - person trashgod; 14.11.2012

Я позволил себе преобразовать полезный пример @David, чтобы использовать метку и цифровую клавиатуру.

Обновление: этот гибрид работает в 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://stackoverflow.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");
            }
        });
    }
}
person trashgod    schedule 13.11.2012
comment
Пожалуйста, рассмотрите возможность принятия @David Kroukamp ответ, поскольку он предшествует моему собственному. - person trashgod; 13.11.2012
comment
+1 отлично, я почему-то не мог заставить работать метку, только JTextField, и все потому, что я забыл позвонить requestFocusInWindow(). Спасибо за исправление, это уже несколько часов ломает мне голову :) - person David Kroukamp; 13.11.2012
comment
код переопределенного метода JApplet - init() должен быть заключен в блок invokeAndWait. (см. мой ответ для меня) - person David Kroukamp; 15.11.2012