Does anyone have a good example of how to Add/Remove rows from a JTable using a custom table model? The issue I seem to be having is how to have the table keep updating when I add or remove items.
The real simple idea here is to have an add and remove button above my table which allows the user on the fly to change the table.
Here is example for adding row:
import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
public class RowAdder extends JFrame {
final SimpleModel tableData = new SimpleModel();
JTable table = new JTable(tableData);
public static void main(String[] args) {
RowAdder ra = new RowAdder();
ra.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ra.setSize(400, 300);
ra.setVisible(true);
}
public RowAdder() {
final JTextField textField = new JTextField();
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
tableData.addText(textField.getText());
textField.setText("");
}
});
add(textField, BorderLayout.SOUTH);
}
}
class SimpleModel extends AbstractTableModel {
Vector textData = new Vector();
public void addText(String text) {
textData.addElement(text);
fireTableDataChanged();
}
public int getRowCount() {
return textData.size();
}
public int getColumnCount() {
return 3;
}
public Object getValueAt(int row, int column) {
return textData.elementAt(row);
}
}
above ref from : http://www.java2s.com/Tutorial/Java/0240__Swing/AddrowstoaTable.htm
Checkout this tutorial about JTable:
http://download.oracle.com/javase/tutorial/uiswing/components/table.html
Specifically for table model check:
http://download.oracle.com/javase/tutorial/uiswing/components/table.html#data
I think this tutorial should answer all your question.
You have to notify the JTable object on changes of the underlying table model. The table is not observing the model but waiting for events.
After every change (or set of changes), create a TableModelEvent and call the tables tableChanged method.
Related
I am trying to write a TableCellEditor that verifies the input for a JTable cell. I have it working except that the error message is being displayed twice. Here is my tester class:
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
public class Tester {
public static void main(String[] args) {
JFrame frame=new JFrame();
frame.setPreferredSize(new Dimension(500,100));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultTableModel model=new DefaultTableModel(null,new String[] {"Col 1","Col 2"});
JTable table=new JTable(model);
table.getColumnModel().getColumn(0).setCellEditor(new decimalCellEditor());
model.insertRow(0,new Object[] {null,null});
JScrollPane scroller=new JScrollPane(table);
frame.add(scroller);
frame.setVisible(true);
frame.pack();
}
}
This is the editor:
import java.awt.Component;
import javax.swing.AbstractCellEditor;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.TableCellEditor;
public class DecimalCellEditor extends AbstractCellEditor implements TableCellEditor {
/**
*
*/
private static final long serialVersionUID = 1L;
private JTextField number=null;
public DecimalCellEditor() {
number=new JTextField();
}
#Override
public Object getCellEditorValue() {
String s=number.getText();
if (s.equals("")) {
return(s);
}
double x=0.;
try {
x=Double.parseDouble(s);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null,"Value must be numeric",null, JOptionPane.ERROR_MESSAGE, null);
return("");
}
return(Double.toString(x));
}
#Override
public Component getTableCellEditorComponent(JTable table_, Object value_, boolean isSelected_, int row_, int column_) {
number.setText(String.valueOf(value_));
return(number);
}
#Override
public boolean stopCellEditing() {
String s=(String) getCellEditorValue();
if (s.equals("")) {
return(super.stopCellEditing());
}
try {
Double.parseDouble(s);
} catch (NumberFormatException e) {
fireEditingCanceled();
return(false);
}
return(super.stopCellEditing());
}
}
The objective is to assure the user enters a numeric value or no value at all (""). What is causing the error to be displayed and dismissed twice when it is non-numeric and how can I stop it? TIA.
Implementing camickr's suggestion
Assuming I understood the suggestion, I don't need the editor?
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class Tester {
public static void main(String[] args) {
JFrame frame=new JFrame();
frame.setPreferredSize(new Dimension(500,100));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyTableModel model=new MyTableModel(null,new String[] {"Col 1","Col 2"});
JTable table=new JTable(model);
model.insertRow(0,new Object[] {"",""});
JScrollPane scroller=new JScrollPane(table);
frame.add(scroller);
frame.setVisible(true);
frame.pack();
}
}
Overriding getColumnClass:
import javax.swing.table.DefaultTableModel;
public class MyTableModel extends DefaultTableModel {
/**
*
*/
private static final long serialVersionUID = 1L;
public MyTableModel(Object[][] data_,String[] columnNames_) {
super(data_,columnNames_);
}
#Override
public Class<?> getColumnClass(int column_) {
if (column_==0) {
return(Double.class);
}
return(getValueAt(0,column_).getClass());
}
}
I obviously didn't do this right as I get exceptions from an unknown source saying:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Cannot format given Object as a Number
I'm guessing there is a problem with my constructor.
First of all class names should start with an upper case character. You have been given links to the Swing tutorials that provide demo code. I'm sure you have access to the Java API. The API and examples all follow the same convention. Learn by example and follow Java conventions!
The objective is to assure the user enters a numeric value or no value at all ("").
Just override the getColumnClass(...) method of the TableModel to return Double.class for the column and the JTable will use an appropriate editor and renderer.
A red border will be placed around the cell and you won't be able to save the data until you fix the problem.
Cannot format given Object as a Number
Edit:
Take the time to think about the change you just made. Take the time to read the error message. Your change just stated the column should contain Double data. So why are you adding an "empty" String in the first column. How can the renderer convert a String to a Double?
Again, if you read the code in the Java tutorials you will see how numeric data is add to the TableModel. I gave you a link to that tutorial long ago because it contains many basics.
I have tried this part of code to get values from a JComboBox that is inside of a JTable, but it doesn't work!
I want to get the value of selected cell in order to insert into DB.
package fx;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
public class ComboInTable extends JFrame {
private static JFrame jFrame;
public ComboInTable() throws HeadlessException {
jFrame=this;
JTable table=new JTable();
DefaultTableModel model= (DefaultTableModel) table.getModel();
model.addColumn("A",new Object[]{"item1"});
model.addColumn("B",new Object[]{"item2"});
JScrollPane scrollPane=new JScrollPane(table);
String[] value1=new String[]{"1","2","3"};
String[] value2=new String[]{"a","b","c"};
TableColumn col0=table.getColumnModel().getColumn(0);
TableColumn col1=table.getColumnModel().getColumn(1);
col0.setCellEditor(new MyComboBoxEditor(value1));
col0.setCellRenderer(new MyComboBoxRenderer(value1));
col1.setCellEditor(new MyComboBoxEditor(value2));
col1.setCellRenderer(new MyComboBoxRenderer(value2));
JComboBox comboBox=new JComboBox(value1);
comboBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if(e.getStateChange() == ItemEvent.SELECTED)
{
System.out.println(e.getItem());
}
}
});
jFrame.setLayout(new FlowLayout());
jFrame.add(scrollPane);
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jFrame.setSize(400, 400);
jFrame.setVisible(true);
}
public static void main(String[] args) {
ComboInTable comboInTable=new ComboInTable();
}
}
I have MyComboBoxEditor and MyComboBoxRenderer classes.
package fx;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
public class MyComboBoxRenderer extends JComboBox implements TableCellRenderer {
public MyComboBoxRenderer(String[] items) {
super( items);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if(isSelected){
setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
}
else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setSelectedItem(value);
return this;
}
}
package fx;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
public class MyComboBoxEditor extends DefaultCellEditor {
public MyComboBoxEditor(String[] items) {
super(new JComboBox(items));
}
}
I have tried this part of code to get values from a JComboBox that is inside of a JTable,
You don't get the value from the combo box.
You get the value from the JTable using the getValueAt(...) method.
I also have no idea why you are creating a custom renderer and editor. Just use the default renderer/editor provided by the table.
Start by reading the section from the Swing tutorial on How to Use Tables. You will find an example that shows how to use a combo box as an editor.
In my application everything is distributed.
On a action, application retrieves data from DB and saves in ArrayList<T>.
I create an object of RelativeTableModel where I pass the ArrayList<T>.
public void RelationsClicked() {
ArrayList<Relation> data = myParent.dbOperation.getRelations();
RelativeTableModel tModel = new RelativeTableModel(data); // subclass of AbstractTableModel
myParent.SetBrowsePanelData(tModel);
myParent.SetMainPanel(CashAccountingView.BROWSEPANEL);
}
I have a BrowseListPanel class that has a JTable in JScrollPane. Its instance is already created in the main application.
I pass the model to BrowseListPanel and finally show the panel.
Code:
public void SetBrowsePanelData(AbstractTableModel tModel) {
browsePanel.setTModel(tModel);
}
// BrowseListPanel's Code
public void setTModel(AbstractTableModel tModel) {
this.tModel = tModel; // tModel = AbstractTableModel
}
// Show the Panel
public void SetMainPanel(String panel) {
activePanel = panel;
SetFontSize();
cards.show(mainPanel, panel);
mainPanel.revalidate();
mainPanel.repaint();
}
But I don't see the Table. I believe as the object of BrowseListPanel (containing the JTable) is already created & later the TableModel is added. So some sort of event should be fired in setTModel().
Am I right? If so, what event should be thrown and what should be its implementation.
Invoking setModel() on the table should be sufficient, but you might call fireTableStructureChanged() on the model explicitly as a way to help sort things out.
Also, verify that you are working on the event dispatch thread.
Addendum: Here's an sscce that shows the basic approach.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
/** #see http://stackoverflow.com/questions/8257148 */
public class SwapTableModel extends JPanel {
public SwapTableModel() {
final JTable table = new JTable(Model.Alpha.model);
table.setPreferredScrollableViewportSize(new Dimension(128, 32));
this.add(new JScrollPane(table));
final JComboBox combo = new JComboBox();
for (Model model : Model.values()) {
combo.addItem(model);
}
this.add(combo);
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Model model = (Model) combo.getSelectedItem();
table.setModel(model.model);
}
});
}
private enum Model {
Alpha(), Beta();
private DefaultTableModel model;
private Model() {
Object[] data = {this.toString()};
this.model = new DefaultTableModel(data, 1);
model.addRow(data);
}
}
private void display() {
JFrame f = new JFrame("SwapTableModel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new SwapTableModel().display();
}
});
}
}
does anyone know why
System.out.println(e.getFirstIndex());
System.out.println(e.getLastIndex());
both does nothing? is my Listener not registered properly? i am trying to know when a certain cell is selected and do something to it. Like setting a default text for that cell when it is selected either by mouse or key.
package VLGui;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.util.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.Timer;
import javax.swing.table.*;
import VLCore.cellSelectedListener;
public class mainFrame extends JFrame{
private JLabel lblTime;
private Vector columnName = new Vector();
private Vector tblData = new Vector();
private JTable JTbl;
private Timer timer = new Timer(1000,new MyListener());
private JPanel topPnl,cenPnl,btmPnl;
private Calendar time;
private Object[] columnNames = {"Veh No.","Description","Time In","Time Out"};
public mainFrame()
{
timer.start();
//jtable settings
JTbl = new JTable(new DefaultTableModel(columnNames,1));
JTbl.setPreferredScrollableViewportSize(JTbl.getPreferredSize());
JTbl.setFillsViewportHeight(true);
JTbl.setCellSelectionEnabled(false);
JTbl.setColumnSelectionInterval(0,0);
JTbl.setRowSelectionInterval(0,0);
JTbl.getSelectionModel().addListSelectionListener(new cellSelectedListener(JTbl));
//Settings
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("Vehicle Log");
setSize(500,1000);
setVisible(true);
//Dec
JScrollPane tableContainer = new JScrollPane(JTbl);
topPnl = new JPanel();
cenPnl = new JPanel();
btmPnl = new JPanel();
lblTime = new JLabel();
//Adding Components
topPnl.add(lblTime,BorderLayout.CENTER);
cenPnl.add(tableContainer);
getContentPane().add(topPnl,BorderLayout.NORTH);
getContentPane().add(cenPnl,BorderLayout.CENTER);
//add(btmPnl);
}
public class MyListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
time = Calendar.getInstance();
lblTime.setText(time.getTime().toString());
lblTime.repaint();
}
}
}
package VLCore;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class cellSelectedListener implements ListSelectionListener {
private JTable jTbl;
public cellSelectedListener()
{
}
public cellSelectedListener(JTable tbl)
{
jTbl = tbl;
}
#Override
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel lsm = (ListSelectionModel)e.getSource();
System.out.println(e.getFirstIndex());
System.out.println(e.getLastIndex());
}
}
The problem is, the row is already selected.
The tables selection model relates to the selection changes of the rows.
If you change the order in which you register the listener as follows...
JTbl.getSelectionModel().addListSelectionListener(new cellSelectedListener(JTbl));
JTbl.setColumnSelectionInterval(0, 0);
JTbl.setRowSelectionInterval(0, 0);
You will see the row selection change.
Update code review...
Generally, this JTbl.setPreferredScrollableViewportSize(JTbl.getPreferredSize()); is not a good idea. You really want to leave it up to the scroll pane to make these kind of decisions. You can alter the column sizes if you really want to effect the width of the table.
Java naming conventions suggest that all instance variables start with a lower case character, soJTbl would become jTbl and all classes start with an upper case, so mainFrame would become MainFrame...small thing, but it's what people are really use to.
I am using a DAO Factory to get my Data from the database. When i am running my program the data is showing in the printline so he is getting it out of the database. But i want it to show in my JTable but this one is empty and i dont know how to fill it.
Code JFrame:
package View;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.WindowConstants;
import javax.swing.table.TableModel;
import Controller.VerwijderController;
import Model.OefeningenListModel;
import Model.OefeningenTableModel;
public class VerwijderenHome extends JFrame {
private JList LijstOefening;
private JScrollPane jScrollPane1;
private Container window = getContentPane();
private JButton delete;
private VerwijderController Controller;
private JTable tabel;
public VerwijderenHome()
{
initGUI();
}
public void addDeleteListener(ActionListener a){
delete.addActionListener(a);
}
private void initGUI() {
setPreferredSize(new Dimension(800, 600));
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLayout(null);
setVisible(true);
JTable table = new JTable(new OefeningenTableModel());
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setBounds(50, 50, 300, 60);
window.add(scrollPane);
delete = new JButton("Delete");
delete.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
delete.setBounds(50, 265, 100, 30);
window.add(delete);
pack();
Controller = new VerwijderController();
addDeleteListener(Controller);
}
public JButton getDelete(){
return delete;
}
public JList getLijst()
{
return LijstOefening;
}
}
Code DefaultTableModel?? (Dont know if i must use this one)
package Model;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import datapackage.DAOFactory;
public class OefeningenTableModel extends DefaultTableModel {
ArrayList<Oefening> oefeningen;
public OefeningenTableModel(){
oefeningen = DAOFactory.getFactory(0).getIDAOOefening().load();
}
}
The DefaultTableModel is backed by a Vector representing the columns and rows of the table model.
You've provided your own ArrayList of objects, but you've not overridden the methods you will require to supply that data back to the table. The DefaultTableModel has no idea of your ArrayList
Try overridding some of the following;
public class OefeningenTableModel extends AbstractTableModel {
ArrayList<Oefening> oefeningen;
public OefeningenTableModel(){
oefeningen = DAOFactory.getFactory(0).getIDAOOefening().load();
}
#Override
public int getRowCount() {
return oefeningen.getSize();
}
#Override
public int getColumnCount() {
// You'll need to fill this out to meet your requirements
}
#Override
public String getColumnName(ing column) {
// You'll need to fill this out to meet your requirements
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
// You'll need to fill this out to meet your requirements
}
}
Take the time to have read through How to use Tables.