JPopupMenu 没有像它应该的那样消失

JPopupMenu doesn't disappear like it should

我有一个用于 运行 锦标赛的 Java 应用程序,我在其中构建了一个自动建议功能,该功能从数据库中获取名称并将它们显示在 JPopupMenu 中。我无法按需复制此错误,但有时 JPopupMenus 中的一个会像往常一样消失,除了它所在位置的轮廓仍在屏幕上并显示在所有内容上,甚至包括其他程序如果我的应用程序被最小化。

这是我正在谈论的内容的屏幕截图:

您可以看到在 "Espinoza" 下面仍然显示 JPopupMenu 的一些残余。这有时在内部包含文本,而其他时候仅在空框中具有背景色。这个残余物纯粹是装饰性的,我还没有找到任何物理或编程方式(热编码)与之交互的方法。

这是我用来显示 JPopupMenu 的方法:

private void resetLastNamePopup() {

    Thread t = new Thread() {

        @Override
        public void run() {

            lnPopup.setVisible(false);
            lnPopup.removeAll();

            if(DBHSDatabaseIntermediary.isConnected()) {

                if(!(fnTextField.getText().equals("") && lnTextField.getText().equals(""))) {

                    JMenuItem item = null;
                    String[] names = DBHSDatabaseIntermediary.getLastNames(fnTextField.getText(), lnTextField.getText());
                    for(int i=0; i < names.length; i++) {

                        if(!names[i].equals(lnTextField.getText().trim())) {

                            item = new JMenuItem(names[i]);
                            item.addActionListener(lnActionListener);
                            item.addMouseListener(NewPlayerPanel.this);
                            lnPopup.add(item);

                        }

                    }

                    if(names.length > 0 && !names[0].equals("")) {

                        lnPopup.setVisible(true);

                    }
                    lnPopup.grabFocus();

                }

            }

        }// ends run()

    };

    t.start();

}

提前致谢。

必须在 AWT 事件分派线程上调用 Swing 方法和构造函数。您正在不同的线程上调用这些方法。结果是“未定义的行为”——这通常意味着事情有时会奏效,但并非总是如此。

您需要将 Swing 调用与数据库调用分开,这是使用 EventQueue.invokeLater (or its alias, SwingUtilities.invokeLater):

private void resetLastNamePopup() {

    lnPopup.setVisible(false);
    lnPopup.removeAll();

    final String fn = fnTextField.getText();
    final String ln = lnTextField.getText();

    Thread t = new Thread() {

        @Override
        public void run() {
            if(DBHSDatabaseIntermediary.isConnected()
                    && !fn.isEmpty() && !ln.isEmpty()) {

                final String[] names =
                    DBHSDatabaseIntermediary.getLastNames(fn, ln);

                // Rebuild JPopupMenu in AWT event thread.
                EventQueue.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        for (String name : names) {
                            if (!name.equals(ln)) {
                                JMenuItem item = new JMenuItem(name);
                                item.addActionListener(lnActionListener);
                                lnPopup.add(item);
                            }
                        }

                        if (names.length > 0 && !names[0].isEmpty()) {
                            lnPopup.setVisible(true);
                            lnPopup.grabFocus();
                        }
                    }
                });
            }
        }// ends run()

    };
    t.start();
}

有关详细信息,请参阅 Java 教程中的 javax.swing package contract, and Concurrency in Swing