JTable value being overwritten - java

My GUI application is Connecting to the DB and I have managed to add a product from the DB to my JTable on the GUI. When I click a second button it overwrites the first. I do not want this as it is an order till system and I want whatever I click to appear on the table as it is clicked. Is there any way to append onto the table rather than overwriting the values every time. Here is my code.
americanoSmall.addActionListener(
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try {
String query = "select ProductName, Price from product where ProductID = 24";
java.sql.PreparedStatement pst = connection.prepareStatement(query);
ResultSet rs = pst.executeQuery();
table.setModel(DbUtils.resultSetToTableModel(rs));
} catch (Exception e1)
{
e1.printStackTrace();
}
}
});

Don't change the table model whenever the model changes. Instead, use the addRow method of the TableModel. Here's a minimal, complete and verifiable example.
import java.awt.BorderLayout;
import java.awt.Container;
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.table.DefaultTableModel;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame("Test");
Container cont = frame.getContentPane();
cont.setLayout(new BorderLayout());
DefaultTableModel dtm = new DefaultTableModel(new Object[]{"Column 1","Column 2"}, 0);
JTable table = new JTable(dtm);
JScrollPane scroll = new JScrollPane(table);
cont.add(scroll, BorderLayout.CENTER);
dtm.addRow(new Object[]{"Value 1", "Value 2"});
JButton add = new JButton("Add");
cont.add(add, BorderLayout.NORTH);
add.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dtm.addRow(new Object[]{"Another value", "Another value"});
}
});
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

Related

JTable add row after sorting bug

I have a JTable and it setAutoCreateRowSorter(true) so that I can sort the row. When I add a row to the table without using sorting, it works fine. But When I sort the table first, (just clicking the column title and rows will be sorted), then add a row to the table bugged.
I used tableModel.addRow(new Object[]{row,row}); to add a row, TableModelListener to listen the insert event. The bug is in the TableModelListener, which means I couldn't find the row I just added,
java.lang.ArrayIndexOutOfBoundsException: 3
Here's my SSCCE, it's a dialog with a table, clicking the button 'add' to Add a row to the table.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import java.awt.GridLayout;
import javax.swing.JTable;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JScrollPane;
public class MainTable extends JDialog {
private static final long serialVersionUID = 156332386872772726L;
private final JPanel contentPanel = new JPanel();
private DefaultTableModel tableModel;
private JTable table;
public static void main(String[] args) {
try {
MainTable dialog = new MainTable();
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public MainTable() {
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(new GridLayout(1, 0, 0, 0));
{
JScrollPane scrollPane = new JScrollPane();
contentPanel.add(scrollPane);
{
table = new JTable();
table.setAutoCreateRowSorter(true);
tableModel = new DefaultTableModel(new String[]{"first","second"},0);
table.setModel(tableModel);
tableModel.addTableModelListener(new TableModelListener(){
#Override
public void tableChanged(TableModelEvent arg0) {
if(arg0.getType() == TableModelEvent.INSERT){
int row = arg0.getFirstRow();
System.out.println(table.getValueAt(row, 0));//bug!! I couldn't find the row I added.
}
}
});
scrollPane.setViewportView(table);
}
}
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("Add");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
int row = tableModel.getRowCount();
tableModel.addRow(new Object[]{row,row});//click button to add a row
}
});
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
}
}
}
}
What I tried
convert row index to model index doesn't work.
use tableModel.insert() instead tableModel.add(),doesn't work.
convert row index to model index doesn't work.
A TableModelListener is a listener for changes to the TableModel. So indexes in the TableModelEvent are relative to the TableModel.
System.out.println(table.getValueAt(row, 0));
Should be:
System.out.println(table.getModel().getValueAt(row, 0));
to get the data from the TableModel.
Or if you want to get the data from the JTable, then you need to use the convertRowIndexToView(...) method.

JTable not appearing though populated from database

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);

How to update data to JTable from vector after button click

How to update data to JTable from a vector after a button click? I have the code to add data to a JTable but it displays the same data for all the rows. Here's the following code:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import mygui.MainParent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Test {
Vector<String> row;
DefaultTableModel DFMO;
Vector<Vector> rowData;
JFrame frame;
private int count = 0;
public static void main(String arg[]){
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Test window = new Test();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Test() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton mybtn = new JButton("Click Me");
frame.getContentPane().add(mybtn, BorderLayout.SOUTH);
row = new Vector<String>();
rowData = new Vector<Vector>();
Vector<String> columnNames = new Vector<String>();
columnNames.addElement("Column One");
columnNames.addElement("Column Two");
columnNames.addElement("Column Three");
DFMO = new DefaultTableModel(rowData, columnNames);
JTable table = new JTable(DFMO);
JScrollPane scrollPane = new JScrollPane(table);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setSize(300, 150);
frame.setVisible(true);
mybtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
datachange();
}
});
datachange();
}
public void datachange(){
count++;
row.addElement("Row"+count+"-Column1");
row.addElement("Row"+count+"-Column2");
row.addElement("Row"+count+"-Column3");
rowData.addElement(row);
DFMO.fireTableDataChanged();
}
}
However, when I execute this code it doesn't show the updated row, even if the count value changes. The following image shows the output of the code.
Try this. You kept adding the same Vector
public void datachange(){
count++;
Vector<String> newRow = new Vector<>();
newRow.addElement("Row"+count+"-Column1");
newRow.addElement("Row"+count+"-Column2");
newRow.addElement("Row"+count+"-Column3");
DFMO.addRow(newRow);
//rowData.addElement(row);
DFMO.fireTableDataChanged();
}
You are adding the data to the Vector object (rowData).
What you should do is add the data directly to the DefaulTableModel object.
Replace
rowData.addElement(row);
with
DMFO.addRow(row);
in your datachange() method.

JScrollPane not displaying

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;
}
}
}

JTable autoscroll to the bottom in Java

I would like the JTable to autoscroll to the bottom whenever I add a new column and show the last 10 rows. However, I have the option of scrolling to anywhere I want (mouse listener?). Do you know how to do that? Here's the code I have so far. It builds a JTable and adds a new row for every mouse click on the JButton.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public class sampleGUI extends JFrame implements ActionListener {
private JButton incrementButton;
private JTable table;
private DefaultTableModel model;
private int count;
private JScrollPane scroll;
public sampleGUI() {
JFrame frame = new JFrame("sample frame");
frame.setLayout(new BorderLayout());
incrementButton = new JButton("Increase the count!");
model = new DefaultTableModel();
model.addColumn("column 1");
table = new JTable(model);
frame.add(incrementButton, BorderLayout.NORTH);
scroll = new JScrollPane(table)
frame.add(scroll, BorderLayout.CENTER);
count = 0;
incrementButton.addActionListener(this);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public synchronized void actionPerformed(ActionEvent e) {
if (e.getSource() == incrementButton) {
count++;
model.addRow(new Object[] { count });
}
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
sampleGUI gui = new sampleGUI();
}
});
}
}
Thanks!
Required to change selection in JTable, add code line
table.changeSelection(table.getRowCount() - 1, 0, false, false);
to
public (synchronized) void actionPerformed(ActionEvent e) {
I would like the JTable to autoscroll to the bottom whenever I add a new column
I assume you mean scroll to the bottom when you add a new row?
model.addRow(new Object[] { count });
table.scrollRectToVisible(...);
You forget add JScrollPane to the table :
//...
frame.add(new JScrollPane(table), BorderLayout.CENTER);
//...
and don't forget
import javax.swing.JScrollPane;

Categories

Resources