2011-11-23 22 views
9

私は大きいパネルを持つスイングアプリを持っていて、それはJScrollPaneで包まれています。ユーザーは通常、タブのサブコンポーネント間を移動するため、ビューに何かをタブで表示すると、スクロールペイントを自動スクロールして、入力フォーカスのあるコンポーネントが常に表示されるようにします。JScrollPaneスクロールを入力フォーカスに追従させるにはどうすればよいですか?

入力フォーカスの変更をリッスンしてからscrollRectToVisibleを呼び出すと、KeyboardFocusManagerを試してみました。

は、ここで(ちょうど/ペーストをコピーして実行します!)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を実行します)。あなたのコード内

答えて

13

他の答えに私のコメント:コンポーネント自体に

でscrollRectToVisibleそれは階層構造に渡すということ 方法;-)の全体のポイントです スクロールをしている親がコンポーネント自体がそれを処理する場合を除き

...

を発見されるまで - のJTextFieldが行うよう:horizo​​をスクロールするために実装されますキャレットを見えるようにします。その方法は、フィールドの親のメソッドを呼び出すことです。

編集

だけ明確にするため、置き換えラインは、あなたがダウンに対して(例えば、その後、比較、あまりにJPanelJViewPortから

通知をRectangleを取らなければならない

content.scrollRectToVisible(focused.getBounds()); 
+0

ありがとうございます。 –

+5

はい、ありがとうございます。あなたの提案された修正は私のアプリでは機能しませんでしたが(上記の例では魅力的でしたが)、実験の少し後に、((JComponent)focused.getParent())。scrollRectToVisible – gustafc

0

一つの大きな問題は、次のとおりです。

focused.scrollRectToVisible(focused.getBounds()); 

あなたがコンポーネント自体にでscrollRectToVisibleを呼び出しています!おそらくタイプミス。あなたの側JScrollPaneに、最終的な変数を作成し、呼び出し

scrollPane.getViewport().scrollRectToVisible(focused.getBounds()); 
+0

でscrollRectToVisibleコンポーネント自体には、そのメソッドの_whole Point_のですスクロールをしているのは – kleopatra

+0

@kleopatraです。私はそれを知らなかった。私が提案した変更はうまく動作しますが、なぜそれが動作しないのかわかりません。 –

+0

なぜ私の答えを参照してください(コメントを投稿した後にのみコンポーネントのタイプに気づきました)。しかし、_do not_メッセージはコードサニティのために直接ビューポートに送られます – kleopatra

3

です - 投票)最終的な出力のためにいくつかの作業が必要でした。JViewPort

ここ
import java.awt.KeyboardFocusManager; 
import java.awt.Rectangle; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import javax.swing.*; 
//http://stackoverflow.com/questions/8245328/how-do-i-make-jscrollpane-scroll-to-follow-input-focus 
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); 
       } 
       final JScrollPane scroll = new JScrollPane(content); 
       KeyboardFocusManager.getCurrentKeyboardFocusManager(). 
         addPropertyChangeListener("focusOwner", new PropertyChangeListener() { 

        @Override 
        public void propertyChange(PropertyChangeEvent evt) { 
         if (!(evt.getNewValue() instanceof JComponent)) { 
          return; 
         } 
         JViewport viewport = (JViewport) content.getParent(); 
         JComponent focused = (JComponent) evt.getNewValue(); 
         if (content.isAncestorOf(focused)) { 
          System.out.println("Scrolling to " + focused.getName()); 
          Rectangle rect = focused.getBounds(); 
          Rectangle r2 = viewport.getVisibleRect(); 
          content.scrollRectToVisible(new Rectangle(rect.x, rect.y, (int) r2.getWidth(), (int) r2.getHeight())); 
         } 
        } 
       }); 

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

いいえ、あなたは必要ありません)任意の追加の矩形の操作b)最終的なフィールド – kleopatra

+0

b)のビットを後退させる必要があります - 参照先コンテンツはスクロールに必要ではなく、コンテンツの子階層にフォー​​カスがあるかどうかを確認するために必要です – kleopatra

0

jtextboxは、ピントを合わせたいとJScrollPaneには、あなたのスクロール成分である:それは親まで階層構造に渡すだ;-)

jScrollpane.getVerticalScrollBar().setValue(jtextbox.getLocation().x); 
関連する問題