Как заставить JScrollPane прокручивать, следуя фокусу ввода?

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

Я пробовал использовать KeyboardFocusManager для прослушивания изменений фокуса ввода, а затем вызвал scrollRectToVisible .

Вот SSCCE , отображающий мою текущую стратегию (просто скопируйте / вставьте и запустите!):

import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;

public class FollowFocus {

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

      public void run() {
        final int ROWS = 100;
        final JPanel content = new JPanel();
        content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
        content.add(new JLabel(
          "Thanks for helping out. Use tab to move around."));
        for (int i = 0; i < ROWS; i++) {
          JTextField field = new JTextField("" + i);
          field.setName("field#" + i);
          content.add(field);
        }

        KeyboardFocusManager.getCurrentKeyboardFocusManager()
                            .addPropertyChangeListener("focusOwner", 
                     new PropertyChangeListener() {

          @Override
          public void propertyChange(PropertyChangeEvent evt) {
            if (!(evt.getNewValue() instanceof JComponent)) {
              return;
            }
            JComponent focused = (JComponent) evt.getNewValue();
            if (content.isAncestorOf(focused)) {
              System.out.println("Scrolling to " + focused.getName());
              focused.scrollRectToVisible(focused.getBounds());
            }
          }
        });

        JFrame window = new JFrame("Follow focus");
        window.setContentPane(new JScrollPane(content));
        window.setSize(200, 200);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setVisible(true);
      }
    });
  }
}

Если вы запустите этот пример, вы заметите, что он работает не очень хорошо.Он получает уведомления об изменении фокуса, но вызов scrollRectToVisible , похоже, не имеет никакого эффекта. В моем приложении (которое слишком сложно, чтобы показывать здесь) scrollRectToVisible работает примерно половину времени, когда я вкладываюсь во что-то за пределами области просмотра.

Есть ли устоявшийся способ решения этой проблемы? Если это имеет значение, приложение Swing построено на Netbeans RCP (и большинство наших клиентов используют Windows).

10
задан gustafc 23 November 2011 в 16:05
поделиться