Spec-Zone .ru
спецификации, руководства, описания, API
След: Создание GUI С JFC/Swing
Урок: Использование Других Функций Swing
Как Использовать Подсистему Фокуса
Домашняя страница > Создание GUI С JFC/Swing > Использование Других Функций Swing

Как Использовать Подсистему Фокуса

Много компонентов ⠀” даже теми, которыми прежде всего управляют с мышью, такие как кнопки ⠀” можно управлять с клавиатурой. Для нажатия клавиши, чтобы влиять на компонент, у компонента должен быть клавиатурный фокус.

С точки зрения пользователя компонент с клавиатурным фокусом является обычно видным ⠀” с точечной или черной границей, например. Окно, содержащее компонент, является также более видным чем другие экранные окна. Эти визуальные индикаторы, которым сообщают пользователь, к которому компоненту будет иметь отношение любой ввод. Только у одного компонента за один раз в оконной системе может быть клавиатурный фокус.

Точно, как окно получает, фокус зависит от системы управления окнами. Нет никакого надежного способа через все платформы, гарантировать, что окно получает фокус. На некоторых операционных системах, таких как Microsoft Windows, переднее окно обычно становится фокусируемым окном. В этих случаях, Window.toFront метод перемещает окно в переднюю сторону, таким образом давая это фокус. Однако, на других операционных системах, таких как Операционная система Solaris™, менеджер окон может выбрать фокусируемое оконное на позиции курсора, и в этих случаях поведение Window.toFront метод отличается.

Компонент обычно получает фокус, когда пользователь щелкает по этому, или когда пользовательские вкладки между компонентами, или иначе взаимодействует с компонентом. Компоненту можно также дать фокус программно, такой как тогда, когда его содержание фрейма или диалогового окна делается видимым. Этот фрагмент кода шоу, как дать определенному компоненту фокус каждый раз окно, получает фокус:

//Make textField get the focus whenever frame is activated.
frame.addWindowFocusListener(new WindowAdapter() {
    public void windowGainedFocus(WindowEvent e) {
        textField.requestFocusInWindow();
    }
});

Если Вы хотите гарантировать, что определенный компонент получает фокус в первый раз, когда окно активируется, можно вызвать requestFocusInWindow метод на компоненте после компонента был понят, но прежде, чем фрейм будет выведен на экран. Следующий пример кода показывает, как эта работа может быть сделана:

    //...Where initialization occurs...
    JFrame frame = new JFrame("Test");
    JPanel panel = new JPanel(new BorderLayout());

    //...Create a variety of components here...

    //Create the component that will have the initial focus.
    JButton button = new JButton("I am first");
    panel.add(button);
    frame.getContentPane().add(panel);  //Add it to the panel

    frame.pack();  //Realize the components.
    //This button will have the initial focus.
    button.requestFocusInWindow(); 
    frame.setVisible(true); //Display the window.

Альтернативно, можно применить пользовательское FocusTraversalPolicy к фрейму и вызову getDefaultComponent метод, чтобы определить, какой компонент получит фокус.


Примечание версии: Этот раздел описывает архитектуру фокуса, реализованную в JDK 1.4. До этих 1.4 выпусков, JComponent методы, такой как setNextFocusableComponent, getNextFocusableComponent, requestDefaultFocus, и isManagingFocus, использовались, чтобы управлять клавиатурным фокусом. Эти методы теперь осуждаются. Другой метод, requestFocus, обескураживается, потому что это пытается дать фокус окну компонента, которое не всегда возможно. С JDK 1.4, следует вместо этого использовать requestFocusInWindow метод, который не пытается сделать окно компонента фокусируемым. Метод возвращает булево значение, указывающее ли метод, за которым следуют.

Остальная часть этого раздела затрагивает следующие темы:

Введение в Подсистему Фокуса

Подсистема фокуса разрабатывается, чтобы сделать правильную вещь настолько незримо насколько возможно. В большинстве случаев это ведет себя разумным способом, и если это не делает можно настроить его поведение различными способами. Некоторые общие сценарии могли бы включать:

FocusConceptsDemo пример иллюстрирует несколько понятий.

Пример FocusConceptsDemo

Попробуйте это: 
  1. Нажмите кнопку Launch, чтобы работать, FocusConceptsDemo, используя Сеть Java™ Запускаются (загрузите JDK 6 или позже). Альтернативно, чтобы скомпилировать и выполнить пример самостоятельно, консультируйтесь, пример индексируют.Запускает приложение FocusConceptsDemo
  2. В случае необходимости щелкните по окну, чтобы дать этому фокус.
  3. Переместите фокус от компонента до компонента, используя клавишу Tab.
    Вы заметите, что, когда фокус перемещается в текстовую область, это остается в текстовой области.
  4. Переместите фокус из Вкладки управления использования текстовой области.
  5. Переместите фокус в противоположное направление, используя Shift-Tab.
  6. Переместите фокус из текстовой области на Вкладке сдвига управления использования противоположного направления.

