import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneLayout;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.TableColumnModel;
/**
*
* @author raistlic
* @date Jan 28, 2013
*/
public class JSplitScrollPane extends JScrollPane {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {
e.printStackTrace();
}
JFrame f = new JFrame("Test Normal ScrollPane");
TestTableModel tm = new TestTableModel(100, 30);
JTable rowHeader = tm.getRowHeaderTable();
JTable content = tm.getContentTable();
JScrollPane pane = new JSplitScrollPane();
pane.setViewportView(content);
pane.setColumnHeaderView(content.getTableHeader());
pane.setRowHeaderView(rowHeader);
pane.setCorner(JScrollPane.UPPER_LEFT_CORNER, rowHeader.getTableHeader());
f.getContentPane().add(pane, BorderLayout.CENTER);
f.setSize(800, 600);
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setVisible(true);
}
});
}
private final JSplitPane splitPane;
private JPanel left, right;
public JSplitScrollPane() {
super();
splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
left = new JPanel(this.new RowHeaderLayout());
right = new JPanel(this.new ContentLayout());
splitPane.setLeftComponent(left);
splitPane.setRightComponent(right);
setLayout(new SplitedScrollPaneLayout());
setRowHeader(createViewport());
setColumnHeader(createViewport());
setViewport(createViewport());
left.add(getRowHeader());
right.add(getViewport());
right.add(getColumnHeader());
right.add(getHorizontalScrollBar());
right.add(getVerticalScrollBar());
this.add(splitPane);
}
@Override
public void setCorner(String key, Component corner) {
Component old = getCorner(key);
super.setCorner(key, corner);
if(old != null)
left.remove(old);
if( corner != null ) {
if( key.equals(UPPER_LEFT_CORNER) ||
key.equals(LOWER_LEFT_CORNER) )
left.add(corner);
else
right.add(corner); // probably problematic, just for demo
}
}
private int calculateTopPreferredHeight() {
int result = 0;
Component c = getCorner(UPPER_LEFT_CORNER);
if( c != null )
result = Math.max(result, c.getPreferredSize().height);
c = getCorner(UPPER_RIGHT_CORNER);
if( c != null )
result = Math.max(result, c.getPreferredSize().height);
c = getColumnHeader();
if( c != null )
result = Math.max(result, c.getPreferredSize().height);
return result;
}
private int calculateBottomPreferredHeight() {
int result = 0;
Component c = getHorizontalScrollBar();
result = Math.max(result, c.getPreferredSize().height);
c = getCorner(LOWER_LEFT_CORNER);
if( c != null )
result = Math.max(result, c.getPreferredSize().height);
c = getCorner(LOWER_RIGHT_CORNER);
if( c != null )
result = Math.max(result, c.getPreferredSize().height);
return result;
}
private int calculateCenterPreferredHeight() {
int result = 0;
Component c = getRowHeader();
if( c != null )
result = Math.max(result, c.getPreferredSize().height);
c = getViewport();
if( c != null )
result = Math.max(result, c.getPreferredSize().height);
return result;
}
private int calculateLeftPreferredWidth() {
int result = 0;
Component c = getCorner(UPPER_LEFT_CORNER);
if( c != null )
result = Math.max(result, c.getPreferredSize().width);
c = getCorner(LOWER_LEFT_CORNER);
if( c != null )
result = Math.max(result, c.getPreferredSize().width);
c = getRowHeader();
if( c != null )
result = Math.max(result, c.getPreferredSize().width);
return result;
}
private int calculateCenterPreferredWidth() {
int result = 0;
Component c = getColumnHeader();
if( c != null )
result = Math.max(result, c.getPreferredSize().width);
c = getViewport();
if( c != null )
result = Math.max(result, c.getPreferredSize().width);
return result;
}
private int calculateRightPreferredWidth() {
int result = 0;
Component c = getCorner(UPPER_RIGHT_CORNER);
if( c != null )
result = Math.max(result, c.getPreferredSize().width);
c = getCorner(LOWER_RIGHT_CORNER);
if( c != null )
result = Math.max(result, c.getPreferredSize().width);
c = getVerticalScrollBar();
if( c != null )
result = Math.max(result, c.getPreferredSize().width);
return result;
}
private class RowHeaderLayout implements LayoutManager {
@Override
public void addLayoutComponent(String name, Component comp) {}
@Override
public void removeLayoutComponent(Component comp) {}
@Override
public Dimension preferredLayoutSize(Container parent) {
int top = calculateTopPreferredHeight();
int center = calculateCenterPreferredHeight();
int bottom = calculateBottomPreferredHeight();
int width = calculateLeftPreferredWidth();
return new Dimension(width, top + center + bottom);
}
@Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}
@Override
public void layoutContainer(Container parent) {
Rectangle bounds = parent.getBounds();
bounds.x = 0;
bounds.y = 0;
Insets insets = parent.getInsets();
bounds.x += insets.left;
bounds.y += insets.top;
bounds.width -= insets.left + insets.right;
if( bounds.width <= 0 )
return;
bounds.height -= insets.top + insets.bottom;
if( bounds.height <= 0 )
return;
int top = Math.min(calculateTopPreferredHeight(), bounds.height);
Component c = getCorner(UPPER_LEFT_CORNER);
if( c != null )
c.setBounds(bounds.x, bounds.y, bounds.width, top);
bounds.y += top;
bounds.height -= top;
if( bounds.height <= 0 )
return;
int bottom = Math.min(calculateBottomPreferredHeight(), bounds.height);
c = getCorner(LOWER_LEFT_CORNER);
if( c != null )
c.setBounds(bounds.x, bounds.y + bounds.height - bottom, bounds.width, bottom);
bounds.height -= bottom;
if( bounds.height <= 0 )
return;
c = getRowHeader();
if( c != null )
c.setBounds(bounds);
}
}
private class ContentLayout implements LayoutManager {
@Override
public void addLayoutComponent(String name, Component comp) {}
@Override
public void removeLayoutComponent(Component comp) {}
@Override
public Dimension preferredLayoutSize(Container parent) {
int heightTop = calculateTopPreferredHeight();
int heightCenter = calculateCenterPreferredHeight();
int heightBottom = calculateBottomPreferredHeight();
int widthCenter = calculateCenterPreferredWidth();
int widthRight = calculateRightPreferredWidth();
return new Dimension(widthCenter + widthRight,
heightTop + heightCenter + heightBottom);
}
@Override
public Dimension minimumLayoutSize(Container parent) {
return new Dimension(100, 100);
}
@Override
public void layoutContainer(Container parent) {
Rectangle bounds = parent.getBounds();
bounds.x = 0;
bounds.y = 0;
Insets insets = parent.getInsets();
bounds.x += insets.left;
bounds.y += insets.top;
bounds.width -= insets.left + insets.right;
bounds.height -= insets.top + insets.bottom;
if( bounds.width <= 0 )
return;
if( bounds.height <= 0 )
return;
int rightWidth = Math.min(bounds.width, calculateRightPreferredWidth());
Rectangle right = new Rectangle(
bounds.x + bounds.width - rightWidth, bounds.y, rightWidth, bounds.height);
Rectangle center = new Rectangle(
bounds.x, bounds.y, bounds.width - right.width, bounds.height);
int top = Math.min(bounds.height, calculateTopPreferredHeight());
Component c = getCorner(UPPER_RIGHT_CORNER);
if( c != null )
c.setBounds(right.x, right.y, right.width, top);
c = getColumnHeader();
if( c != null && center.width > 0 )
c.setBounds(center.x, center.y, center.width, top);
right.y += top;
right.height -= top;
center.y += top;
center.height -= top;
if( right.height <= 0 )
return;
int bottom = Math.min(right.height, calculateBottomPreferredHeight());
c = getCorner(LOWER_RIGHT_CORNER);
if( c != null )
c.setBounds(right.x, right.y, right.width, bottom);
getHorizontalScrollBar().setBounds(
center.x, center.y + center.height - bottom, center.width, bottom);
right.height -= bottom;
center.height -= bottom;
if( right.height <= 0 )
return;
getVerticalScrollBar().setBounds(right);
c = getViewport();
if( c != null )
c.setBounds(center);
}
}
private static class SplitedScrollPaneLayout extends ScrollPaneLayout {
@Override
public void addLayoutComponent(String name, Component comp) {}
@Override
public void removeLayoutComponent(Component comp) {}
@Override
public Dimension preferredLayoutSize(Container parent) {
@SuppressWarnings("unchecked")
JSplitScrollPane ssp = (JSplitScrollPane)parent;
return ssp.splitPane.getPreferredSize();
}
@Override
public Dimension minimumLayoutSize(Container parent) {
@SuppressWarnings("unchecked")
JSplitScrollPane ssp = (JSplitScrollPane)parent;
return ssp.splitPane.getMinimumSize();
}
@Override
public void layoutContainer(Container parent) {
@SuppressWarnings("unchecked")
JSplitScrollPane ssp = (JSplitScrollPane)parent;
Rectangle rec = ssp.getBounds();
rec.x = 0;
rec.y = 0;
Insets insets = ssp.getInsets();
rec.x += insets.left;
rec.y += insets.top;
rec.width -= insets.left + insets.right;
rec.height -= insets.top + insets.bottom;
ssp.splitPane.setBounds(rec);
}
}
}
class TestTableModel extends AbstractTableModel {
private int rows;
private int cols;
private JTable rowHeader;
private JTable content;
TestTableModel(int rows, int cols) {
assert rows > 0;
assert cols > 0;
this.rows = rows;
this.cols = cols;
rowHeader = createRowHeaderTable();
content = createContentTable();
rowHeader.setPreferredScrollableViewportSize(new Dimension(150, 150));
rowHeader.setSelectionModel(content.getSelectionModel());
content.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
}
JTable getRowHeaderTable() {
return rowHeader;
}
JTable getContentTable() {
return content;
}
@Override
public int getRowCount() {
return rows;
}
@Override
public int getColumnCount() {
return cols + 1;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if( columnIndex == 0 )
return String.format("Row Header %03d", rowIndex + 1);
else
return String.format("Cell [ %03d, %03d ]", rowIndex + 1, columnIndex);
}
private JTable createRowHeaderTable() {
JTable table = new JTable(this);
TableColumnModel model = new DefaultTableColumnModel();
model.addColumn(table.getColumnModel().getColumn(0));
table.setColumnModel(model);
return table;
}
private JTable createContentTable() {
JTable table = new JTable(this);
TableColumnModel model = table.getColumnModel();
model.removeColumn(model.getColumn(0));
table.setColumnModel(model);
return table;
}
}
这里就先不作整理了。