【问题标题】:FocusListener on editable JCombobox not firing可编辑 JCombobox 上的 FocusListener 未触发
【发布时间】:2013-03-10 15:51:39
【问题描述】:

首先: 抱歉,我无法提供 SSCCE。我试图在一个小项目上重现这个问题,但没有成功,或者我应该说成功,因为它在那里工作!

所以这是我的问题: 我有一个可编辑的 JCombobox,它应该通过单击编辑器组件来监听焦点事件。但事实并非如此。

这是我附加监听器的代码 sn-p:

cmbZoom.setToolTipText(locale.getString("GUI_ZoomFactor"));
cmbZoom.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16));
cmbZoom.setPreferredSize(new Dimension(88, 29));
cmbZoom.setEditable(true);
((JTextField)cmbZoom.getEditor().getEditorComponent()).setHorizontalAlignment(JTextField.CENTER);
cmbZoom.getEditor().getEditorComponent().addFocusListener(
  new FocusListener(){
    public void focusGained(FocusEvent arg0) {
      System.out.println("GAINED");
    }

    public void focusLost(FocusEvent arg0) {
      System.out.println("LOST");
    }
  });

我已经尝试删除组合框上的所有其他侦听器,删除观察者模式,使组合框受到保护并将侦听器附加到每个子项上,...

我也尝试过重新实现它,就像写在这篇文章中一样: JCombobox focusLost is not firing-why is that?

有没有调试事件的好方法?

整个项目可以在 Github 上查看: https://github.com/nexxx/Database-Analyzer

工具栏类可以在这里找到(代码从第 98 行开始): https://github.com/nexxx/Database-Analyzer/blob/master/src/dba/gui/auxClasses/toolBars/ToolBar.java

【问题讨论】:

  • 同一代码在某些情况下会导致问题但在其他情况下不会导致问题的事实使我怀疑您的代码可能未在AWT event dispatch thread上执行。
  • @VGR 非常感谢!这就是问题所在!你能写一个答案,我可以把它标记为已解决。
  • 顺便说一句:找到代码中的错误是你的工作(这是工作小例子和真实事物之间的区别),所以在这里倾倒你所有的代码就赢了没有太大作用。好的一面是:每次挖掘你都会变得更好:-)

标签: java swing jcombobox focuslistener


【解决方案1】:
  • 我建议不要将 FocusListenerItem & DocumentListener 添加到 JComboBox'es Editor 中,这样会造成无限循环

例如,

import java.awt.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.Vector;
import javax.swing.*;
import javax.swing.UIManager;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.metal.MetalComboBoxButton;

public class MyComboBox {

    private Vector<String> listSomeString = new Vector<String>();
    private JComboBox someComboBox = new JComboBox(listSomeString);
    private JComboBox editableComboBox = new JComboBox(listSomeString);
    private JComboBox non_EditableComboBox = new JComboBox(listSomeString);
    private JFrame frame;

    public MyComboBox() {
        listSomeString.add("-");
        listSomeString.add("Snowboarding");
        listSomeString.add("Rowing");
        listSomeString.add("Knitting");
        listSomeString.add("Speed reading");
//
        someComboBox.setPrototypeDisplayValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
        someComboBox.setFont(new Font("Serif", Font.BOLD, 16));
        someComboBox.setEditable(true);
        someComboBox.getEditor().getEditorComponent().setBackground(Color.YELLOW);
        ((JTextField) someComboBox.getEditor().getEditorComponent()).setBackground(Color.YELLOW);
        someComboBox.getEditor().getEditorComponent().addFocusListener(fcsListener);
//
        editableComboBox.setPrototypeDisplayValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
        editableComboBox.setFont(new Font("Serif", Font.BOLD, 16));
        editableComboBox.setEditable(true);
        JTextField text = ((JTextField) editableComboBox.getEditor().getEditorComponent());
        text.setBackground(Color.YELLOW);
        JComboBox coloredArrowsCombo = editableComboBox;
        Component[] comp = coloredArrowsCombo.getComponents();
        for (int i = 0; i < comp.length; i++) {
            if (comp[i] instanceof MetalComboBoxButton) {
                MetalComboBoxButton coloredArrowsButton = (MetalComboBoxButton) comp[i];
                coloredArrowsButton.setBackground(null);
                break;
            }
        }
        editableComboBox.getEditor().getEditorComponent().addFocusListener(fcsListener);
//
        non_EditableComboBox.setPrototypeDisplayValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
        non_EditableComboBox.setFont(new Font("Serif", Font.BOLD, 16));
        non_EditableComboBox.addFocusListener(fcsListener);
//
        frame = new JFrame();
        frame.setLayout(new GridLayout(0, 1, 10, 10));
        frame.add(someComboBox);
        frame.add(editableComboBox);
        frame.add(non_EditableComboBox);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocation(100, 100);
        frame.pack();
        frame.setVisible(true);
    }

    //
    private FocusListener fcsListener = new FocusListener() {

        @Override
        public void focusGained(FocusEvent e) {
            dumpInfo(e);
        }

        @Override
        public void focusLost(FocusEvent e) {
            dumpInfo(e);
        }

        private void dumpInfo(FocusEvent e) {
            final Component c = e.getComponent();
            System.out.println("Source  : " + name(e.getComponent()));
            System.out.println("Opposite : " + name(e.getOppositeComponent()));
            System.out.println("Temporary: " + e.isTemporary());
            if (c instanceof JFormattedTextField) {//works for editable JComboBox too
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        ((JFormattedTextField) c).selectAll();
                    }
                });
            } else if (c instanceof JTextField) {
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        ((JTextField) c).selectAll();
                    }
                });
            } else if (c instanceof JTextField) {
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        ((JComboBox) c).getEditor().selectAll();
                    }
                });
            }
        }

        private String name(Component c) {
            return (c == null) ? null : c.getName();
        }
    };

    public static void main(String[] args) {
        UIManager.put("ComboBox.background", new ColorUIResource(Color.yellow));
        UIManager.put("JTextField.background", new ColorUIResource(Color.yellow));
        UIManager.put("ComboBox.selectionBackground", new ColorUIResource(Color.magenta));
        UIManager.put("ComboBox.selectionForeground", new ColorUIResource(Color.blue));
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                MyComboBox aCTF = new MyComboBox();
            }
        });
    }
}

【讨论】:

    【解决方案2】:

    相同的代码在某些情况下会导致问题,但在其他情况下不会导致问题,这让我怀疑您的代码可能没有在 AWT event dispatch thread 上执行。

    【讨论】:

    • 准确地说,为了在这个线程上分发你的事件,把你的事件主体包含在里面: SwingUtilities.invokeLater(new Runnable() { public void run() { /* event body here */ }});
    猜你喜欢
    • 2010-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-10
    相关资源
    最近更新 更多