KeyboardFocusManager критический элемент подсистемы фокуса. Это управляет состоянием и инициирует изменения. Менеджер по клавиатуре отслеживает владельца фокуса ⠀” компонент, который получает ввод от клавиатуры. Фокусируемое окно является окном, которое содержит владельца фокуса.


JWindow и фокус: использовать a JWindow компонент в Вашем GUI, следует знать что JWindow фрейм обладания компонента должен быть видимым для любых компонентов в окне, чтобы получить фокус. По умолчанию, если Вы не определяете фрейм обладания для a JWindow компонент, невидимый фрейм обладания создается для этого. Результат - это компоненты в JWindow компонент не мог бы быть в состоянии получить фокус. Решение состоит в том, чтобы или определить видимый фрейм обладания, создавая JWindow компонент, или использовать неукрашенный JFrame компонент вместо этого.

Цикл фокуса (или цикл обхода фокуса) являются рядом компонентов, которые совместно используют общего предка в иерархии включения. Корень цикла фокуса является контейнером, который является корнем для определенного цикла обхода фокуса. По умолчанию, каждый JWindow и JInternalFrame компонент может быть корнем цикла фокуса. Корень цикла фокуса может самостоятельно содержать один или более корней цикла фокуса. Следующие объекты Swing могут быть корнями цикла фокуса: JApplet, JDesktopPane, JDialog, JEditorPane, JFrame, JInternalFrame, и JWindow. В то время как это могло бы казаться это JTable и JTree объекты являются корнями цикла фокуса, они не.

Политика обхода фокуса определяет порядок, в котором группа компонентов перемещаются. Swing обеспечивает LayoutFocusTraversalPolicy class, который решает порядок навигации, основанной на расположении зависимые от менеджера факторы, такие как размер, расположение, и ориентация компонентов. В пределах цикла фокуса по компонентам можно переместиться в прямом или обратном направлении. В иерархии корней цикла фокуса вверх обход вынимает фокус из текущего цикла в родительский цикл.

В большинстве моделей Стили по компонентам перемещаются, используя ключи Shift-Tab и Вкладка. Эти ключи являются ключами обхода фокуса значения по умолчанию и могут быть изменены программно. Например, можно добавить, Входят как прямой ключ обхода фокуса со следующими четырьмя строками кода:

Set forwardKeys = getFocusTraversalKeys(
    KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
Set newForwardKeys = new HashSet(forwardKeys);
newForwardKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
    newForwardKeys);

Вкладка смещает фокус в прямом направлении. Shift-Tab перемещает фокус в обратное направление. Например, в FocusConceptsDemo, у первой кнопки есть начальный фокус. Переключение вкладок перемещает фокус через кнопки в текстовую область. Дополнительное переключение вкладок перемещает курсор в пределах текстовой области, но не из текстовой области, потому что в текстовой области Вкладка не является ключом обхода фокуса. Однако, Вкладка управления перемещает фокус из текстовой области и в первое текстовое поле. Аналогично, Вкладка сдвига управления перемещает фокус из текстовой области и в предыдущий компонент. Клавиша CTRL используется условно, чтобы переместить фокус из любого компонента, который обрабатывает Вкладку специальным способом, такой как JTable.

Вы только что получили краткое введение в архитектуру фокуса. Если Вы хотите больше деталей, см. спецификацию для Подсистемы Фокуса.

Проверка допустимости Ввода

Общее требование проекта GUI является компонентом, который ограничивает ввод пользователя ⠀” например, текстовое поле, которое позволяет только числовой ввод в десятичном формате (деньги, например) или текстовое поле, которое позволяет только 5 цифр для почтового индекса. Выпуск 1.4 обеспечивает удобный, удобный в работе отформатированный компонент текстового поля, который позволяет вводу быть ограниченным множеству локализуемых форматов. Можно также определить пользовательское средство форматирования для текстового поля, которое может выполнить специальную проверку, такую как определение, форматируются ли значения не только правильно, но также и разумные.

Можно использовать входной верификатор в качестве альтернативы пользовательскому средству форматирования, или когда у Вас есть компонент, который не является текстовым полем. Входной верификатор позволяет Вам отклонять определенные значения, такие как должным образом отформатированный, но недопустимый почтовый индекс, или значения за пределами требуемого диапазона, например температура тела выше чем 110°F. Чтобы использовать входной верификатор, Вы создаете подкласс InputVerifier (class, представленный в JDK 1.3), создайте экземпляр своего подкласса, и установите экземпляр как входной верификатор для одного или более компонентов.

С входным верификатором компонента консультируются всякий раз, когда компонент собирается потерять фокус. Если значение компонента не является приемлемым, входной верификатор может принять соответствующие меры, такие как отказ привести к фокусу на компоненте или замене ввода пользователя с последним допустимым значением и затем разрешения фокуса передать следующему компоненту. Однако, InputVerifier не вызывается, когда фокус передается другому высокоуровневому компоненту.

