JTabbedPaneのタブ追加位置をハイライト表示する
Total: 8, Today: 8, Yesterday: 0
Posted by aterai at
Last-modified:
Summary
JTabbedPaneのタブ追加時にそのタブ領域、領域が非表示の場合はスクロールボタンをハイライトするアニメーションで追加位置を知らせるよう設定します。
Screenshot

Advertisement
Source Code Examples
class TabHighlightLayerUI extends LayerUI<JTabbedPane> {
private static final int MAX = 32;
private final Rectangle rect = new Rectangle();
private final Timer animator = new Timer(10, null);
private transient ActionListener listener;
private int alpha;
@Override public void installUI(JComponent c) {
super.installUI(c);
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(AWTEvent.HIERARCHY_EVENT_MASK);
}
}
@Override public void uninstallUI(JComponent c) {
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(0);
}
super.uninstallUI(c);
}
@Override public void paint(Graphics g, JComponent c) {
super.paint(g, c);
if (c instanceof JLayer) {
Graphics2D g2 = (Graphics2D) g.create();
float a = alpha / 100f;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, a));
g2.setPaint(Color.RED);
g2.fill(rect);
g2.dispose();
}
}
@Override protected void processHierarchyEvent(
HierarchyEvent e, JLayer<? extends JTabbedPane> l) {
super.processHierarchyEvent(e, l);
Container parent = e.getChangedParent();
JTabbedPane tabs = l.getView();
long flags = e.getChangeFlags();
if (Objects.equals(parent, tabs) && flags == HierarchyEvent.PARENT_CHANGED) {
EventQueue.invokeLater(() -> startAnime(l, e.getComponent()));
}
}
private void startAnime(JLayer<? extends JTabbedPane> l, Component c) {
JTabbedPane tabs = l.getView();
int idx = tabs.indexOfComponent(c);
Rectangle tabRect = tabs.getBoundsAt(idx);
if (tabs.getBounds().contains(tabRect)) {
rect.setBounds(tabRect);
} else {
JButton b = getScrollForwardButton(tabs);
if (b != null) {
rect.setBounds(b.getBounds());
}
}
animator.start();
animator.removeActionListener(listener);
listener = ae -> {
if (alpha < MAX) {
alpha += 1;
} else {
alpha = 0;
animator.stop();
}
l.paintImmediately(rect);
};
animator.addActionListener(listener);
animator.start();
}
private static JButton getScrollForwardButton(JTabbedPane tabs) {
JButton button1 = null;
JButton button2 = null;
for (Component c : tabs.getComponents()) {
if (c instanceof JButton) {
if (Objects.isNull(button1)) {
button1 = (JButton) c;
} else if (Objects.isNull(button2)) {
button2 = (JButton) c;
}
}
}
int x1 = Objects.nonNull(button1) ? button1.getX() : -1;
int x2 = Objects.nonNull(button2) ? button2.getX() : -1;
return x1 > x2 ? button1 : button2;
}
}
View in GitHub: Java, KotlinDescription
JTabbedPane.SCROLL_TAB_LAYOUTを設定したJTabbedPaneをラップするJLayerを設定LayerUI#installUI(...)をオーバーライドしてJLayer#setLayerEventMask(AWTEvent.HIERARCHY_EVENT_MASK)で階層イベントを取得するよう設定LayerUI#processHierarchyEvent(...)をオーバーライドしてJLayerを設定したJTabbedPaneの子としてタブコンテンツコンポーネントが追加された後にハイライトアニメーションを開始するよう設定JTabbedPane#indexOfComponent(...)で追加されたタブのインデックスを取得し、JTabbedPane#getBoundsAt(...)でその領域を取得- 取得したタブ領域が
JTabbedPane領域内に含まれる場合はそのタブ領域をハイライトする - 取得したタブ領域が
JTabbedPane領域内に含まれない場合はスクロールボタンの領域をハイライトする- このサンプルではタブは末尾にのみ追加するので、
scrollTabsBackwardボタンより右側に配置されたscrollTabsForwardボタンをハイライトする
- このサンプルではタブは末尾にのみ追加するので、
- 取得したタブ領域が
Timerを使用してアルファ値を変更しつつ、JLayer#paintImmediately(Rectangle)でハイライト領域を再描画することでアニメーションを行う