Im having an issue with JTable columns. I create the JTable but the columns wont show up.And yes, I tried the previously asked question about this issue saying about adding a JScrollPane but putting the ScrollPane inside destroyed completely my Table and the Table wasn't visible.
I tried frame.getContentPane.add(new JScrollPane(table)) from this link (JTable won't show column headers) but didnt have any effect as I said above.
Im not using a layout manager.
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test1?user=me&password=12345");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM consoles INNER JOIN hardware ON consoles.id=hardware.id");
ResultSetMetaData md = rs.getMetaData();
int columnCount = md.getColumnCount();
String[] cols = new String[columnCount];
for (i=1;i<= columnCount;i++)
{
cols[i-1] = md.getColumnName(i);
}
DefaultTableModel model = new DefaultTableModel(cols,0);
while (rs.next())
{
Object[] row = new Object[columnCount];
for (i = 1 ; i <= columnCount ; i++)
{
row[i-1] = rs.getObject(i);
}
model.addRow(row);
}
JTable table = new JTable(model);
model.fireTableDataChanged();
table.setCellSelectionEnabled(true);
table.setColumnSelectionAllowed(true);
table.setFillsViewportHeight(true);
table.setSurrendersFocusOnKeystroke(true);
table.setBounds(146,59,763,360);
frame.getContentPane().add((table));
model.fireTableDataChanged();
}
JTable is designed to work with JScrollPane, it will automatically add the TableHeader to the scroll pane, for example
Instead of
frame.getContentPane().add((table));
Try using...
frame.getContentPane().add(new JScrollPane(table));
See How to Use Tables for more details
Beware, you should avoid using setBounds and instead use an appropriate layout manager, you should also void using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
Updated...
You should never need to call fireTableDataChanged or any other event methods on a model, they are not meant for your use, but for use within the model.
Before adding the table/scroll pane to the content pane, try this...
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(new JScrollPane(table));
Let me demonstrate...
With a layout manager...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class TableExample {
public static void main(String[] args) {
new TableExample();
}
public TableExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
int columnCount = 10;
String[] cols = new String[columnCount];
for (int i = 1; i <= columnCount; i++) {
cols[i - 1] = Integer.toString(i);
}
DefaultTableModel model = new DefaultTableModel(cols, 0);
JTable table = new JTable(model);
table.setCellSelectionEnabled(true);
table.setColumnSelectionAllowed(true);
table.setFillsViewportHeight(true);
table.setSurrendersFocusOnKeystroke(true);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Without a layout manager...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class TableExample {
public static void main(String[] args) {
new TableExample();
}
public TableExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
int columnCount = 10;
String[] cols = new String[columnCount];
for (int i = 1; i <= columnCount; i++) {
cols[i - 1] = Integer.toString(i);
}
DefaultTableModel model = new DefaultTableModel(cols, 0);
JTable table = new JTable(model);
table.setCellSelectionEnabled(true);
table.setColumnSelectionAllowed(true);
table.setFillsViewportHeight(true);
table.setSurrendersFocusOnKeystroke(true);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
The problem isn't with the code you've shown us, the problem is with your choice to do away with one of the core concepts upon which the Swing API is built on...the layout manager
You can try to get the TableHeader from the Table and add this to the ContentPane:
JTableHeader tableHeader = table.getTableHeader();
frame.getContentPane().add(tableHeader);
Either you have to wrap your table in a JScrollPane like this:
frame.getContentPane().add(new JScrollPane(table));
Or you have to add the table header separatly:
frame.getContentPane().add(table.getTableHeader, BorderLayout.NORTH);
frame.getContentPane().add(table); // By default this adds to CENTER
This assumes the layout manager of the content pane is the default BorderLayout.
Related
I've populated JTable from database. But the table is not appearing. I can not figure out the problem with the code. I can not understand whether the problem is with layout or the code block retrieving data from database. Also I am not getting any Exception message. I've added frame.getContentPane().add(scroll, BorderLayout.CENTER); in the code, still can not the table. Please see the attached image what I am getting.
import java.awt.EventQueue;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import controller.DB_con;
public class Jtable {
private JFrame frame;
private JTable table;
String[] columnNames = {"ID", "name", "username", "contact", "GENDER"};
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Jtable window = new Jtable();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.toString());
}
}
});
}
/**
* Create the application.
*/
public Jtable() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout(0, 0));
table = new JTable();
frame.getContentPane().add(table, BorderLayout.CENTER);
DefaultTableModel model = new DefaultTableModel();
model.setColumnIdentifiers(columnNames);
table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
table.setFillsViewportHeight(true);
JScrollPane scroll = new JScrollPane(table);
frame.getContentPane().add(scroll, BorderLayout.CENTER);
scroll.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scroll.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
try
{
Connection sqlCon = DB_con.getSQLConnection();
PreparedStatement ps = sqlCon.prepareStatement("select id,name,username,contact,gender from temp_tbl");
int i = 0;
ResultSet rs = ps.executeQuery();
while(rs.next())
{
String id = rs.getString("id");
String name = rs.getString("name");
String username = rs.getString("username");
String contact = rs.getString("contact");
String gender = rs.getString("gender");
model.addRow(new Object[]{id, name, username, contact, gender});
i++;
}
}
catch(Exception ex)
{
System.out.println(ex.toString());
}
}
}
You add the JTable to the frame, you then add it to the JScrollPane but never add the JScrollPane to the anything ...
A component can only reside within a single container, so when you do JScrollPane scroll = new JScrollPane(table);, you are removing the JTable from the frame.
Add frame.getContentPane().add(scroll, BorderLayout.CENTER); after you've created the JScrollPane
You also never apply the TableModel to the JTable
table.setModel(model);
frame.getContentPane().add(scroll, BorderLayout.CENTER);
I'm trying to display a JscrollPane using this code. but it's displaying a blank frame with just the "close" button displayed. Can't figure out why it wouldn't display. Any help would be greatly appreciated! :)
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.SQLException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.table.DefaultTableModel;
import edu.pitt.bank.Account;
import edu.pitt.bank.Transaction;
import edu.pitt.utilities.DbUtilities;
import edu.pitt.utilities.MySqlUtilities;
public class TransactionUI {
private JFrame frame;
private JScrollPane transactionPane;
private JTable tblTransactions;
public TransactionUI(Account userAccount) {
frame = new JFrame();
frame.setTitle("Account Transactions");
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
transactionPane = new JScrollPane();
frame.getContentPane().add(transactionPane);
DbUtilities db = new MySqlUtilities();
String [] cols = {"Type", "Amount", "Date"};
String sql = "SELECT type, amount, transactionDate FROM srp63_bank1017.transaction;";
try {
System.out.println("use getDataTable()");
DefaultTableModel transactionList = db.getDataTable(sql, cols);
System.out.println("getDataTable() used");
tblTransactions = new JTable(transactionList);
tblTransactions.setFillsViewportHeight(true);
tblTransactions.setShowGrid(true);
tblTransactions.setGridColor(Color.BLACK);
transactionPane.getViewport().add(tblTransactions);
} catch (SQLException e) {
e.printStackTrace();
}
JButton btnClose = new JButton("Close");
btnClose.setBounds(323, 212, 89, 23);
btnClose.setBounds(284, 214, 73, 23);
frame.getContentPane().add(btnClose);
}
public JFrame getFrame() {
return frame;
}
}
I use this to call the above frame from another class:
public void actionPerformed(ActionEvent arg0) {
if(userAccount.getAccountID() != null){
TransactionUI tUI = new TransactionUI(userAccount);
tUI.getFrame().setVisible(true);
} else {
System.out.println("Account object must not be null");
}
}
});
Here is the getDataTable method...
public DefaultTableModel getDataTable(String sqlQuery, String[] customColumnNames) throws SQLException{
ResultSet rs = getResultSet(sqlQuery);
/* Metadata object contains additional information about a ResulSet,
* such as database column names, data types, etc...
*/
ResultSetMetaData metaData = rs.getMetaData();
// Get column names from the metadata object and store them in a Vector variable
Vector<String> columnNames = new Vector<String>();
for(int column = 0; column < customColumnNames.length; column++){
columnNames.add(customColumnNames[column]);
}
// Create a nested Vector containing an entire table from the ResultSet
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
while(rs.next()){
Vector<Object> vector = new Vector<Object>();
for(int columnIndex = 1; columnIndex <= metaData.getColumnCount(); columnIndex++){
vector.add(rs.getObject(columnIndex));
}
data.add(vector);
}
return new DefaultTableModel(data, columnNames);
}
I received no errors
Problem #1
frame.getContentPane().setLayout(null);
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
See Laying Out Components Within a Container for more details
Problem #2
transactionPane.getViewport().add(tblTransactions);
Don't use ad with JScrollPane or JViewport, use
transactionPane.getViewport().setView(tblTransactions);
or
transactionPane.setViewportView(tblTransactions);
instead
See
How to Use Scroll Panes for more details
import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JTable table = new JTable(new DefaultTableModel(100, 100));
table.setGridColor(Color.LIGHT_GRAY);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(table);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Problem #3
The use of multiple windows, see The Use of Multiple JFrames, Good/Bad Practice? for a more in-depth discussion
I think what you really want is some kind of modal dialog. See How to Make Dialogs for more details
Your code without modifications
(Except removing the database code)
This is how your code looks on my PC, take a good hard look at the button...
Your code modified to use layout managers...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
TransactionUI ui = new TransactionUI();
JFrame frame = ui.getFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TransactionUI {
private JFrame frame;
private JScrollPane transactionPane;
private JTable tblTransactions;
public TransactionUI() {
frame = new JFrame();
frame.setTitle("Account Transactions");
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
transactionPane = new JScrollPane();
frame.getContentPane().add(transactionPane);
String[] cols = {"Type", "Amount", "Date"};
String sql = "SELECT type, amount, transactionDate FROM srp63_bank1017.transaction;";
System.out.println("use getDataTable()");
DefaultTableModel transactionList = new DefaultTableModel(100, 100);
System.out.println("getDataTable() used");
tblTransactions = new JTable(transactionList);
tblTransactions.setFillsViewportHeight(true);
tblTransactions.setShowGrid(true);
tblTransactions.setGridColor(Color.BLACK);
transactionPane.setViewportView(tblTransactions);
JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT));
JButton btnClose = new JButton("Close");
buttons.add(btnClose);
frame.getContentPane().add(buttons, BorderLayout.SOUTH);
}
public JFrame getFrame() {
return frame;
}
}
}
I have the following scenario: a JFrame which contains several JPanels that are selected using a CardLayout. One JPanel contains a pretty large JTable which I have wrapped in a JScrollPane and added the JScrollPane to the main JPanel:
package com.javaswingcomponents.demo;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.table.DefaultTableModel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class MyPanel extends JPanel {
private DefaultTableModel model = new DefaultTableModel();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setBounds(100, 100, 450, 535);
frame.getContentPane().add(new MyPanel());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MyPanel() {
JTable table = new JTable(model);
JScrollPane scrollPaneParte = new JScrollPane(table);
scrollPaneParte.setPreferredSize(new Dimension(600, 600));
scrollPaneParte.setBounds(10, 92, 867, 92);
add(scrollPaneParte);
scrollPaneParte.setViewportView(table);
addColumns(model);
}
public void addColumns(DefaultTableModel model) {
for (int ii=0;ii<10;ii++)
model.addColumn("Field"+ii);
}
}
I initially thought the problem was the XY (null) layout used, but even changing to BorderLayout nothing happens, that is, the ScrollBar is not displayed and only a part of the JTable is shown.
Any idea how to solve this issue?
EDIT: I have included a full working example which reproduces the issue.
This variant works reliably. Note that the default layout of a panel is flow layout. If the GUI becomes too small for the components in the flow layout, they will be truncated as in your example. I'd tend to change the layout to grid layout, which fixes the problem, in one sense. But in this example, we follow best practices for setting sizes (and locations) and enforce the minimum size.
import java.awt.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class MyPanel extends JPanel {
private DefaultTableModel model = new DefaultTableModel();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.getContentPane().add(new MyPanel());
frame.pack();
frame.setMinimumSize(frame.getSize());
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MyPanel() {
addColumns(model);
JTable table = new JTable(model);
JScrollPane scrollPaneParte = new JScrollPane(table);
add(scrollPaneParte);
}
public void addColumns(DefaultTableModel model) {
for (int ii=0;ii<10;ii++)
model.addColumn("Field"+ii);
}
}
I have looked and found that many people weren't putting their table into a scrollPane. Even though I nest my table into a scrollPane then into the frame it still fails to show the header. Is there something else I'm missing ? Thanks
public class Gui extends JFrame {
AbstractTableModel model;
JTable table;
public void start(AbstractTableModel model) {
this.model = model;
table=new JTable(model){
#Override
public boolean isCellEditable(int arg0, int arg1) {
return false;
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumn column = null;
for (int i = 0; i < model.getColumnCount(); i++) {
column = table.getColumnModel().getColumn(i);
column.setPreferredWidth(120);
column.setMaxWidth(300);
column.setMinWidth(50);
}
JScrollPane pane = new JScrollPane(table);
pane.setPreferredSize(new Dimension(900,900));
add(pane);
setLayout(new FlowLayout());
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
Based on your code and then having to add the missing functionality, you code works...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
public class Gui extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
Gui frame = new Gui();
frame.start(new DefaultTableModel(new Object[]{"A", "B", "C"}, 10));
}
});
}
AbstractTableModel model;
JTable table;
public void start(AbstractTableModel model) {
this.model = model;
table = new JTable(model) {
#Override
public boolean isCellEditable(int arg0, int arg1) {
return false;
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumn column = null;
for (int i = 0; i < model.getColumnCount(); i++) {
column = table.getColumnModel().getColumn(i);
column.setPreferredWidth(120);
column.setMaxWidth(300);
column.setMinWidth(50);
}
JScrollPane pane = new JScrollPane(table);
pane.setPreferredSize(new Dimension(900, 900));
add(pane);
setLayout(new FlowLayout());
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
}
This then leads to two broad assumptions...
You're TableModel doesn't have any columns
You're TableModel doesn't have any column names...
For example, a TableModel with no column names...
Personally...
I wouldn't use FlowLayout for this, BorderLayout will give better results
pack the frame before you make it visible
Set the layout before you add components as sometimes, things can get messed up...
For example...
setLayout(new FlowLayout()); // But I'd use a `BorderLayout`
add(pane);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true);
Here is an example table of what I have been using:
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane);
table = new JTable();
DefaultTableModel tableModel = new DefaultTableModel(new Object[]{"Row 1","Row 2"},0);
table.setModel(tableModel);
scrollPane.setViewportView(table);
I've attempted to use the following autoscrolling methods both with the same result.
// Method 1
JScrollBar vertical = scrollPane.getVerticalScrollBar();
vertical.setValue(vertical.getMaximum());
// Method 2
table.scrollRectToVisible(table.getCellRect(table.getRowCount(), 0, true));
Both examples go to the near-bottom of the table, up until the last (bottom) row that the user has to scroll down to see, only to happen again when another row is added.
EDIT: Example code to replicate the problem
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JScrollPane;
import javax.swing.table.DefaultTableModel;
public class ScrollTableEx extends JFrame {
private static final long serialVersionUID = 1L;
public int i = 100;
public JScrollPane scrollPane;
public JPanel contentPane;
public JTable table;
public JButton add;
public DefaultTableModel model = new DefaultTableModel(new Object[] { "Int (+)", "Int (-)" }, 0);
public static void main(String[] args) {
ScrollTableEx frame = new ScrollTableEx();
frame.setVisible(true);
}
public ScrollTableEx() {
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
setSize(500,400);
scrollPane = new JScrollPane();
table = new JTable();
table.setCellSelectionEnabled(true);
table.setModel(model);
scrollPane.setViewportView(table);
for (int i = 0; i < 100; i++) {
model.addRow(new Object[] { i, i * -1 });
Rectangle goodRect = table.getCellRect(model.getRowCount() - 1, 0, true);
table.scrollRectToVisible(goodRect);
}
JButton add = new JButton("Add");
add.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Rectangle goodRect = table.getCellRect(model.getRowCount() - 1, 0, true);
table.scrollRectToVisible(goodRect);
model.addRow(new Object[] { i, i * -1 });
i++;
}
});
add(add, BorderLayout.NORTH);
add(scrollPane, BorderLayout.CENTER);
}
}
The problem is, JTable and TableModel are both 0 indexed. That is, the last value is actually rowCount - 1.
So when you use table.getCellRect(table.getRowCount(), 0, true), it's actually returning a Rectangle of the right position, just with a 0 height, because the row doesn't actually exist.
Instead you want to use table.getCellRect(table.getRowCount() - 1, 0, true)
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class ScrollTable {
public static void main(String[] args) {
new ScrollTable();
}
public ScrollTable() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final DefaultTableModel model = new DefaultTableModel(new Object[]{"Test"}, 0);
for (int index = 0; index < 100; index++) {
model.addRow(new Object[]{index});
}
final JTable table = new JTable(model);
JButton add = new JButton("Add");
add.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
model.addRow(new Object[]{model.getRowCount()});
Rectangle badRect = table.getCellRect(model.getRowCount(), 0, true);
Rectangle goodRect = table.getCellRect(model.getRowCount() - 1, 0, true);
System.out.println("bad = " + badRect);
System.out.println("goodRect = " + goodRect);
table.scrollRectToVisible(goodRect);
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.add(add, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I would avoid using .setBounds where possible. It does not take into consideration the variety of differences that exist between different computers and OS's and while it might look perfectly fine when you are developing, when you move it another system, it could produce undeseriable results - IMHO