Следующие два примера показывают ипотечные калькуляторы. Каждый использует отформатированные текстовые поля и другую входную проверку использования со стандартными текстовыми полями.

InputVerificationDemo и пример, который демонстрирует

Попробуйте это: 
  1. Нажмите кнопку Launch, чтобы работать, FormattedTextFieldDemo, используя Сеть Java™ Запускаются (загрузите JDK 6 или позже). Альтернативно, чтобы скомпилировать и выполнить пример самостоятельно, консультируйтесь, пример индексируют.Запускает приложение FormattedTextFieldDemo
  2. Нажмите кнопку Launch, чтобы работать, InputVerificationDemo, используя Сеть Java™ Запускаются (загрузите JDK 6 или позже). Альтернативно, чтобы скомпилировать и выполнить пример самостоятельно, консультируйтесь, пример индексируют.Запускает приложение InputVerificationDemo
  3. Сравните эти два ипотечных калькулятора рядом. Вы будете видеть, что входной демонстрационный пример проверки определяет допустимые входные значения в связанной метке для каждого доступного для редактирования текстового поля. Попытайтесь ввести ужасно отформатированные значения в оба примера, чтобы наблюдать поведение. Затем попытайтесь ввести должным образом отформатированное, но недопустимое значение.

Можно найти код для Входного демонстрационного примера Проверки в InputVerificationDemo.java. Вот код для InputVerifier подкласс, MyVerifier:

class MyVerifier extends InputVerifier
                 implements ActionListener {
    double MIN_AMOUNT = 10000.0;
    double MAX_AMOUNT = 10000000.0;
    double MIN_RATE = 0.0;
    int MIN_PERIOD = 1;
    int MAX_PERIOD = 40;

   public boolean shouldYieldFocus(JComponent input) {
        boolean inputOK = verify(input);
        makeItPretty(input);
        updatePayment();

        if (inputOK) {
            return true;
        } else {
            Toolkit.getDefaultToolkit().beep();
            return false;
        }
    }

    protected void updatePayment() {
        double amount = DEFAULT_AMOUNT;
        double rate = DEFAULT_RATE;
        int numPeriods = DEFAULT_PERIOD;
        double payment = 0.0;

        //Parse the values.
        try {
            amount = moneyFormat.parse(amountField.getText()).
                              doubleValue();
        } catch (ParseException pe) {pe.printStackTrace();}
        try {
            rate = percentFormat.parse(rateField.getText()).
                                 doubleValue();
        } catch (ParseException pe) {pe.printStackTrace();}
        try {
            numPeriods = decimalFormat.parse(numPeriodsField.getText()).
                              intValue();
        } catch (ParseException pe) {pe.printStackTrace();}

        //Calculate the result and update the GUI.
        payment = computePayment(amount, rate, numPeriods);
        paymentField.setText(paymentFormat.format(payment));
    }

    //This method checks input, but should cause no side effects.
    public boolean verify(JComponent input) {
        return checkField(input, false);
    }

    protected void makeItPretty(JComponent input) {
        checkField(input, true);
    }

    protected boolean checkField(JComponent input, boolean changeIt) {
        if (input == amountField) {
            return checkAmountField(changeIt);
        } else if (input == rateField) {
            return checkRateField(changeIt);
        } else if (input == numPeriodsField) {
            return checkNumPeriodsField(changeIt);
        } else {
            return true; //should not happen
        }
    }

    //Checks that the amount field is valid.  If it is valid,
    //it returns true; otherwise, returns false.  If the
    //change argument is true, this method sets the
    //value to the minimum or maximum value if necessary and
    // (even if not) sets it to the parsed number so that it
    // looks good -- no letters, for example.
    protected boolean checkAmountField(boolean change) {
        boolean wasValid = true;
        double amount = DEFAULT_AMOUNT;

        //Parse the value.
        try {
            amount = moneyFormat.parse(amountField.getText()).
                              doubleValue();
        } catch (ParseException pe) {
            pe.printStackTrace();
            wasValid = false;
        }

        //Value was invalid.
        if ((amount < MIN_AMOUNT) || (amount > MAX_AMOUNT)) {
            wasValid = false;
            if (change) {
                if (amount < MIN_AMOUNT) {
                    amount = MIN_AMOUNT;
                } else { // amount is greater than MAX_AMOUNT
                    amount = MAX_AMOUNT;
                }
            }
        }

        //Whether value was valid or not, format it nicely.
        if (change) {
            amountField.setText(moneyFormat.format(amount));
            amountField.selectAll();
        }

        return wasValid;
    }

    //Checks that the rate field is valid.  If it is valid,
    //it returns true; otherwise, returns false.  If the
    //change argument is true, this method reigns in the
    //value if necessary and (even if not) sets it to the
    //parsed number so that it looks good -- no letters,
    //for example.
    protected boolean checkRateField(boolean change) {
        ...//Similar to checkAmountField...
    }

    //Checks that the numPeriods field is valid.  If it is valid,
    //it returns true; otherwise, returns false.  If the
    //change argument is true, this method reigns in the
    //value if necessary and (even if not) sets it to the
    //parsed number so that it looks good -- no letters,
    //for example.
    protected boolean checkNumPeriodsField(boolean change) {
        ...//Similar to checkAmountField...
    }

    public void actionPerformed(ActionEvent e) {
        JTextField source = (JTextField)e.getSource();
        shouldYieldFocus(source); //ignore return value
        source.selectAll();
    }
}

