java - JList选择随机跳转到前一个索引

标签 java swing jlist

我有一个 JList,我希望能够导航到不同的单元格,键入文本,然后按“Enter”键提交更改。问题是,当我更改几个单元格,然后通过向上和向下键导航并尝试在当前选定的单元格中键入内容时,选择会以某种方式跳转到先前填充的单元格。我已将代码缩减到我认为复制问题的最低限度:

package listtest;

import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.DefaultListModel;
import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class JListSelection{

    static int selectedIndex;
    static JList<String> serials;
    static DefaultListModel<String> model;
    static private JPopupMenu editPopup;
    static private JTextField editTextField;

    public static void main(String[] args) {
        JPanel pan = new JPanel(null);
        selectedIndex = 0;
        serials = new JList<String>();

        model = new DefaultListModel<String>();
        serials = new JList<String>(model);
        for(int i = 0; i < 19; i++) {
            model.addElement(" ");
        }
        serials.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        serials.addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                selectedIndex = serials.getSelectedIndex();
                System.out.println("in listener: " + serials.getSelectedIndex());
            }
        });
        serials.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                System.out.println("In keypressed: " + e.getKeyCode() + " " + serials.getSelectedIndex());
            }
            public void keyReleased(KeyEvent e) {
                int code = e.getKeyCode();
                switch( code ){ 
                    case KeyEvent.VK_UP:
                        System.out.println("UP " + serials.getSelectedIndex());
                        break;
                    case KeyEvent.VK_DOWN:
                        System.out.println("DOWN " + serials.getSelectedIndex());
                        break;
                }
                if(e.getKeyCode() >= KeyEvent.VK_A && e.getKeyCode() <= KeyEvent.VK_Z
        || e.getKeyCode() >= KeyEvent.VK_0 && e.getKeyCode() <= KeyEvent.VK_9) {

                    System.out.println(selectedIndex + " " + serials.getSelectedIndex());
                    Rectangle r = serials.getCellBounds(selectedIndex, selectedIndex);

                    if (editPopup == null) {
                        createEditPopup();
                    }

                    editPopup.setPreferredSize(new Dimension(r.width, r.height));
                    editPopup.show(serials, r.x, r.y);

                    editTextField.setText(
                        serials.getSelectedValue().toString().equals(" ") ? 
                        e.getKeyChar()+"" : serials.getSelectedValue().toString());
                        editTextField.requestFocusInWindow(); 
                }
            }
        });

        serials.setBounds(0, 0, 200, 800);
        pan.add(serials);
        JDialog di = new JDialog();
        di.setContentPane(pan);
        di.pack();
        di.setLocationRelativeTo(null);
        di.setSize(300, 400);
        di.setVisible(true);
    }

    private static void createEditPopup(){
        editTextField = new JTextField();

        editTextField.setBorder(
            UIManager.getBorder("List.focusCellHighlightBorder"));
        editTextField.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                DefaultListModel<String> model = (DefaultListModel<String>) 
                    serials.getModel();
                model.set(selectedIndex, editTextField.getText());
                editPopup.setVisible(false);
            }
        });

        editPopup = new JPopupMenu();
        editPopup.setBorder(new EmptyBorder(0, 0, 0, 0));
        editPopup.add(editTextField);
    }
}

如果您运行代码并首先选择一个单元格并输入一些内容,然后按 Enter 键,它就会按预期工作。如果您随后使用向下箭头键在某个时刻键入一些其他单元格,则选择将跳转到先前选择的单元格,我无法找出任何方法来查看导致此跳转的原因,更不用说阻止它了。 p>

最佳答案

您遇到了 JList 的一项功能。发生的情况是,当您键入每个字符时,JList 会尝试滚动到以您键入的字母开头的条目。 因此,如果您输入“Joe”和“Dave”,然后尝试输入“Jerry”,JList 将选择“Joe”行。

参见:Deactivate selection by letter in JList

遵循该问题的技术:

// Add these lines just before your first "addKeyListener"
for (KeyListener lsnr : serials.getKeyListeners()) {
  if(lsnr.getClass().getSimpleName().equals("Handler")){
    serials.removeKeyListener(lsnr);
  }
}

这些行位于代码示例中的第 47 行之前。 这是取消 JList 自动选择特性的一种粗略方法。

我们要删除的监听器由 installListeners() 方法中的 BasicListUI 添加到 JList 中,如 list.addKeyListener (getHandler())。请参阅 BasicListUI 的源代码。 getHandler() 返回的类是一个包罗万象的监听器,它实现了多个不同的监听器接口(interface),包括 KeyListener,这就是实现自动选择行为的地方。

使用 getSimpleName() 来确定类名的奇怪用法是必要的,因为 HandlerBasicListUI 中的私有(private)类,因此我们可以'不要使用instanceof。 不用说,这些恶作剧会导致代码变得有些脆弱。如果您希望使用这种方法,请确保您对其进行了良好的记录,并准备在迁移到 future 的 Java 版本时修复它。

如果您发现自己在设计这样的组件时遇到困难,那么您可能使用了错误的组件。也许您最好使用单列 JTable

关于java - JList选择随机跳转到前一个索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56586361/

相关文章:

java - 如何在 JScrollPane 中修改 JPanel 的大小?

java - 我不能选择我创建的其他单选按钮?

java - 如何根据选择的按钮从类中调用方法?

java - BorderLayout.CENTER 和 BorderLayout.EAST 之间的 JSeparator?

java - 有没有办法用 JList 获取垂直索引?

java - ListCellRendererComponent() 方法更新 JList 的所有对象(元素),类似于最后添加的元素

java - JList 从 jlist 检索数据

java - Spring boot security,找不到oauth2和thymeleaf静态资源

Java - 整数和二进制

java - 为什么我的单元测试在添加参数后失败?