使用Enter键而不是单击时,为什么不能使用所有操作按钮功能?

时间:2017-08-26 23:55:20

标签: java swing jbutton enter

我的操作按钮读取JTextField值并更新同一字段,原始值中仅包含数字。它还会自动将数字复制到剪贴板并使JLabel可见,让用户知道它已被复制。只要用户再次在文本字段中键入,该标签就会再次隐藏。

示例:用户输入“abc123cde456”并单击操作按钮。输出为“123456”。将显示一个标签,告知该值已被复制。

我已使用 getRootPane()。setDefaultButton(按钮)将此按钮设为默认值,以便用户可以使用Enter键触发它。问题是,当使用键而不是鼠标单击时,输出和复制到剪贴板工作,但JLabel不可见。

我注意到在按下键之前将焦点设置在JTextField上时,Enter键正常工作,但在我的布局中执行此操作的唯一方法是将鼠标单击按钮顶部并“拖动”到外部,所以焦点转到按钮而不是JTextField,如下所示:

passing focus to button before hitting Enter key

下面的代码 - 顺便说一下,我正在研究NetBeans IDE:

JFrame类

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;

public class FrameZ extends javax.swing.JFrame {

    public FrameZ() {
        initComponents();
        labelCopied.setVisible(false);
        inputTxt.addActionListener(actionButton.getActionListeners()[0]);
        getRootPane().setDefaultButton(actionButton);
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        inputTxt = new javax.swing.JTextField();
        actionButton = new javax.swing.JButton();
        labelCopied = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        inputTxt.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                inputTxtKeyTyped(evt);
            }
        });

        actionButton.setText("Only numbers");
        actionButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                actionButtonActionPerformed(evt);
            }
        });

        labelCopied.setText("Copied!");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGap(0, 0, Short.MAX_VALUE)
                        .addComponent(labelCopied)
                        .addGap(72, 72, 72))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(inputTxt, javax.swing.GroupLayout.PREFERRED_SIZE, 127, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 18, Short.MAX_VALUE)
                        .addComponent(actionButton)
                        .addContainerGap())))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(actionButton)
                    .addComponent(inputTxt, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(labelCopied)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                        

    private void actionButtonActionPerformed(java.awt.event.ActionEvent evt) {                                             

        String inputValue = inputTxt.getText();
        StringBuilder digitsOnly = new StringBuilder();

        for (int i = 0; i < inputValue.length(); i++) {
            char c = inputValue.charAt(i);
            if (Character.isDigit(c)) {
                digitsOnly.append(c);
            }
        }

        inputTxt.setText(digitsOnly.toString());

        //copying to clipboard:
        StringSelection strSelect = new StringSelection(inputTxt.getText());
        Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard();
        clpbrd.setContents(strSelect, null);

        labelCopied.setVisible(true);
    }                                            

    private void inputTxtKeyTyped(java.awt.event.KeyEvent evt) {                                  
            labelCopied.setVisible(false);
    }                                 

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new FrameZ().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JButton actionButton;
    private javax.swing.JTextField inputTxt;
    private javax.swing.JLabel labelCopied;
    }

主要课程

    public class Main {
    public static void main(String args[]){
        FrameZ frm = new FrameZ();

        frm.setVisible(true);
        frm.setResizable(false);
        frm.setLocationRelativeTo(null);
    }
}

1 个答案:

答案 0 :(得分:0)

要解决问题,您需要:

  1. 使用调试器逐步完成代码
  2. 将System.out.println(...)语句添加到您的代码
  3. 上述任何一个都可以帮助您理解逻辑流程,看它是否符合您的期望。

    我没有使用IDE,因此我进行了以下更改以添加一些调试代码:

    private void actionButtonActionPerformed(java.awt.event.ActionEvent evt) {
    System.out.println("action");
    

    private void inputTxtKeyTyped(java.awt.event.KeyEvent evt) {
        System.out.println("hide");
    

    如果您进行了这些更改并在文本字段中键入数据并使用Enter键,您将看到如下输出:

    hide
    hide
    hide
    hide
    action
    hide
    

    为什么会这样?好吧,看来Enter键生成KeyTyped事件,此事件在ActionEvent

    之后处理

    解决此问题的一种方法是包装使标签在SwingUtilities.invokeLater(...)中可见的逻辑。这将导致代码被添加到事件队列的末尾,因此它将在Enter键生成的事件之后执行:

        //labelCopied.setVisible(true);
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                labelCopied.setVisible(true);
            }
        });