Отметьте что verify метод реализуется, чтобы обнаружить недопустимые значения, но не делает ничего иного. verify метод существует только, чтобы определить, является ли ввод допустимым ⠀”, это никогда не должно переводить диалоговое окно в рабочее состояние или вызывать любые другие побочные эффекты. shouldYieldFocus вызовы метода verify и, если значения недопустимо, наборы это к минимальному или максимальному значению. shouldYieldFocus методу позволяют вызвать побочные эффекты, в этом случае, он всегда форматирует текстовое поле и может также изменить его значение. В нашем примере, shouldYieldFocus метод всегда возвращает true так, чтобы передача фокуса никогда не была фактически предотвращена. Это - только один способ, которым может быть реализована проверка. Сочтите другую версию этого демонстрационного примера вызванной InputVerificationDialogDemo это поднимает диалоговое окно, когда ввод данных пользователем недопустим и требует, чтобы пользователь ввел юридическое значение.

Входной верификатор устанавливается, используя setInputVerifier метод JComponent class. Например, InputVerificationDemo имеет следующий код:

private MyVerifier verifier = new MyVerifier();
...
amountField.setInputVerifier(verifier);

Создание Пользовательского Компонента Focusable

Для компонента, чтобы получить фокус, это должно удовлетворить три требования: это должно быть видимо, включенное, и focusable. Входная карта может также быть дана. Для получения дополнительной информации о входной карте, читайте, Как Использовать Привязки клавиш.

Пример TrackFocusDemo определяет простой компонент Picture. Его конструктора показывают ниже:

public Picture(Image image) {
    this.image = image;
    setFocusable(true);
    addMouseListener(this);
    addFocusListener(this);
}

Звонок setFocusable(true) метод делает компонент focusable. Если Вы явно подаете свои компонентные привязки клавиш WHEN_FOCUSED входная карта, Вы не должны вызвать setFocusable метод.

Визуально показать изменения в фокусе (при рисовании красной границы только, когда у компонента есть фокус), Picture имеет слушателя фокуса.

Чтобы получить фокус, когда пользователь щелкает по изображению, у компонента есть слушатель мыши. Слушатель mouseClicked метод запрашивает на фокус быть переданным изображению. Вот код:

public void mouseClicked(MouseEvent e) {
    //Since the user clicked on us, let us get focus!
    requestFocusInWindow();
}

См. Изменения Фокуса Отслеживания к Многократным Компонентам для большего количества обсуждения примера TrackFocusDemo.

Настройка Обхода Фокуса

Подсистема фокуса определяет порядок значения по умолчанию, который применяется при использовании ключей обхода фокуса (таких как Вкладка), чтобы переместиться. Политика приложения Swing определяется LayoutFocusTraversalPolicy . Можно установить политику обхода фокуса по любому Container при использовании setFocusCycleRoot метод. Однако, если контейнер не является корнем цикла фокуса, он не может иметь никакого очевидного эффекта. Альтернативно можно передать провайдеров политики обхода фокуса к FocusTraversalPolicy методы вместо корней цикла фокуса. Используйте isFocusTraversalPolicyProvider() метод, чтобы определить, ли a Container провайдер политики обхода фокуса. Используйте setFocusTraversalPolicyProvider() метод, чтобы установить контейнер для того, чтобы обеспечить политику обхода фокуса.

FocusTraversalDemo пример демонстрирует, как настроить поведение фокуса.

Демонстрационный пример Обхода Фокуса, который демонстрирует пользовательский FocusTraversalPolicy.


Попробуйте это: 
  1. Нажмите кнопку Launch, чтобы работать, FocusTraversalDemo, используя Сеть Java™ Запускаются (загрузите JDK 6 или позже). Альтернативно, чтобы скомпилировать и выполнить пример самостоятельно, консультируйтесь, пример индексируют.Запускает приложение FocusTraversalDemo
  2. Щелкните по окну, в случае необходимости, чтобы дать этому фокус.
  3. Отметьте порядок фокуса, поскольку Вы снабжаете вкладками через компоненты. Порядок фокуса был решен порядком, что компоненты были добавлены к области контента. Отметьте также, что флажок никогда не получает фокус; мы удалили это из цикла фокуса.
  4. Чтобы переместить фокус из таблицы, используйте Вкладку управления или Вкладку сдвига управления.
  5. Щелкните по флажку Custom FocusTraversalPolicy. Это поле устанавливает пользовательскую политику обхода фокуса по фрейму.
  6. Попытайтесь снабдить вкладками через компоненты снова. Отметьте, что порядок фокуса находится теперь в слева направо, нисходящий порядок.

