I have to synchronize the horizontal scrolling of tables. The columns would be the same only property that can be changed for the columns is their size. Now the following code shows 3 tables with synchronised scrolling. But as i change size of any one column in any of the table and then try to scroll, i get an Stack Overflow error and the gui is distorted.
I am trying to achieve it by setting the viewport position of rest of the tables to the column which comes first on the left hand side.
If the size of the columns are different then then from the percentage scrolled for that column i am reconstructing the position of other table.
import java.awt.Color;
import java.awt.Point;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
public class ScrollableJTable implements AdjustmentListener{
JFrame frame = null;
JPanel panel = null;
JTable table = null;
JTableHeader header = null;
JScrollPane pane = null;
JTable table1 = null;
JTableHeader header1 = null;
JScrollPane pane1 = null;
JTable table2 = null;
JTableHeader header2 = null;
JScrollPane pane2 = null;
public static void main(String[] args) {
new ScrollableJTable();
}
public ScrollableJTable() {
frame = new JFrame("Creating a Scrollable JTable!");
panel = new JPanel();
String data[][] = {
{"001", "vinod", "Bihar", "India", "Biology", "65", "First","001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"002", "Raju", "ABC", "Kanada", "Geography", "58", "second","001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"003", "Aman", "Delhi", "India", "computer", "98", "Dictontion","001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"004", "Ranjan", "Bangloor", "India", "chemestry", "90", "Dictontion","001", "vinod", "Bihar", "India", "Biology", "65", "First"}
};
String col[] = {"Roll", "Name", "State", "country", "Math", "Marks", "Grade","Roll", "Name", "State", "country", "Math", "Marks", "Grade"};
table = new JTable(data, col);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
header = table.getTableHeader();
header.setBackground(Color.yellow);
pane = new JScrollPane(table);
pane.getHorizontalScrollBar().addAdjustmentListener(this);
pane.setSize(100, 100);
table1 = new JTable(data, col);
table1.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
header1 = table1.getTableHeader();
header1.setBackground(Color.yellow);
pane1 = new JScrollPane(table1);
pane1.getHorizontalScrollBar().addAdjustmentListener(this);
pane1.setSize(100, 100);
table2 = new JTable(data, col);
table2.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
header2 = table2.getTableHeader();
header2.setBackground(Color.yellow);
pane2 = new JScrollPane(table2);
pane2.getHorizontalScrollBar().addAdjustmentListener(this);
pane2.setSize(100, 100);
panel.setSize(500, 500);
panel.add(pane);
panel.add(pane1);
panel.add(pane2);
frame.add(panel);
frame.pack();
frame.setSize(1000, 1000);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void adjustmentValueChanged(AdjustmentEvent e) {
JScrollPane scrollPane = null, scroll = null;
JScrollBar bar = null;
int position[] = null;
bar = (JScrollBar) e.getAdjustable();
scroll = (JScrollPane) bar.getParent();
position = this.getFirstVisibleColumnIndex(scroll);
for (int j = 0; j < panel.getComponentCount(); j++) {
scrollPane = (panel.getComponent(j) instanceof JScrollPane) ? (JScrollPane) panel.getComponent(j) : null;
if (scrollPane != null && scrollPane != scroll) this.setFirstColumnVisiblePosition(position, scrollPane);
}
}
private int[] getFirstVisibleColumnIndex(JScrollPane scroll) {
JTable table = null;
TableColumnModel model = null;
Object obj = null;
int retval[] = null, index = -1, position = -1, relpos = -1;
if (scroll == null) return null;
obj = scroll.getViewport().getView();
table = (obj instanceof JTable ? (JTable)obj : null);
if (table == null) return null;
model = table.getColumnModel();
if (model == null) return null;
position = scroll.getViewport().getViewPosition().x;
for (int column = 0; index == -1 && column < model.getColumnCount(); column++) {
position = position - model.getColumn(column).getWidth();
if (position < 0) {
index = column;
relpos = ((position + model.getColumn(column).getWidth()) * 100) / model.getColumn(column).getWidth();
}
}
retval = new int[2];
retval[0] = index;
retval[1] = relpos;
return retval;
}
private boolean setFirstColumnVisiblePosition(int position[], JScrollPane scroll) {
JTable table = null;
TableColumnModel model = null;
Object obj = null;
int pos = 0, width = 0;
if (scroll == null || position == null) return false;
obj = scroll.getViewport().getView();
table = (obj instanceof JTable ? (JTable)obj : null);
if (table == null) return false;
model = table.getColumnModel();
if (model == null) return false;
if (position[0] == -1 || position [1] == -1) return false;
for (int column = 0; column < position[0]; column++) {
pos = pos + model.getColumn(column).getWidth();
}
width = model.getColumn(position[0]).getWidth();
pos = pos + ((position[1] * width) / 100);
scroll.getViewport().setViewPosition(new Point(pos, scroll.getViewport().getViewPosition().y));
return true;
}
}
there are important issues as AdjustmentListener
hardcoded for last JScrollBar
only (cant comment something works, better coud be know the value for all JScrollBars and recalculate the concrete value for another JScrollBars)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.JTableHeader;
public class ScrollableJTable {
private JFrame frame = null;
private JPanel panel = null;
private JTable table = null;
private JTableHeader header = null;
private JScrollPane pane = null;
private JTable table1 = null;
private JTableHeader header1 = null;
private JScrollPane pane1 = null;
private JTable table2 = null;
private JTableHeader header2 = null;
private JScrollPane pane2 = null;
public static void main(String[] args) {
new ScrollableJTable();
}
public ScrollableJTable() {
frame = new JFrame("Creating a Scrollable JTable!");
panel = new JPanel();
String data[][] = {
{"001", "vinod", "Bihar", "India", "Biology", "65", "First", "001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"002", "Raju", "ABC", "Kanada", "Geography", "58", "second", "001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"003", "Aman", "Delhi", "India", "computer", "98", "Dictontion", "001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"004", "Ranjan", "Bangloor", "India", "chemestry", "90", "Dictontion", "001", "vinod", "Bihar", "India", "Biology", "65", "First"}
};
String col[] = {"Roll", "Name", "State", "country", "Math", "Marks", "Grade", "Roll", "Name", "State", "country", "Math", "Marks", "Grade"};
table = new JTable(data, col);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
header = table.getTableHeader();
header.setBackground(Color.yellow);
pane = new JScrollPane(table);
pane.setPreferredSize(new Dimension(400, 200));
table1 = new JTable(data, col);
table1.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
header1 = table1.getTableHeader();
header1.setBackground(Color.yellow);
pane1 = new JScrollPane(table1);
pane1.setPreferredSize(new Dimension(400, 200));
table2 = new JTable(data, col);
table2.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
header2 = table2.getTableHeader();
header2.setBackground(Color.yellow);
pane2 = new JScrollPane(table2);
pane2.setPreferredSize(new Dimension(200, 200));
panel.setSize(500, 500);
panel.add(pane);
panel.add(pane1);
panel.add(pane2);
frame.add(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
final JScrollBar bar = pane.getHorizontalScrollBar();
final JScrollBar bar1 = pane1.getHorizontalScrollBar();
final JScrollBar bar2 = pane2.getHorizontalScrollBar();
bar2.addAdjustmentListener(new AdjustmentListener() {
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
bar.setValue(e.getValue());
bar1.setValue(e.getValue());
}
});
}
}
don't use setSize
, most of LayoutManagers
accepting PreferredSize
(hardcoded in my code example)
FlowLayout
(built_in LayoutManager
for JPanel
) accepting only PreferredSize
use JFrame#pack()
rether than JFrame#setSize(int, int)
have look at InitialThread
(event everybody can tell you that) output from AdjustmentListener
is done on EDT, wrap output to the invokeLater()
in the case that you hare to calculate value for different JScrollBars
with different size on the screen, output should be delayed and then nicer, without jumping of JScrollPane
s contens on the screen
EDIT
whatever, anything I tried no exception, only in the case that ColumnModel doesn't equals RowModel, rest is only to calculate the ratio for every ScrollBars Models
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.JTableHeader;
public class ScrollableJTable {
private JFrame frame = null;
private JPanel panel = null;
private JTable table = null;
private JTableHeader header = null;
private JScrollPane pane = null;
private JTable table1 = null;
private JTableHeader header1 = null;
private JScrollPane pane1 = null;
private JTable table2 = null;
private JTableHeader header2 = null;
private JScrollPane pane2 = null;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
ScrollableJTable scrollableJTable = new ScrollableJTable();
}
});
}
public ScrollableJTable() {
frame = new JFrame("Creating a Scrollable JTable!");
panel = new JPanel();
String data[][] = {
{"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"002", "Raju", "ABC", "Kanada", "Geography", "58", "second",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"003", "Aman", "Delhi", "India", "computer", "98", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"004", "Ranjan", "Bangloor", "India", "chemestry", "90", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"}
};
String data1[][] = {
{"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"002", "Raju", "ABC", "Kanada", "Geography", "58", "second",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"002", "Raju", "ABC", "Kanada", "Geography", "58", "second",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"003", "Aman", "Delhi", "India", "computer", "98", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"003", "Aman", "Delhi", "India", "computer", "98", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"004", "Ranjan", "Bangloor", "India", "chemestry", "90", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"004", "Ranjan", "Bangloor", "India", "chemestry", "90", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"}
};
String data2[][] = {
{"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"002", "Raju", "ABC", "Kanada", "Geography", "58", "second",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"002", "Raju", "ABC", "Kanada", "Geography", "58", "second",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"002", "Raju", "ABC", "Kanada", "Geography", "58", "second",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"003", "Aman", "Delhi", "India", "computer", "98", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"003", "Aman", "Delhi", "India", "computer", "98", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"003", "Aman", "Delhi", "India", "computer", "98", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"},
{"004", "Ranjan", "Bangloor", "India", "chemestry", "90", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"004", "Ranjan", "Bangloor", "India", "chemestry", "90", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First",
"004", "Ranjan", "Bangloor", "India", "chemestry", "90", "Dictontion",
"001", "vinod", "Bihar", "India", "Biology", "65", "First"}
};
String col[] = {"Roll", "Name", "State", "country", "Math", "Marks",
"Grade", "Roll", "Name", "State", "country", "Math", "Marks", "Grade"};
String col1[] = {"Roll", "Name", "State", "country", "Math", "Marks",
"Grade", "Roll", "Name", "State", "country", "Math", "Marks", "Grade",
"Roll", "Name", "State", "country", "Math", "Marks", "Grade",
"Roll", "Name", "State", "country", "Math", "Marks", "Grade"};
String col2[] = {"Roll", "Name", "State", "country", "Math", "Marks",
"Grade", "Roll", "Name", "State", "country", "Math", "Marks", "Grade",
"Roll", "Name", "State", "country", "Math", "Marks", "Grade",
"Roll", "Name", "State", "country", "Math", "Marks", "Grade",
"Roll", "Name", "State", "country", "Math", "Marks", "Grade",
"Roll", "Name", "State", "country", "Math", "Marks", "Grade"};
table = new JTable(data, col);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
header = table.getTableHeader();
header.setBackground(Color.yellow);
pane = new JScrollPane(table);
pane.setPreferredSize(new Dimension(400, 200));
table1 = new JTable(data1, col1);
table1.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table1.setPreferredScrollableViewportSize(table1.getPreferredSize());
header1 = table1.getTableHeader();
header1.setBackground(Color.yellow);
pane1 = new JScrollPane(table1);
pane1.setPreferredSize(new Dimension(400, 200));
table2 = new JTable(data2, col2);
table2.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table2.setPreferredScrollableViewportSize(table2.getPreferredSize());
header2 = table2.getTableHeader();
header2.setBackground(Color.yellow);
pane2 = new JScrollPane(table2);
pane2.setPreferredSize(new Dimension(200, 200));
panel.setSize(500, 500);
panel.add(pane);
panel.add(pane1);
panel.add(pane2);
frame.add(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
final JScrollBar bar = pane.getHorizontalScrollBar();
final JScrollBar bar1 = pane1.getHorizontalScrollBar();
final JScrollBar bar2 = pane2.getHorizontalScrollBar();
bar2.addAdjustmentListener(new AdjustmentListener() {
@Override
public void adjustmentValueChanged(final AdjustmentEvent e) {
if (e.getValueIsAdjusting()) {
final int i = bar.getMaximum();
if (e.getValue() > i) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
bar.setValue(i);
}
});
} else {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
bar.setValue(e.getValue());
}
});
}
final int i1 = bar1.getMaximum();
if (e.getValue() > i1) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
bar1.setValue(i1);
}
});
} else {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
bar1.setValue(e.getValue());
}
});
}
}
}
});
}
}