Continue JTable data on another JTable beside it instead of scrolling
I've got a JTable displaying more than 200 rows. I'd like to show all the rows in a JPanel so that the user doesn't have to scroll down.
I've tried to get the number of visible rows in my first table and add another JTable with remaining rows, using viewport as shown in https://coderanch.com/t/340707/java/find-visible-row-count-JTable.
However, the method returns the number of visible rows only after the panel is painted and visible to users. So I can't add another JTable dynamically to the same panel.
Following is the code I've used to achieve the above requirement, but the new table is added only when button is clicked. I tried to add tables dynamically based on visible rows in lastTable, but as explained above, I don't get the correct numbers of visible rows until the table appears in viewport.
import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JViewport; import javax.swing.ScrollPaneConstants; import javax.swing.table.AbstractTableModel; public class DataPanel extends JPanel{ /** * */ private static final long serialVersionUID = 1L; List data = new ArrayList(); JScrollPane scrollPane; JTable table, lastTable; JPanel boxPanel; int rows = 0; public DataPanel() { for (int i = 0; i newData = getData(rows); DataModel newModel = new DataModel(newData); JTable newTable = new JTable(newModel); lastTable = newTable; JScrollPane newScrollPane = new JScrollPane(newTable); newScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); boxPanel.add(newScrollPane); } } private List getData(int rows) { // TODO Auto-generated method stub List newData = new ArrayList(); for(int i=0; i= rows) { newData.add(data.get(i)); } } return newData; } private int getVisibleRowCount(JTable table) { JViewport viewport = (JViewport) table.getParent(); Dimension extentSize = viewport.getExtentSize(); // JViewport int visibleRows = extentSize.height/table.getRowHeight(); return visibleRows; } public static void main(String args[]) { new DataPanel(); } private class DataModel extends AbstractTableModel{ static final int COL1_INDEX = 0; static final int COL2_INDEX = 1; private final String[] COLUMN_NAMES = new String[] {"ID", "Name"}; private List data = new ArrayList(); public DataModel(List newData) { data = newData; } public List getData() { return data; } public void setData(List data) { this.data = data; } @Override public int getColumnCount() { // TODO Auto-generated method stub return COLUMN_NAMES.length; } @Override public int getRowCount() { // TODO Auto-generated method stub if (null == data) return 0; return data.size(); } @Override public Object getValueAt(int row, int col) { // TODO Auto-generated method stub System.out.println("Requesting Row :" + row + " and Column : " + col); if (col == COL1_INDEX) { return row; }else { return data.get(row); } } @Override public String getColumnName(int column) { // TODO Auto-generated method stub return COLUMN_NAMES[column]; } } }
Any help in solving this issue is much appreciated. Thanks in advance.
I've figured out a way to solve the above issue. I've added a component listener to the frame and whenever its size changes, I've looped through the tables and changed the DataModel of those tables to show only visible rows.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
import javax.swing.table.AbstractTableModel;
public class DataPanel extends JPanel{
/**
*
*/
private static final long serialVersionUID = 1L;
private static final int ROW_HEIGHT = 18;
List<String> data = new ArrayList<String>();
List<JTable> tables = new ArrayList<JTable>();
JScrollPane scrollPane;
JTable table, lastTable;
JPanel boxPanel;
JFrame f;
int rows = 0;
public DataPanel()
{
for (int i = 0; i < 50; i++)
data.add("Blah " + i);
DataModel tableData = new DataModel(data);
tableData.setData(data);
setLayout(new BorderLayout());
/*JButton btn = new JButton("Action");
btn.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
addTable();
}
});
add(btn, BorderLayout.NORTH);*/
boxPanel = new JPanel();
boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.X_AXIS));
addTable();
add(boxPanel, BorderLayout.CENTER);
f = new JFrame();
f.getContentPane().add(this);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(500,500);
f.setVisible(true);
f.addComponentListener(adapter);
}
protected void addTable() {
// TODO Auto-generated method stub
while (rows < data.size())
{
System.out.println("Querying " + rows);
List<String> newData = getData(rows);
rows += getVisibleRowCount();
DataModel newModel = new DataModel(newData);
JTable newTable = new JTable(newModel);
lastTable = newTable;
newTable.setRowHeight(ROW_HEIGHT);
JScrollPane newScrollPane = new JScrollPane(newTable);
tables.add(newTable);
newScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
boxPanel.add(newScrollPane);
System.out.println("Now " + rows);
}
}
private ComponentAdapter adapter = new ComponentAdapter()
{
@Override
public void componentResized(ComponentEvent arg0) {
// TODO Auto-generated method stub
//super.componentResized(arg0);
rows = 0;
for (JTable eachTable : tables)
{
List<String> newData = getData(rows);
rows += getVisibleRowCount();
DataModel newModel = new DataModel(newData);
eachTable.setModel(newModel);
((DataModel)eachTable.getModel()).fireTableDataChanged();
}
}
};
private List<String> getData(int rows) {
// TODO Auto-generated method stub
List<String> newData = new ArrayList<String>();
int j = 0;
for(int i=0; i<data.size() && j < getVisibleRowCount(); i++)
{
if (i >= rows)
{
newData.add(data.get(i));
j++;
}
}
return newData;
}
private int getVisibleRowCount()
{
Dimension extentSize = null;
int visibleRows = 12;
if (null != f)
{
extentSize = f.getSize();
visibleRows = (extentSize.height - 50)/ROW_HEIGHT;
}
return visibleRows;
}
public static void main(String args[])
{
new DataPanel();
}
private class DataModel extends AbstractTableModel{
static final int COL1_INDEX = 0;
static final int COL2_INDEX = 1;
private final String[] COLUMN_NAMES = new String[]
//LM2 - B & O abbreviations to be replaced by B & S. - HP 17e9355d63
//LM2 - brokers should be able to see trader names in the order panel - HP e4fbaa791a
{"ID", "Name"};
private List<String> data = new ArrayList<String>();
public DataModel(List<String> newData)
{
data = newData;
}
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
@Override
public int getColumnCount() {
// TODO Auto-generated method stub
return COLUMN_NAMES.length;
}
@Override
public int getRowCount() {
// TODO Auto-generated method stub
if (null == data)
return 0;
return data.size();
}
@Override
public Object getValueAt(int row, int col) {
// TODO Auto-generated method stub
if (col == COL1_INDEX)
{
return row;
}else
{
return data.get(row);
}
}
@Override
public String getColumnName(int column) {
// TODO Auto-generated method stub
return COLUMN_NAMES[column];
}
}
}
I'm not sure if this is an efficient way, but it works and that's what I need for now. Please let me know if there's a better way to solve this issue.
Thanks again.