Java Swing — фокус JDialog по умолчанию

Я нашел в Интернете такую ​​информацию:

«Когда JDialog (или JFrame, если на то пошло) становится видимым, фокус по умолчанию помещается на первый компонент, на который можно сфокусироваться».

Рассмотрим такой код:

public class MyDialog extends JDialog{
    // Dialog's components:
    private JLabel dialogLabel1 = new JLabel("Hello");
    private JLabel dialogLabel2 = new JLabel("Message");
    private JButton dialogBtn = new JButton("Sample Btn text");

    public MyDialog(JFrame parent, String title, ModalityType modality){
        super(parent, title, modality);
        dialogBtn.setName("Button");    //
        dialogLabel1.setName("Label1"); // - setting names
        dialogLabel2.setName("Label2"); //
        setTitle(title);
        setModalityType(modality);
        setSize(300, 100);
        setLocation(200, 200);
        // adding comps to contentPane
        getContentPane().add(dialogLabel1, BorderLayout.PAGE_START);
        getContentPane().add(dialogBtn, BorderLayout.CENTER);
        getContentPane().add(dialogLabel2, BorderLayout.PAGE_END);
        pack();
    }

    public void showDialog(){
        setVisible(true);
        listComps(rootPane.getComponents());
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    }

    /*
     * Itereates through all subcomps recursively and displays some relevant info
     * OUTPUT FORM:  ComponentName | isFocusable | hasFocus
     */
    private void listComps(Component[] comps){
        if(comps.length == 0) return;  
        for(Component c : comps){       
            JComponent jC = (JComponent)c;
            System.out.println(jC.getName() + " | " + jC.isFocusable() +" | " + jC.hasFocus());
            listComps(jC.getComponents());
        }    
    }

    public static void main(String[] args) {
        final JFrame frame = new JFrame();
        frame.setPreferredSize(new Dimension(300, 400));
        frame.setVisible(true);
        JButton btn = new JButton("Show dialog");
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                    MyDialog dialog = new MyDialog(frame, "Sample title", ModalityType.APPLICATION_MODAL);
                    dialog.showDialog();
            }
        });
        frame.add(btn, BorderLayout.CENTER);
        frame.pack();
    }
}

Вывод: запустить:

null.glassPane | true | false
null.layeredPane | true | false
null.contentPane | true | false
Label1 | true | false
Button | true | true
Label2 | true | false

Почему фокус установлен на JButton ?? Это не первый фокусируемый компонент! Когда я удалил JButton, фокус не был перенесен ни на один компонент. Почему? Все композиции по умолчанию фокусируются...


person guitar_freak    schedule 24.07.2013    source источник
comment
Что значит сосредоточить внимание на ярлыке? Кажется, что кнопка — единственный компонент, для которого имеет смысл фокусироваться.   -  person Vincent van der Weele    schedule 24.07.2013
comment
хороший вопрос, создание нового контейнера верхнего уровня (на основе pers из Native OS) - довольно сложное и долгое действие, 1. требуется обернуть в invokeLater == Oracle tutorial Concurency in Swing - Initial Tread, 2. или упаковать и установитьVisible(true ), 3. используйте кодовые теги   -  person mKorbel    schedule 24.07.2013
comment
Просто напишите dialogLabel1.requestFocusInWindow(); в конце конструктора MyDialog(), тогда JLabel получит фокус вместо JButton...   -  person nIcE cOw    schedule 24.07.2013
comment
@Heuster Я спрашиваю, потому что, когда я регистрирую некоторые события keyStrokeEvents в inputMap rootPane с помощью WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, у меня возникает проблема, когда внутри моего диалога есть только JLabels. KeyStroke в этом случае не будет прецессироваться, так как не имеет связи с фокусом. В этом случае необходимо искусственно установить label.setFocusable(true). Но, наверное, это единственный способ   -  person guitar_freak    schedule 24.07.2013
comment
@nIcEcOw Спасибо, это именно то, чем я сейчас занимаюсь, но я подумал, что, возможно, есть какое-то другое решение;)   -  person guitar_freak    schedule 24.07.2013
comment
@guitar_freak: На самом деле JLabel в основном используется для отображения Text or Images. На самом деле он не используется для выполнения какого-либо действия, как уже отмечал Хеустер. Пока сложно сказать, зачем именно вам нужен JLabel для получения фокуса, при отсутствии знания того, что именно требуется. Может быть, есть подход, о котором вы не думаете :-) В остальном ПРИВЕТСТВУЙТЕ и ПРОДОЛЖАЙТЕ УЛЫБАТЬСЯ :-)   -  person nIcE cOw    schedule 24.07.2013


Ответы (2)


Это не первый фокусируемый компонент! Когда я удалил JButton, фокус не был перенесен ни на один компонент. Почему? Все композиции по умолчанию доступны для фокусировки.

Чтобы ответить на вопрос, почему: это решение FocusTraversalPolicy, в частности accept(..) в DefaultFocusTraversalPolicy, которое в конечном итоге возвращается к фиктивному NullComponentPeer (который по умолчанию не фокусируется, поскольку на самом деле не существует :-)

Из вашего комментария похоже, что реальный вопрос может заключаться в том, «как реализовать keyBindings, если у rootPane нет фокусируемых дочерних элементов» - если это так, варианты

  • используйте компонент componentInputMap rootPane, то есть WHEN_IN_FOCUSED_WINDOW
  • заставить сам rootPane быть сфокусированным (вероятно, лучше всего делать это только в том случае, если нет фокусируемых дочерних элементов)
person kleopatra    schedule 24.07.2013
comment
Я никогда не видел JDialog (украшенный или нет) с родителем (модальным/модальным или включенным), который потерял фокус, даже есть только JLabels, пожалуйста, или пропустите, я что-то - person mKorbel; 24.07.2013
comment
@mKorbel ?? - извините, не понимаю, что вы имеете в виду - person kleopatra; 24.07.2013
comment
если я понимаю, что у OP есть проблема с фокусом JDialogs, то он / она пробовал любой ZOO со своими дочерними элементами (есть несколько вопросов с новым ядром unix или linux на Java7 (Open JDK)) или я неправильно прочитал и не понимаю ?? ? - person mKorbel; 24.07.2013
comment
@mKorbel без каких-либо действительно фокусируемых дочерних элементов, диалоговое окно является focusOwner, что является проблемой, поскольку диалоговое окно не является дочерним элементом rootPane, поэтому привязки компонентов, когда-предок-сфокусированного, не будут активированы (вот как я понимаю ОП, может быть, конечно, неправильно :) - person kleopatra; 24.07.2013

Взгляните на JLabel javadoc В нем говорится :

Область отображения для короткой текстовой строки или изображения, или того и другого. Метка не реагирует на входные события. В результате он не может получить фокус клавиатуры

Думаю, именно по этой причине ваш лейбл не получает внимания.

person mael    schedule 24.07.2013
comment
Странность - это возвращаемое значение isFocusable() - person kiheru; 24.07.2013