JTable でセルのないところに行っぽい表示を出せますか?
のようなことを,先週末ぐらいにきかれて「できるんじゃないですかね?」と答えて作ってみた.
意外にサクッと作れた.Swing ってうまくできてますね.
普通の JTable + カスタマイズした JViewport
JScrollPane を Javadoc で調べてみると,セル領域外の表示をごにょごにょしたいときは JViewport を改造すればよいことが解ります.
Oracle Technology Network for Java Developers
で,こんな↓感じのコードを書くと,
TestMain.java
public class TestMain { static class TestFrame extends JFrame { public TestFrame() { TestTable table = new TestTable(); TestTableViewport viewport = new TestTableViewport(); viewport.setView(table); JScrollPane scroll = new JScrollPane(); scroll.setViewport(viewport); getContentPane().add(scroll); setSize(480, 320); setDefaultCloseOperation(EXIT_ON_CLOSE); setTitle("Swing ちょっとだけ好きになれた"); } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new TestFrame().setVisible(true); } }); } }
TestTable.java
public class TestTable extends JTable { public static final Icon ICON = new ImageIcon(TestTable.class .getResource("start.gif")); public TestTable() { super(new AbstractTableModel() { public int getColumnCount() { return 3; } public int getRowCount() { return 30; } public Object getValueAt(int rowIndex, int columnIndex) { return "Dummy"; } }); setDefaultRenderer(Object.class, new CancelSelectionRenderer()); setShowGrid(false); getTableHeader().setReorderingAllowed(false); setAutoResizeMode(AUTO_RESIZE_OFF); } static class CancelSelectionRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { setOpaque(false); setFont(table.getFont()); setValue(value); setIcon(ICON); return this; } } }
TestTableViewport.java
public class TestTableViewport extends JViewport { public void setView(final JTable table) { table.setOpaque(false); table.getSelectionModel().addListSelectionListener( new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { repaint(); } }); super.setView(table); super.setBackground(table.getBackground()); } @Override public JTable getView() { return super.getView() instanceof JTable ? (JTable) super.getView() : null; } @Override public void paintComponent(Graphics g) { super.paintComponent(g); JTable table = getView(); if (table == null || table.getRowCount() < 1) { return; } final Color saveColor = g.getColor(); // 表示中の領域 Rectangle viewRect = getViewRect(); // 交互に行を描画 final int rowCount = table.getRowCount(); final Color back = table.getBackground(); final Color blue = getTranslucentColor(Color.BLUE); boolean isColor = false; for (int r = 0; r < rowCount; ++r) { g.setColor((isColor = !isColor) ? blue : back); Rectangle rc = table.getCellRect(r, 0, true); g.fillRect(0, rc.y - viewRect.y, viewRect.width, rc.height - 1); } // 選択状態を描画 g.setColor(getTranslucentColor(Color.RED)); int[] selections = table.getSelectedRows(); for (int sel : selections) { Rectangle rc = table.getCellRect(sel, 0, true); g.fillRect(0, rc.y - viewRect.y, viewRect.width - 1, rc.height - 1); } // フォーカス状態を描画 int lead = table.getSelectionModel().getLeadSelectionIndex(); if (0 <= lead) { g.setColor(Color.BLACK); Rectangle rc = table.getCellRect(lead, 0, true); BasicGraphicsUtils.drawDashedRect(g, 0, rc.y - viewRect.y, viewRect.width, rc.height - 1); } g.setColor(saveColor); } private Color getTranslucentColor(Color color) { return new Color(color.getRed(), color.getGreen(), color.getBlue(), 30); } }
↓こんな感じになります.
セルのないところで行を選択できるようにするためには,JViewport に MouseListener を追加して対応すればいける.