Можно найти код демонстрационного примера в FocusTraversalDemo.java.

Флажок был удален из цикла фокуса с этой строкой кода:

togglePolicy.setFocusable(false);

Вот пользовательское приложение FocusTraversalPolicy:

...
JTextField tf1 = new JTextField("Field 1");
JTextField tf2 = new JTextField("A Bigger Field 2");
JTextField tf3 = new JTextField("Field 3");
JTextField tf4 = new JTextField("A Bigger Field 4");
JTextField tf5 = new JTextField("Field 5");
JTextField tf6 = new JTextField("A Bigger Field 6");
JTable table = new JTable(4,3);
...
public FocusTraversalDemo() {
    super(new BorderLayout());

    JTextField tf1 = new JTextField("Field 1");
    JTextField tf2 = new JTextField("A Bigger Field 2");
    JTextField tf3 = new JTextField("Field 3");
    JTextField tf4 = new JTextField("A Bigger Field 4");
    JTextField tf5 = new JTextField("Field 5");
    JTextField tf6 = new JTextField("A Bigger Field 6");
    JTable table = new JTable(4,3);
    togglePolicy = new JCheckBox("Custom FocusTraversalPolicy");
    togglePolicy.setActionCommand("toggle");
    togglePolicy.addActionListener(this);
    togglePolicy.setFocusable(false);  //Remove it from the focus cycle.
    //Note that HTML is allowed and will break this run of text
    //across two lines.
    label = new JLabel("<html>Use Tab (or Shift-Tab) to navigate from component to component.<p>Control-Tab 
    (or Control-Shift-Tab) allows you to break out of the JTable.</html>");

    JPanel leftTextPanel = new JPanel(new GridLayout(3,2));
    leftTextPanel.add(tf1, BorderLayout.PAGE_START);
    leftTextPanel.add(tf3, BorderLayout.CENTER);
    leftTextPanel.add(tf5, BorderLayout.PAGE_END);
    leftTextPanel.setBorder(BorderFactory.createEmptyBorder(0,0,5,5));
    JPanel rightTextPanel = new JPanel(new GridLayout(3,2));
    rightTextPanel.add(tf2, BorderLayout.PAGE_START);
    rightTextPanel.add(tf4, BorderLayout.CENTER);
    rightTextPanel.add(tf6, BorderLayout.PAGE_END);
    rightTextPanel.setBorder(BorderFactory.createEmptyBorder(0,0,5,5));
    JPanel tablePanel = new JPanel(new GridLayout(0,1));
    tablePanel.add(table, BorderLayout.CENTER);
    tablePanel.setBorder(BorderFactory.createEtchedBorder());
    JPanel bottomPanel = new JPanel(new GridLayout(2,1));
    bottomPanel.add(togglePolicy, BorderLayout.PAGE_START);
    bottomPanel.add(label, BorderLayout.PAGE_END);

    add(leftTextPanel, BorderLayout.LINE_START);
    add(rightTextPanel, BorderLayout.CENTER);
    add(tablePanel, BorderLayout.LINE_END);
    add(bottomPanel, BorderLayout.PAGE_END);
    setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
    Vector<Component> order = new Vector<Component>(7);
    order.add(tf1);
    order.add(tf2);
    order.add(tf3);
    order.add(tf4);
    order.add(tf5);
    order.add(tf6);
    order.add(table);
    newPolicy = new MyOwnFocusTraversalPolicy(order);
}

Использовать пользовательское FocusTraversalPolicy, реализуйте следующий код любого корня цикла фокуса.

    MyOwnFocusTraversalPolicy newPolicy = new MyOwnFocusTraversalPolicy();
    frame.setFocusTraversalPolicy(newPolicy);

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

Отслеживание Фокуса Изменяется на Многократные Компоненты

В некоторых ситуациях приложение, возможно, должно отследить, у какого компонента есть фокус. Эта информация могла бы использоваться, чтобы динамически обновить меню или возможно строку состояния. Если Вы должны отследить фокус только на определенных компонентах, может иметь смысл реализовывать слушателя события фокуса.

Если слушатель фокуса не является соответствующим, можно вместо этого зарегистрировать a PropertyChangeListener на KeyboardFocusManager. Слушатель изменения свойства уведомляется относительно каждого изменения, включающего фокус, включая изменения владельцу фокуса, фокусируемому окну, и политике обхода фокуса значения по умолчанию. См. таблицу Свойств KeyboardFocusManager для полного списка.

Следующий пример демонстрирует, как отслеживать владельца фокуса, устанавливая слушателя изменения свойства на менеджере по клавиатурному фокусу.

Пример TrackFocusDemo, который демонстрирует, как отслеживать владельца фокуса.

Попробуйте это: 
  1. Нажмите кнопку Launch, чтобы работать, TrackFocusDemo, используя Сеть Java™ Запускаются (загрузите JDK 6 или позже). Альтернативно, чтобы скомпилировать и выполнить пример самостоятельно, консультируйтесь, пример индексируют.Запускает приложение TrackFocusDemo
  2. В случае необходимости щелкните по окну, чтобы дать этому фокус.
  3. Окно показывает шесть изображений, каждое из которых выводится на экран a Picture компонент. Picture у этого есть фокус, обозначается с красной границей. Метка у основания окна описывает Picture у этого есть фокус.
  4. Переместите фокус к другому Picture при использовании Вкладки или Shift-Tab, или нажимая на изображение. Поскольку слушатель изменения свойства был зарегистрирован на менеджере по клавиатурному фокусу, изменение в фокусе обнаруживается, и метка обновляется соответственно.

Можно просмотреть код демонстрационного примера в TrackFocusDemo.java. Пользовательский компонент, используемый для рисования изображений, может быть найден в Picture.java. Вот код, который определяет и устанавливает слушателя изменения свойства:

KeyboardFocusManager focusManager =
    KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(
    new PropertyChangeListener() {
        public void propertyChange(PropertyChangeEvent e) {
            String prop = e.getPropertyName();
            if (("focusOwner".equals(prop)) &&
                  ((e.getNewValue()) instanceof Picture)) {
                Component comp = (Component)e.getNewValue();
                String name = comp.getName();
                Integer num = new Integer(name);
                int index = num.intValue();
                if (index < 0 || index > comments.length) {
                    index = 0;
                }
                info.setText(comments[index]);
            }
        }
    }
);

Пользовательский компонент, Picture, ответственно за рисование изображения. Все шесть компонентов определяются этим способом:

pic1 = new Picture(createImageIcon("images/" +
            mayaString + ".gif", mayaString).getImage());
pic1.setName("1");

Передачи Фокуса синхронизации

Передачи фокуса являются асинхронными. Это качество может привести к некоторым нечетным связанным с синхронизацией проблемам и предположениям, особенно во время автоматических передач фокуса. Например, вообразите приложение с окном, содержащим кнопку Start, кнопку Cancel и текстовое поле. Компоненты добавляются в этом порядке:

  1. Запустите кнопку
  2. Текстовое поле
  3. Кнопка отмены

Когда приложение запускается, LayoutFocusTraversalPolicy определяет политику обхода фокуса ⠀” в этом случае, это - порядок, что компоненты были добавлены к их контейнеру. В этом примере требуемое поведение состоит в том, что у кнопки Start есть начальный фокус, и когда кнопка Start нажимается, это отключается, и затем кнопка Cancel получает фокус. Корректный способ реализовать это поведение состоял бы в том, чтобы добавить компоненты к контейнеру в требуемом порядке или создать пользовательскую политику обхода фокуса. Если по некоторым причинам это не возможно, то можно реализовать это поведение со следующим фрагментом кода:

public void actionPerformed(ActionEvent e) {
    //This works.
    start.setEnabled(false);
    cancel.requestFocusInWindow();
}

Как требующийся, фокус идет от кнопки Start до кнопки Cancel, а не к текстовому полю. Но различный результат произошел бы, если бы те же самые методы вызвали в противоположном порядке следующим образом:

public void actionPerformed(ActionEvent e) {
    //This does not work.
    cancel.requestFocusInWindow();
    start.setEnabled(false);
}

В этом случае фокус требуют на кнопке Cancel прежде, чем это оставило кнопку Start. Звонок requestFocusInWindow метод инициирует передачу фокуса, но это сразу не перемещает фокус в кнопку Cancel. Когда кнопка Start отключается, фокус передается следующему компоненту (таким образом, всегда есть компонент с фокусом), и, в этом случае, это тогда переместило бы фокус в текстовое поле, не в кнопку Cancel.

Есть несколько ситуаций, в которых Вы должны обратиться с просьбами фокуса после всех других изменений, которые могли бы влиять на фокус, применяется к:

API Фокуса

Следующие таблицы приводят обычно используемых конструкторов и методы, связанные с фокусом. API фокуса попадает в четыре категории:

Для более подробной информации об архитектуре фокуса см. спецификацию для Подсистемы Фокуса. Можно также найти, Как Записать полезному Слушателю Фокуса.

Полезные Методы для Компонентов

Весь этот API был представлен в JDK 1.4.

Метод (в Component) Цель
isFocusOwner () Возвраты true если компонент является владельцем фокуса. Этот метод, представленный в JDK 1.4, представляет устаревший hasFocus.
(булев) setRequestFocusEnabled
isRequestFocusEnabled ()
(в JComponent)
Наборы или начинают работу, должен ли этот компонент получить фокус. Установка setRequestFocusEnabled к false обычно препятствует тому, чтобы щелчки мышью дали компоненту фокус, все еще позволяя перемещение с помощью клавиатуры дать компоненту фокус. Этот метод применяется только к компонентам, которые получают события от нажатия мыши. Например, можно использовать этот метод на a JButton, но не на a JPanel. Если Вы пишете пользовательский компонент Вам решать, чтобы соблюдать это свойство. Этот метод рекомендуется по setFocusable метод и позволит Вашей программе работать лучше на пользователей, использующих вспомогательные технологии.
(булев) setFocusable
isFocusable ()
Наборы или получают focusable состояние компонента. Компонент должен быть focusable, чтобы получить фокус. Когда компонент был удален из цикла фокуса с setFocusable(false), по этому больше нельзя переместиться с клавиатурой. setRequestFocusEnabled метод рекомендуется так, чтобы Ваша программа могла быть выполнена пользователями, использующими вспомогательные технологии.
requestFocusInWindow () Запросы, что этот компонент должен получить фокус. Окно компонента должно быть током фокусируемое окно. Для этого запроса, который будет предоставлен подкласс JComponent должно быть видимым, включал, и focusable, и имейте входную карту для этого запроса, который будет предоставлен. Нельзя предположить, что у компонента есть фокус, пока это не запускает a FOCUS_GAINED событие. Этот метод предпочитается requestFocus метод, который зависим от платформы.
setFocusTraversalKeys (интервал, Набор)
getFocusTraversalKeys (интервал)
areFocusTraversalKeysSet (интервал)
(в java.awt.Container)
Наборы или получают ключи обхода фокуса для определенного направления или определяют, были ли какие-либо ключи обхода фокуса явно установлены на этом контейнере. Если никакие ключи обхода фокуса не были установлены, они наследованы от предка или от менеджера по клавиатурному фокусу. Ключи обхода фокуса могут быть установлены для следующих направлений: KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, или KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. Если Вы устанавливаете UP_CYCLE_TRAVERSAL_KEYS или DOWN_CYCLE_TRAVERSAL_KEYS, следует также вызвать setImplicitDownCycleTraversal(false) на политике обхода фокуса.

Создание и Используя Пользовательский FocusTraversalPolicy

Класс или Метод Цель
LayoutFocusTraversalPolicy class, который, по умолчанию, определяет политику обхода фокуса для компонентов Swing.
getComponentAfter (Контейнер, Компонент) Учитывая компонент, который передают как входной, возвращает компонент, у которого должен затем быть фокус.
getComponentBefore (Контейнер, Компонент) Учитывая компонент, который передают как входной, возвращает компонент, у которого должен быть фокус перед этим компонентом. Метод используется для обратного переключения вкладок.
getDefaultComponent (Контейнер)
(в javax.swing.SortingFocusTraversalPolicy)
Возвращает компонент, у которого должен быть фокус значения по умолчанию.
getFirstComponent (Контейнер) Возвращает первый компонент в цикле обхода.
getInitialComponent (Контейнер) Возвращает компонент, который должен получить фокус, когда окно делается видимым впервые.
getLastComponent (Контейнер) Возвращает последний компонент в цикле обхода.
setFocusTraversalPolicy (FocusTraversalPolicy)
getFocusTraversalPolicy (FocusTraversalPolicy)
(в java.awt.Container)
Наборы или получают политику обхода фокуса или определяют, была ли политика установлена. Отметьте, что установка политики обхода фокуса по контейнеру, который не является корнем цикла фокуса, не может иметь никакого очевидного эффекта. Значение null средства, что политика не была явно установлена. Если никакая политика не была установлена, политика наследована от родительского корня цикла фокуса.
isFocusCycleRoot ()
(булев) setFocusCycleRoot
(в java.awt.Container)
Проверки или наборы, является ли контейнер корнем цикла обхода фокуса.
isFocusTraversalPolicyProvider ()
(булев) setFocusTraversalPolicyProvider
(в java.awt.Container)
Проверки или наборы, будет ли контейнер использоваться, чтобы обеспечить политику обхода фокуса.

Входной API Проверки

Весь этот API был представлен в JDK 1.3.

Класс или Метод Цель
InputVerifier Абстрактный class, который позволяет контроль ввода через механизм фокуса. Когда попытка предпринимается, чтобы сместить фокус от компонента, содержащего входной верификатор, фокус не оставляется, пока верификатор не удовлетворяется.
shouldYieldFocus (JComponent)
InputVerifier)
Когда у компонента есть входной верификатор, этот метод вызывает система, чтобы определить, может ли фокус оставить этот компонент. Этот метод может вызвать побочные эффекты, такие как перевод в рабочее состояние диалогового окна. Если этот метод возвращается false, фокус остается на компоненте, который передают в к методу.
проверьте (JComponent)
InputVerifier)
Вы должны переопределить этот метод, чтобы проверить, что ввод компонента допустим. Это должно возвратиться true если допустимый, иначе возвратитесь false. Этот метод не должен вызвать побочные эффекты, такие как перевод в рабочее состояние диалогового окна. Этим методом вызывают shouldYieldFocus.
setInputVerifier (inputVerifier)
getInputVerifier ()
JComponent)
Наборы или присваивали входной верификатор компоненту. По умолчанию у компонентов нет никакого входного верификатора.
(булев) setVerifyInputWhenFocusTarget
getVerifyInputWhenFocusTarget ()
JComponent)
Наборы или добираются, вызывают ли входной верификатор для текущего владельца фокуса прежде, чем этот компонент запрашивает фокус. Значение по умолчанию true. Этот метод должен быть установлен в false для компонентов, таких как кнопка Cancel или полоса прокрутки, которая должна получить фокус, даже если введенный недопустимо.

