概要

JScrollPaneから取得した垂直JScrollBarとそれらのスクロールをロックするためのJToggleButtonを別パネルに配置します。

サンプルコード

JTable table = new JTable(16, 4);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JScrollPane scroll = new JScrollPane(table);
JToggleButton lock = new JToggleButton("🔓");
lock.setBorder(BorderFactory.createEmptyBorder());
lock.setContentAreaFilled(false);
lock.setFocusPainted(false);
lock.setFocusable(false);
DisableInputLayerUI<Component> layerUI = new DisableInputLayerUI<>();
lock.addItemListener(e -> {
  AbstractButton b = (AbstractButton) e.getItemSelectable();
  if (e.getStateChange() == ItemEvent.SELECTED) {
    b.setText("🔒");
    scrollLock(scroll, true);
    layerUI.setLocked(true);
  } else if (e.getStateChange() == ItemEvent.DESELECTED) {
    b.setText("🔓");
    scrollLock(scroll, false);
    layerUI.setLocked(false);
  }
});
JScrollBar verticalScrollBar = scroll.getVerticalScrollBar();
JPanel verticalBox = new JPanel(new BorderLayout());
verticalBox.setOpaque(false);
verticalBox.add(new JLayer<>(verticalScrollBar, layerUI));
verticalBox.add(lock, BorderLayout.SOUTH);
BoundedRangeModel model = verticalScrollBar.getModel();
model.addChangeListener(e -> {
  BoundedRangeModel m = (BoundedRangeModel) e.getSource();
  verticalBox.setVisible(m.getMaximum() - m.getMinimum() > m.getExtent());
});
verticalBox.setVisible(model.getMaximum() - model.getMinimum() > model.getExtent());
JPanel panel = new JPanel(new BorderLayout(0, 0));
panel.add(scroll);
panel.add(verticalBox, BorderLayout.EAST);
View in GitHub: Java, Kotlin

解説

  • JPanel
    • 垂直JScrollBarとスクロールロック用のJToggleButtonを配置するためのJPanelを作成
  • 垂直JScrollBar
    • JScrollPane#getVerticalScrollBar()で取得して上記のJPanel中央にロック用のJLayerをはさんで追加
    • JScrollPane#getVerticalScrollBar()#getModel()で取得したBoundedRangeModelChangeListenerを追加し、垂直JScrollBarが非表示になる場合は親JPanelごとsetVisible(false)メソッドで非表示に設定
  • ロック用JToggleButton
    • 上記のJPanel下部に追加
    • 選択状態になるとテキストを🔓から🔒に変更
    • さらにJScrollPaneのホイールスクロール、内部のコンポーネントをsetEnabled(false)などで無効化
    • JScrollPaneから別パネルに移動、配置されている垂直JScrollBarJLayerで入力イベントをブロック
    • ロック用JToggleButton自身は上記のJLayerでまとめて入力がブロックされない位置に配置する必要がある

参考リンク

コメント