/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package open.dolphin.utilities.control; import java.awt.*; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.EventObject; import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.EtchedBorder; /** * アコーディオンパネル * @author Life Sciences Computing Corporation. */ public class AccordionPanel extends JScrollPane { private Box verticalBox; private Component verticalGlue; private AccordionListener acdListener; /** * コンストラクタ */ public AccordionPanel() { super(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); verticalBox = Box.createVerticalBox(); verticalGlue = Box.createVerticalGlue(); getVerticalScrollBar().setUnitIncrement(25); getViewport().add(verticalBox); verticalBox.setOpaque(true); verticalBox.setBackground(Color.WHITE); verticalBox.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); acdListener = new AccordionListener() { @Override public void accordionStateChanged(AccordionEvent e) { verticalBox.revalidate(); } }; getViewport().addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { verticalBox.revalidate(); } }); } /** * コンポーネントの追加 * @param title タイトル * @param comp コンポーネント */ public void addComponent(String title, Component comp) { AccordionPartPanel accordion = new AccordionPartPanel(title, comp); verticalBox.remove(verticalGlue); verticalBox.add(Box.createVerticalStrut(5)); verticalBox.add(accordion); verticalBox.add(verticalGlue); verticalBox.revalidate(); accordion.addAccordionListener(acdListener); } /** * パネルを開く * @param title タイトル */ public void openPanel(String title) { for(int i = 0; i < verticalBox.getComponentCount(); i++) { Component comp = verticalBox.getComponent(i); if(comp != null && comp instanceof AccordionPartPanel) { AccordionPartPanel panel = (AccordionPartPanel)comp; String val = panel.getTitle(); if(title.equals(val)) { panel.changeStatePanel(); break; } } } } /** * パネルが開いてるかどうかの取得 * @param title タイトル * @return Open/Close */ public boolean isPanelOpen(String title) { boolean open = false; for(int i = 0; i < verticalBox.getComponentCount(); i++) { Component comp = verticalBox.getComponent(i); if(comp != null && comp instanceof AccordionPartPanel) { AccordionPartPanel panel = (AccordionPartPanel)comp; String val = panel.getTitle(); if(title.equals(val)) { if(panel.isPanelOpen()) { open = true; } break; } } } return open; } public static void main( String[] args ) { //JFrame frame = new JFrame(); //AccordionPanel panel = new AccordionPanel(); //panel.addPanel("Test", new JPanel()); //frame.add(panel); } } /** * アコーディオンの部品 * @author Life Sciences Computing Corporation. */ class AccordionPartPanel extends JPanel { private static final String MARK_CLOSE = "▲ "; private static final String MARK_OPEN = "▽ "; private String partTitle; private JLabel partLabel; private JPanel partPanel; private ArrayList accordionListenerList; private Color COLOR_TITLE_GRADATION1; private Color COLOR_TITLE_GRADATION2; private Color COLOR_TITLE_TEXT; private Color COLOR_BODY_BACKGROUND; /** * コンストラクタ * @param title タイトル * @param comp コンポーネント */ public AccordionPartPanel(String title, Component comp) { super(new BorderLayout()); accordionListenerList = new ArrayList(); partTitle = title; COLOR_TITLE_GRADATION1 = Color.WHITE; COLOR_TITLE_GRADATION2 = Color.ORANGE; COLOR_TITLE_TEXT = Color.BLACK; COLOR_BODY_BACKGROUND = Color.GRAY; partLabel = new JLabel(MARK_CLOSE + partTitle) { @Override protected void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D)g; //g2.setPaint(new GradientPaint(50, 0, COLOR_TITLE_GRADATION1, getWidth(), getHeight(), COLOR_TITLE_GRADATION2)); g2.setPaint(new GradientPaint(0, 0, COLOR_TITLE_GRADATION1, 0, 30, COLOR_TITLE_GRADATION2)); g2.fillRect(0, 0, getWidth(), getHeight()); super.paintComponent(g); } }; partLabel.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent evt) { changeStatePanel(); } }); partLabel.setForeground(COLOR_TITLE_TEXT); //partLabel.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 2)); partLabel.setBorder(BorderFactory.createBevelBorder(EtchedBorder.LOWERED)); partLabel.setPreferredSize(new Dimension(0, 50)); Font font = new Font("Label.font", Font.BOLD, 13); partLabel.setFont(font); add(partLabel, BorderLayout.NORTH); partPanel = new JPanel(); partPanel.add(comp); partPanel.setVisible(false); partPanel.setOpaque(true); partPanel.setBackground(COLOR_BODY_BACKGROUND); Border outBorder = BorderFactory.createMatteBorder(0, 2, 2, 2, Color.WHITE); Border inBorder = BorderFactory.createEmptyBorder(10, 10, 10, 10); Border border = BorderFactory.createCompoundBorder(outBorder, inBorder); partPanel.setBorder(border); add(partPanel); } /** * サイズの取得 * @return サイズ */ @Override public Dimension getPreferredSize() { Dimension d = partLabel.getPreferredSize(); if(partPanel.isVisible()) { d.height += partPanel.getPreferredSize().height; } return d; } /** * 最大サイズの取得 * @return サイズ */ @Override public Dimension getMaximumSize() { Dimension d = getPreferredSize(); d.width = Short.MAX_VALUE; return d; } /** * パネルの状態変更 */ public void changeStatePanel() { partPanel.setVisible(!partPanel.isVisible()); partLabel.setText((partPanel.isVisible() ? MARK_OPEN : MARK_CLOSE) + partTitle); revalidate(); execAccordionEvent(); EventQueue.invokeLater(new Runnable() { @Override public void run() { partPanel.scrollRectToVisible(partPanel.getBounds()); } }); } /** * アコーディオンリスナーの追加 * @param listener */ public void addAccordionListener(AccordionListener listener) { if(!accordionListenerList.contains(listener)) { accordionListenerList.add(listener); } } /** * アコーディオンリスナーの削除 * @param listener */ public void removeAccordionListener(AccordionListener listener) { accordionListenerList.remove(listener); } /** * アコーディオンイベントの実行 */ public void execAccordionEvent() { ArrayList list = (ArrayList)accordionListenerList.clone(); AccordionEvent e = new AccordionEvent(this); for(int i = 0; i < list.size(); i++) { AccordionListener listener = (AccordionListener)list.get(i); listener.accordionStateChanged(e); } } /** * タイトルの取得 * @return タイトル */ public String getTitle() { return partTitle; } /** * パネルが開いてるかどうかの取得 * @return Open/Close */ public boolean isPanelOpen() { return partPanel.isVisible(); } } /** * アコーディオンイベント * @author Life Sciences Computing Corporation. */ class AccordionEvent extends EventObject{ /** * コンストラクタ * @param source 親 */ public AccordionEvent(Object source) { super(source); } } /** * アコーディオンリスナーのインターフェース * @author Life Sciences Computing Corporation. */ interface AccordionListener{ /** * Boxの再描画 * @param e イベント */ public void accordionStateChanged(AccordionEvent e); }