JProgressBarでページのスクロールした距離を表示する
Total: 424, Today: 9, Yesterday: 6
Posted by aterai at
Last-modified:
Summary
JProgressBarでページのスクロールした距離を表示する進捗インジケーターを作成し、JScrollPaneのヘッダに追加します。
Screenshot

Advertisement
Source Code Examples
JScrollPane scroll = new JScrollPane(new JTextArea(buf.toString()));
BoundedRangeModel model = scroll.getVerticalScrollBar().getModel();
JProgressBar progress = new ScrollIndicator(model);
scroll.setColumnHeaderView(progress);
// ...
class ScrollIndicator extends JProgressBar {
protected ScrollIndicator(BoundedRangeModel model) {
super(model);
}
@Override public void updateUI() {
super.updateUI();
setUI(new ScrollIndicatorUI());
setBorder(BorderFactory.createEmptyBorder());
}
@Override public double getPercentComplete() {
BoundedRangeModel m = getModel();
int max = m.getMaximum();
int min = m.getMinimum();
double maxExtent = Math.max(max - m.getExtent() - min, 0d);
return (m.getValue() - min) / maxExtent;
}
@Override public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
if (getOrientation() == HORIZONTAL) {
d.height = 4;
} else {
d.width = 4;
}
return d;
}
}
class ScrollIndicatorUI extends BasicProgressBarUI {
@Override public void paintDeterminate(Graphics g, JComponent c) {
Insets b = progressBar.getInsets();
Rectangle r = SwingUtilities.calculateInnerArea(progressBar, null);
if (!r.isEmpty()) {
int amountFull = getAmountFull(b, r.width, r.height); // + extent;
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(UIManager.getColor("ProgressBar.foreground"));
if (progressBar.getOrientation() == SwingConstants.HORIZONTAL) {
g2.fillRect(r.x, r.y, amountFull, r.height);
} else { // VERTICAL
// Draw progress from top to bottom
g2.fillRect(r.x, r.y, r.width, amountFull);
// Draw progress from bottom to top
// g2.fillRect(r.x, r.y + r.height - amountFull, r.width, amountFull);
}
// Deal with possible text painting
if (progressBar.isStringPainted()) {
paintString(g2, r.x, r.y, r.width, r.height, amountFull, b);
}
g2.dispose();
}
}
}
View in GitHub: Java, KotlinDescription
JScrollPane#getVerticalScrollBar()で縦JScrollBarを取得し、そのBoundedRangeModelを共有するJProgressBarを作成JScrollPane#setColumnHeaderView(...)でJScrollPaneのカラムヘッダに配置
- 縦
JScrollBarの表示領域(JViewportの高さ)がそのBoundedRangeModelのノブの高さ(extent)となるが、JProgressBarのBoundedRangeModelは進捗の描画にextentは使用しない(常に0)ので、進捗が100%になってもJProgressBarの右端にextent分の塗り残しが発生する- このサンプルではこれを解消するため、以下のような調整を行っている
- 進捗状況の描画領域サイズを計算する
BasicProgressBarUI#getAmountFull(...)が内部でJProgressBar#getPercentComplete()を使用するので、JProgressBar#getPercentComplete()を以下のようにオーバーライドし、縦JScrollBarのノブの下辺の位置がJProgressBarの現在値となるよう、BoundedRangeModel#getValue()ではなくBoundedRangeModel#getValue() + BoundedRangeModel#getExtent()の値で進捗のパーセントを求めるよう変更 - 縦
JScrollBarの実際の可動域は最大値からノブの高さ(Extent)を引いた位置になるので、これを分母にして最上端ではm.getValue() == 0で0%、最下端ではm.getValue() == m.getMaximum() - m.getExtent()で100%の進捗パーセントが返るよう変更
Reference
- JProgressBar#setModel(BoundedRangeModel) (Java Platform SE 8)
- JEditorPaneのミニマップを表示する
- JEditorPaneのスクロールに連動してJTreeのノードを選択する
- JTextFieldの表示領域をJScrollBarでスクロールする