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

这是我正在谈论的屏幕截图:
java - JPopupMenu不会像应有的那样消失-LMLPHP

您可以看到在“ 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(或其别名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 contractConcurrency in Swing

关于java - JPopupMenu不会像应有的那样消失,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38444405/

10-10 19:27