Свойства KeyboardFocusManager

Эта таблица определяет связанные свойства для KeyboardFocusManager. Слушатель может быть зарегистрирован для этих свойств, вызывая addPropertyChangeListener.

Весь этот API был представлен в JDK 1.4.

Свойство Цель
focusOwner Компонент, который в настоящий момент получает ключевые события.
permanentFocusOwner Компонент, который последний раз получил постоянное FOCUS_GAINED событие. Обычно то же самое как focusOwner, если временное изменение фокуса не в настоящий момент в действительности.
focusedWindow Окно, которое является или это содержит владельца фокуса.
activeWindow Компонент должен всегда быть любой a Frame или a Dialog. Активное окно является или фокусируемым окном, или первым фреймом или диалоговым окном, которое является владельцем фокусируемого окна.
defaultFocusTraversalPolicy Политика обхода фокуса значения по умолчанию, которая может быть установлена setFocusTraversalPolicy метод Container class.
forwardDefaultFocusTraversalKeys Набор значения по умолчанию фокусирует ключи для прямого обхода. Для многострочных текстовых компонентов, эти ключи значение по умолчанию к Вкладке управления. Для всех других компонентов, эти ключи значение по умолчанию, чтобы Снабдить вкладками и Вкладка управления.
backwardDefaultFocusTraversalKeys Набор значения по умолчанию фокусирует ключи для обратного обхода. Для многострочных текстовых компонентов эти ключи значение по умолчанию к Вкладке сдвига управления. Для всех других компонентов эти ключи значение по умолчанию к Shift-Tab и Вкладке сдвига управления.
upCycleDefaultFocusTraversalKeys Набор значения по умолчанию фокусирует ключи для цикл. Эти ключи являются нулем, по умолчанию, для компонентов Swing. Если Вы устанавливаете эти ключи на KeyboardFocusManager, или если Вы устанавливаете downCycleFocusTraversalKeys на корне цикла фокуса следует также вызвать setImplicitDownCycleTraversal(false) метод на политике обхода фокуса.
downCycleDefaultFocusTraversalKeys Набор значения по умолчанию фокусирует ключи для вниз цикл. Эти ключи являются нулем, по умолчанию, для компонентов Swing. Если Вы устанавливаете эти ключи на KeyboardFocusManager, или если Вы устанавливаете upCycleFocusTraversalKeys на корне цикла фокуса следует также вызвать setImplicitDownCycleTraversal(false) метод на политике обхода фокуса.
currentFocusCycleRoot Контейнер, который является текущим корнем цикла фокуса.

Примеры тот Фокус Использования

Следующая таблица приводит примеры, которые управляют фокусом:

Пример Где Описано Примечания
FocusConceptsDemo Этот раздел Демонстрирует основное поведение фокуса значения по умолчанию.
FocusTraversalDemo Этот раздел Демонстрирует, как переопределить порядок фокуса значения по умолчанию.
TrackFocusDemo Этот раздел Демонстрирует, как использовать a PropertyChangeListener отслеживать владельца фокуса. Также реализует пользовательский focusable компонент.
InputVerificationDemo Этот раздел Демонстрирует, как реализовать InputVerifier проверить ввода данных пользователем.
InputVerificationDialogDemo Этот раздел Демонстрирует, как реализовать InputVerifier это поднимает диалоговое окно, когда ввод данных пользователем недопустим.
FocusEventDemo Как Записать Слушателю Фокуса Отчеты все события фокуса, которые происходят на нескольких компонентах, чтобы демонстрировать обстоятельства, при которых запускаются события фокуса.


Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Как к Support Assistive Technologies
Следующая страница: Как Использовать Привязки клавиш