java 每次更新JPopupMenu时,JTextField都会失去焦点

7uzetpgm  于 2023-03-28  发布在  Java
关注(0)|答案(2)|浏览(140)

每当我在搜索栏中输入一个字符时,我都必须再次手动单击搜索栏以保持焦点。

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;
import java.awt.event.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;

public class SearchTextField extends JTextField {
    private JPopupMenu searchResultPopup;
    private SearchPOI searchPOI;

    public SearchTextField(SearchPOI searchPOI) {
        this.searchPOI = searchPOI;
        searchResultPopup = new JPopupMenu();

        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if (!isNavigationKey(e)) {
                    updatePOIList();
                }
            }
        });

        searchResultPopup.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentHidden(ComponentEvent e) {
                SwingUtilities.invokeLater(() -> requestFocusInWindow());
            }
        });
    }

    private boolean isNavigationKey(KeyEvent e) {
        return e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN
                || e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_ESCAPE;
    }

private void updatePOIList() {
    String searchText = getText();
    List<PointOfInterest> pois;
    if (searchText.isEmpty()) {
        pois = searchPOI.getAllPOIs();
    } else {
        pois = searchPOI.searchForPOI(searchText);
    }

    searchResultPopup.removeAll();
    for (PointOfInterest poi : pois) {
        JMenuItem menuItem = new JMenuItem(poi.getName());
        menuItem.addActionListener(e -> {
            setText(poi.getName());
            searchResultPopup.setVisible(false);
            requestFocusInWindow(); // request focus after selecting an item
        });
        searchResultPopup.add(menuItem);
    }

    if (!pois.isEmpty()) {
        searchResultPopup.show(this, 0, this.getHeight());
    } else {
        searchResultPopup.setVisible(false);
        requestFocusInWindow(); // request focus after hiding the popup
    }
}
}

我试过使用JCombobox,但不起作用,我也试过FocusListener。每当我尝试使用requestFocus时,搜索栏都会保持焦点,但弹出菜单不能正确更新。

bq3bfh9z

bq3bfh9z1#

我不确定你到底想实现什么样的行为,但根据我所收集的信息,我成功地使用了一个可编辑的JComboBox:

import java.util.Arrays;
import java.util.Objects;

import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JFrame;

import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;

import javax.swing.text.JTextComponent;

import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;

public class SearchField {
    private static final String[] VALUES = {
        "Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta",
        "Iota", "Kappa", "Lambda", "Mu", "Nu", "Xi", "Omicron", "Pi", "Rho",
        "Sigma", "Tau", "Upsilon", "Phi", "Chi", "Psi", "Omega"
    };

    private final JComboBox<String> field;

    private boolean updatingList;

    public SearchField() {
        field = new JComboBox<>(VALUES);
        field.setEditable(true);
        field.getEditor().setItem("");
        field.addActionListener(e ->
            EventQueue.invokeLater(() -> field.hidePopup()));

        JTextComponent editor =
            (JTextComponent) field.getEditor().getEditorComponent();
        editor.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent event) {
                EventQueue.invokeLater(() -> restrictValues(field));
            }

            @Override
            public void removeUpdate(DocumentEvent event) {
                EventQueue.invokeLater(() -> restrictValues(field));
            }

            @Override
            public void changedUpdate(DocumentEvent event) {
                EventQueue.invokeLater(() -> restrictValues(field));
            }

        });
    }

    public JComponent component() {
        return field;
    }

    private String[] readValues(String target) {
        if (target == null || target.isEmpty()) {
            return VALUES;
        } else {
            return Arrays.stream(VALUES)
                .filter(v -> v.toLowerCase().contains(target))
                .toArray(String[]::new);
        }
    }

    void restrictValues(JComboBox<String> field) {
        if (updatingList) {
            return;
        }

        String editorValue =
            Objects.toString(field.getEditor().getItem(), "").strip();

        updatingList = true;

        String target = editorValue.toLowerCase();
        String[] newValues = readValues(target);

        field.setModel(new DefaultComboBoxModel<String>(newValues));
        field.getEditor().setItem(editorValue);
        field.showPopup();

        EventQueue.invokeLater(() -> {
            updatingList = false;
        });
    }

    static void show() {
        SearchField field = new SearchField();

        JPanel panel = new JPanel(new BorderLayout());
        panel.add(field.component());
        panel.setBorder(BorderFactory.createEmptyBorder(24, 24, 24, 24));

        JFrame frame = new JFrame("Search Field");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(panel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> show());
    }
}
plupiseo

plupiseo2#

您可以在更新JPopMenu后尝试调用requestFocusInWindow()函数。

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;
import java.awt.event.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;

public class SearchTextField extends JTextField {
    private JPopupMenu searchResultPopup;
    private SearchPOI searchPOI;

    public SearchTextField(SearchPOI searchPOI) {
        this.searchPOI = searchPOI;
        searchResultPopup = new JPopupMenu();

        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if (!isNavigationKey(e)) {
                    updatePOIList();
                }
            }
        });

        searchResultPopup.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentHidden(ComponentEvent e) {
                SwingUtilities.invokeLater(() -> requestFocusInWindow());
            }
        });
    }

    private boolean isNavigationKey(KeyEvent e) {
        return e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN
                || e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_ESCAPE;
    }

private void updatePOIList() {
    String searchText = getText();
    List<PointOfInterest> pois;
    if (searchText.isEmpty()) {
        pois = searchPOI.getAllPOIs();
    } else {
        pois = searchPOI.searchForPOI(searchText);
    }

    searchResultPopup.removeAll();
    for (PointOfInterest poi : pois) {
        JMenuItem menuItem = new JMenuItem(poi.getName());
        menuItem.addActionListener(e -> {
            setText(poi.getName());
            searchResultPopup.setVisible(false);
        });
        searchResultPopup.add(menuItem);
    }
    requestFocusInWindow();

    if (!pois.isEmpty()) {
        searchResultPopup.show(this, 0, this.getHeight());
    } else {
        searchResultPopup.setVisible(false);
        requestFocusInWindow(); // request focus after hiding the popup
    }
}
}

相关问题