I keep getting nullpointer exception for jtable getrowcount() method - java

I am trying to create a table that can be filtered but I keep getting a null pointer exception for the getRowCount() method in my table model class.
HomePagePanel(where my table is)
public class homepagePanel extends JPanel implements ActionListener {
private JButton uploadEmail, viewEmail, logout, delete;
private JLabel userLog;
private JLabel tableLabel;
private JScrollPane scrollPane;
private EmailTableListener emailTableListener;
//private EmailTablePanel EmailPanel;
private HomePagePanelListener homepagePanelListener;
private List<Item> dc;
private Controller controller;
private JTable table;
private EmailTableModel emailModel;
private JPopupMenu popup;
private JTextField filterText;
private JLabel filterLabel;
private TableRowSorter<EmailTableModel> sorter;
public homepagePanel() {
controller = new Controller();
userLog = new JLabel("Logged in:");
uploadEmail = new JButton("Upload");
viewEmail = new JButton("View");
delete = new JButton("Delete");
logout = new JButton("Log Out");
tableLabel = new JLabel("Emails stored");
//Email stuff
emailModel = new EmailTableModel();
sorter = new TableRowSorter<EmailTableModel>(emailModel);
table = new JTable(emailModel);
table.setRowSorter(sorter);
//
filterLabel = new JLabel("Filter Text: ", SwingConstants.TRAILING);
filterText = new JTextField(10);
filterLabel.setLabelFor(filterText);
//documenet listener
filterText.getDocument().addDocumentListener(new DocumentListener(){
#Override
public void changedUpdate(DocumentEvent e) {
// TODO Auto-generated method stub
newFilter();
}
#Override
public void insertUpdate(DocumentEvent e) {
// TODO Auto-generated method stub
newFilter();
}
#Override
public void removeUpdate(DocumentEvent e) {
// TODO Auto-generated method stub
newFilter();
}
});
// Adds the table to a scrollpane
scrollPane = new JScrollPane(table);
scrollPane
.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollPane
.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
popup = new JPopupMenu();
JMenuItem removeItem = new JMenuItem("Delete row");
popup.add(removeItem);
//adds mouse listener to show
table.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e) {
int row = table.rowAtPoint(e.getPoint());
table.getSelectionModel().setSelectionInterval(row, row);
if(e.getButton() == MouseEvent.BUTTON3){
popup.show(table, e.getX(), e.getY());//shows popup
}
}
});
//removeitem actionlistener
removeItem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
int row = table.getSelectedRow();
if(emailTableListener != null){
emailTableListener.rowDeleted(row);
emailModel.fireTableRowsDeleted(row, row);
}
}
});
// EmailPanel = new EmailTablePanel();
layoutComponents();
viewEmail.addActionListener(this);
uploadEmail.addActionListener(this);
logout.addActionListener(this);
private void newFilter(){
RowFilter<EmailTableModel, Object> rf = null;
try{
rf = RowFilter.regexFilter(filterText.getText());
}catch(java.util.regex.PatternSyntaxException e){
return;
}
sorter.setRowFilter(rf);
}
TableModel
package view;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import model.Item;
public class EmailTableModel extends AbstractTableModel {
private List<Item> dc;
private String[] colNames = {"ID", "To", "From", "Subject", "Topic", "Message Content", "Comments", "Attachments"};
public EmailTableModel(){
//System.out.println(dc.size());
}
public String getColumnName(int column) {
// TODO Auto-generated method stub
return colNames[column];
}
public void setData(List<Item> dc){
this.dc = dc;
}
#Override
public int getColumnCount() {
// TODO Auto-generated method stub
return 8;
}
#Override
public int getRowCount() {
// TODO Auto-generated method stub
return dc.size();
}
#Override
public Object getValueAt(int row, int column) {
Item item = dc.get(row);
switch(column){
case 0:
return item.getId();
case 1:
return item.getTo();
case 2:
return item.getFrom();
case 3:
return item.getSubject();
case 4:
return item.getTopic();
case 5:
return item.getMessageContent();
case 6:
return item.getComments();
case 7:
return item.getAttachments();
}
return null;
}
public Class getColumnClass(int column) {
Class returnValue;
// Verifying that the column exists(index > 0 && index < number of
// columns
if ((column >= 0) && (column < getColumnCount())) {
returnValue = getValueAt(0, column).getClass();
} else {
// Returns the class for the item in the column
returnValue = Object.class;
}
return returnValue;
};
}
database class(retriving data for jtable)
public void loadItems() throws SQLException {
//connects to the database
getConnected();
Items.clear();//clears the linked list
String sql = "Select Id, Reciever, Sender, Subject, topic, Email_Content, Comments, Attachments from item order by Id";//querly for select statement
Statement selectStatement = con.createStatement();
ResultSet results = selectStatement.executeQuery(sql);
while (results.next()) {
int id = results.getInt("Id");
String To = results.getString("Reciever");
String From = results.getString("Sender");
String Subject = results.getString("Subject");
String topic = results.getString("topic");
String Email_Content = results.getString("Email_Content");
String Comments = results.getString("Comments");
String Attachments = results.getString("Attachments");
Item item = new Item(id, To, From, Subject, topic, Email_Content,
Comments, Attachments);
Items.add(item);//add item to linked list
}
}
mainframe(where I set the data
loadItems(); //method used to load the data from the database
HomepagePanel.setData(controller.getItems());//sets data

Here:
public class HomePagePanel { // note code conventios!
...
public HomePagePanel() {
...
emailModel = new EmailTableModel();
sorter = new TableRowSorter<EmailTableModel>(emailModel);
table = new JTable(emailModel);
...
}
}
You don't call emailModel.setData() right before creating the table. It means your table model's data never is initialized and dc still being null at this point. Consequently when getRowCount() method is called during JTable creation it throws the NPE you're facing.
IMHO you should consider remove setData() method and add the items list to the EmailTableModel constructor instead, and better organize your code to avoid this kind of situation:
Do database call and get items list
Create a new table model
Create new JTable
Edit
"Should i just call fireTableDataChanged when I insert or delete an
item?"
No, you just need to provide methods to add/delete items to your table model and then notify TableModelListeners about such events. For instance:
public class EmailTableModel extends AbstractTableModel {
...
public void addRow(Item item) {
int rowIndex = dc.size();
dc.add(item);
fireTableRowsInserted(rowIndex, rowIndex);
}
...
public void deleteRow(Item item) {
int rowIndex = dc.indexOf(item);
if(rowIndex > -1) {
dc.remove(item);
fireTableRowsDeleted(rowIndex, rowIndex);
}
}
...
}
See AbstractTableModel API:
fireTableRowsInserted(int firstRow,int
lastRow)
fireTableRowsDeleted(int firstRow, int
lastRow)

Related

JTable click and show new window

I have JTable which shows data from arraylist through AbstractTableModel.
What I want to do is when I click (left-click) on row in JTable, I want to show new window where can I see and edit data from row stored in arraylist.
I have MouseListener already written, but it does nothing.
There are main,table and tablemodel classes.
public class MainWindow extends JFrame {
private Controller controller;
private Prihlasovanie prihlasovanie;
private TabulkaSkladnik tabulkaskladnik;
private Okno okno;
public MainWindow() {
super("PROJEKT OOP");
setVisible(true);
setSize(750, 508);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new BorderLayout());
setMinimumSize(new Dimension(800,500));
controller = new Controller();
tabulkaskladnik = new TabulkaSkladnik();
prihlasovanie = new Prihlasovanie();
tabulkaskladnik.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
Okno okno = new Okno();
okno.setVisible(true);
}
});
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
getContentPane().add(tabbedPane, BorderLayout.NORTH);
tabbedPane.addTab("Prihlasovanie", null , prihlasovanie , null);
tabbedPane.addTab("Skladnik", null , tabulkaskladnik , null);
tabulkaskladnik.setData(controller.getObjednavky());
}
}
public class TabulkaSkladnik extends JTable {
private JTable tabulka;
private SkladnikTableModel tabulkaModel;
public TabulkaSkladnik() {
tabulkaModel = new SkladnikTableModel();
tabulka = new JTable(tabulkaModel);
setLayout(new BorderLayout());
add(new JScrollPane(tabulka),BorderLayout.CENTER);
}
public void setData(List<Objednavka> databaza) {
tabulkaModel.setData(databaza);
}
public void refresh() {
tabulkaModel.fireTableDataChanged();
}
}
public class SkladnikTableModel extends AbstractTableModel {
private List<Objednavka> databaza;
private String[] colNames = {"ID", "Nazov", "Popis", "Meno", "Priezvisko"};
public SkladnikTableModel() {
}
public void setData(List<Objednavka> databaza) {
this.databaza = databaza;
}
public String getColumnName(int column) {
// TODO Auto-generated method stub
return colNames[column];
}
public Class getColumnClass(int col) {
return getValueAt(0,col).getClass();
}
#Override
public int getColumnCount() {
// TODO Auto-generated method stub
return 5;
}
#Override
public int getRowCount() {
return databaza.size();
}
#Override
public Object getValueAt(int riadok, int stlpec) {
Objednavka objednavka = databaza.get(riadok);
switch(stlpec) {
case 0: return objednavka.getId();
case 1: return objednavka.getNazov();
case 2: return objednavka.getOpis();
case 3: return objednavka.getMeno();
case 4: return objednavka.getPriezvisko();
}
return null;
}
}
Thank you for your help! :)

populate multiple combobox with same model but select diff

Having problems with the ComboBox, I have populated multiple ComboBoxes with the same model, but when I run my program and select a value from one ComboBox it selects the same value for the rest.
ComboHBoy.setModel(defaultComboBoxModel);
ComboHGirl.setModel(defaultComboBoxModel);
ComboDHBoy.setModel(defaultComboBoxModel);
ComboDHGirl.setModel(defaultComboBoxModel);
That's because they all are referenced to the same model, any change of the model will affect the all the other combos.
There is no way to solve this except that every combobox have it's own DefaultComboBoxModel.
private DefaultComboBoxModel hBoyModel= new DefaultComboBoxModel();
private DefaultComboBoxModel hGirlModel= new DefaultComboBoxModel();
//....
ComboHBoy.setModel(hBoyModel);
ComboHGirl.setModel(hGrilModel);
//....
Use just a ListModel to manage your data and create a ComboboxModel adapter that is based on the ListModel. This ComboboxModel will only add the selection capability. Remember that a ComboboxModel extends ListModel. So it is easy to adapt the interfaces.
The only tricky part is to handle the update events.
For example:
public class ListAdapterComboboxModel implements ComboBoxModel {
private ListModel dataModel;
private Object selectedObject;
private DataModelListDataListenerAdapter listDataListenerAdapter;
public ListAdapterComboboxModel(ListModel ListModel) {
dataModel = ListModel;
this.listDataListenerAdapter = new DataModelListDataListenerAdapter();
dataModel.addListDataListener(listDataListenerAdapter);
}
public int getSize() {
return dataModel.getSize();
}
public Object getElementAt(int index) {
return dataModel.getElementAt(index);
}
public void addListDataListener(ListDataListener l) {
listDataListenerAdapter.addListDataListener(l);
}
public void removeListDataListener(ListDataListener l) {
listDataListenerAdapter.removeListDataListener(l);
}
public void setSelectedItem(Object anObject) {
if ((selectedObject != null && !selectedObject.equals(anObject))
|| selectedObject == null && anObject != null) {
selectedObject = anObject;
ListDataEvent e = new ListDataEvent(this,
ListDataEvent.CONTENTS_CHANGED, -1, -1);
listDataListenerAdapter.delegateListDataEvent(e);
}
}
public Object getSelectedItem() {
return selectedObject;
}
private class DataModelListDataListenerAdapter implements ListDataListener {
protected EventListenerList listenerList = new EventListenerList();
public void removeListDataListener(ListDataListener l) {
listenerList.remove(ListDataListener.class, l);
}
public void addListDataListener(ListDataListener l) {
listenerList.add(ListDataListener.class, l);
}
public void intervalAdded(ListDataEvent e) {
delegateListDataEvent(e);
}
public void intervalRemoved(ListDataEvent e) {
checkSelection(e);
delegateListDataEvent(e);
}
public void contentsChanged(ListDataEvent e) {
checkSelection(e);
delegateListDataEvent(e);
}
private void checkSelection(ListDataEvent e) {
Object selectedItem = getSelectedItem();
ListModel listModel = (ListModel) e.getSource();
int size = listModel.getSize();
boolean selectedItemNoLongerExists = true;
for (int i = 0; i < size; i++) {
Object elementAt = listModel.getElementAt(i);
if (elementAt != null && elementAt.equals(selectedItem)) {
selectedItemNoLongerExists = false;
break;
}
}
if (selectedItemNoLongerExists) {
ListAdapterComboboxModel.this.selectedObject = null;
}
}
protected void delegateListDataEvent(ListDataEvent lde) {
ListDataListener[] listeners = listenerList
.getListeners(ListDataListener.class);
for (ListDataListener listDataListener : listeners) {
listDataListener.contentsChanged(lde);
}
}
}
}
And then just use it like this
public class ComboboxModelTest extends JFrame{
public static void main(String[] args) {
ComboboxModelTest comboboxModelTest = new ComboboxModelTest();
comboboxModelTest.pack();
comboboxModelTest.setVisible(true);
}
public ComboboxModelTest() {
Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
DefaultListModel defaultListModel = new DefaultListModel();
defaultListModel.addElement("Element 1");
defaultListModel.addElement("Element 2");
ComboBoxModel firstComboboxModel = new ListAdapterComboboxModel(defaultListModel);
ComboBoxModel secondComboboxModel = new ListAdapterComboboxModel(defaultListModel);
JComboBox jComboBox1 = new JComboBox(firstComboboxModel);
JComboBox jComboBox2 = new JComboBox(secondComboboxModel);
contentPane.add(jComboBox1);
contentPane.add(jComboBox2);
}
}
Then you only have to manage the data in one ListModel and you have distinct selection models.
Also take a look at The MVC pattern and SWING.

How to refresh data in JTable I am using TableModel

Hi,
I have created my TableModel and want to refresh JTable once I added a new row. What should be added to the listener to "refresh" JTable?
public class MyTableModel implements TableModel {
private Set<TableModelListener> listeners = new HashSet<TableModelListener>();
//List<Staff> staffs = Factory.getInstance().getStaffDAO().getAllStaff();
private List<Staff> staffs;
public MyTableModel(List<Staff> staffs){
this.staffs = staffs;
}
#Override
public int getRowCount() {
return staffs.size();
}
#Override
public int getColumnCount() {
return 5;
}
#Override
public String getColumnName(int columnIndex) {
switch (columnIndex){
case 0:
return "First Name";
case 1:
return "Second Name";
case 2:
return "Date";
case 3:
return "Position";
case 4:
return "Salary";
}
return "";
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return Object.class;
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Staff staff = staffs.get(rowIndex);
switch (columnIndex){
case 0:
return staff.getName();
case 1:
return staff.getSurname();
case 2:
return staff.getDate();
case 3:
return staff.getPosition();
case 4:
return staff.getSalary();
}
return "";
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
}
#Override
public void addTableModelListener(TableModelListener l) {
}
#Override
public void removeTableModelListener(TableModelListener l) {
}
}
Here is my listener of my Add row Button:
#Override
public void actionPerformed(ActionEvent e) {
Staff staff = new Staff();
staff.setName(JOptionPane.showInputDialog("Enter First Name"));
staff.setSurname(JOptionPane.showInputDialog("Enter Second Name"));
staff.setDate(JOptionPane.showInputDialog("Enter Date"));
staff.setPosition(JOptionPane.showInputDialog("Enter Position"));
staff.setSalary(JOptionPane.showInputDialog("Enter Salary"));
try {
Factory.getInstance().getStaffDAO().addStaff(staff);
} catch (SQLException e1) {
e1.printStackTrace();
}
!!!Here should be some code that will be firing my table after adding new row!!!
}
I've tried to use method firetabledatachanged() of AbstractTableModel in my actionPerformed() but with unluck, it is appeared ClassCastException.
UPDATE 1
WorkPlaceGui.java
public class WorkPlaceGui extends JFrame implements ActionListener {
AbstractTableModel model;
JTable jTable;
JScrollPane jScrollPane;
public WorkPlaceGui()throws SQLException{
List<Staff> staffs = Factory.getInstance().getStaffDAO().getAllStaff();
for(int i = 0; i < 0; i++) {
staffs.add(new Staff("First Name " + staffs.get(i).getName(), "Second Name " + staffs.get(i).getSurname(), "Date " + staffs.get(i).getDate(), "Position " + staffs.get(i).getPosition(), "Salary " + staffs.get(i).getSalary()));
}
model = new MyTableModel(staffs);
jTable = new JTable(model);
JButton jBtnAdd = new JButton("Добавить");
JButton jBtnDel = new JButton("Удалить");
JButton jBtnUpd = new JButton("Обновить");
JButton jBtnAdmin = new JButton("Админка");
JPanel panelNorth = new JPanel();
JPanel panelCenter = new JPanel();
JPanel panelSouth = new JPanel();
jTable.setPreferredScrollableViewportSize(new Dimension(350, 150));
jScrollPane = new JScrollPane(jTable);
panelNorth.setLayout(new FlowLayout());
panelNorth.add(jBtnAdd);
panelNorth.add(jBtnDel);
panelNorth.add(jBtnUpd);
panelNorth.add(jBtnAdmin);
panelCenter.add(jScrollPane);
setLayout(new BorderLayout());
add(panelNorth, BorderLayout.NORTH);
add(panelCenter, BorderLayout.CENTER);
jBtnAdd.addActionListener(this);
setPreferredSize(new Dimension(550, 300));
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setTitle("Staff data base");
pack();
setVisible(true);
setLocationRelativeTo(null);
}
#Override
public void actionPerformed(ActionEvent e) {
Staff staff = new Staff();
staff.setName(JOptionPane.showInputDialog("Enter First Name"));
staff.setSurname(JOptionPane.showInputDialog("Enter Second Name"));
staff.setDate(JOptionPane.showInputDialog("Enter Date"));
staff.setPosition(JOptionPane.showInputDialog("Enter Position"));
staff.setSalary(JOptionPane.showInputDialog("Enter Salary"));
try {
Factory.getInstance().getStaffDAO().addStaff(staff);
} catch (SQLException e1) {
e1.printStackTrace();
}
model.fireTableDataChanged();
}
}
MyTableModel.java
public class MyTableModel extends AbstractTableModel {
private List<Staff> staffs;
public MyTableModel(List<Staff> staffs){
this.staffs = staffs;
}
#Override
public int getRowCount() {
return staffs.size();
}
#Override
public int getColumnCount() {
return 5;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Staff staff = staffs.get(rowIndex);
switch (columnIndex){
case 0:
return staff.getName();
case 1:
return staff.getSurname();
case 2:
return staff.getDate();
case 3:
return staff.getPosition();
case 4:
return staff.getSalary();
}
return "";
}
}
You've done it the hard way.
First of all, you've implemented directly from TableModel and secondly you've failed to implement the listener requirements...
Instead, try extending from the AbstractTableModel instead, which already includes the implementations of the listener registration and notification.
You will need to provide a method that will allow you to add a row to the table model. In this method you need to use the fireTableRowsInserted method which will notify any tables using the model, that a new row has been added...
Update with example
This is VERY, VERY basic example. It's only intention is to demonstrate the use of fireTableRowsInserted. It uses a Swing Timer to add a new row every 125 milliseconds until you kill it ;)
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
public class DynamicTable {
public static void main(String[] args) {
new DynamicTable();
}
public DynamicTable() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final MyTableModel model = new MyTableModel();
JTable table = new JTable(model);
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);
Timer timer = new Timer(125, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
model.addRow();
}
});
timer.start();
}
});
}
public class MyTableModel extends AbstractTableModel {
private List<String[]> rows;
public MyTableModel() {
rows = new ArrayList<>(25);
}
#Override
public int getRowCount() {
return rows.size();
}
#Override
public int getColumnCount() {
return 4;
}
#Override
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
String[] row = rows.get(rowIndex);
return row[columnIndex];
}
public void addRow() {
int rowCount = getRowCount();
String[] row = new String[getColumnCount()];
for (int index = 0; index < getColumnCount(); index++) {
row[index] = rowCount + "x" + index;
}
rows.add(row);
fireTableRowsInserted(rowCount, rowCount);
}
}
}
Updated with another example
Because your table model is backed by its own List, it has no connection to your factory. It doesn't know when you add or remove objects from it. This means you become responsible for updating the model:
public class MyTableModel extends AbstractTableModel {
private List<Staff> staffs;
public MyTableModel(List<Staff> staffs){
this.staffs = staffs;
}
#Override
public int getRowCount() {
return staffs.size();
}
#Override
public int getColumnCount() {
return 5;
}
public void add(Staff staff) {
int size = getSize();
staffs.add(staff);
fireTableRowsInserted(size, size);
}
public void remove(Staff staff) {
if (staffs.contains(staff) {
int index = stafff.indexOf(staff);
staffs.remove(staff);
fireTableRowsDeleted(index, index);
}
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
Staff staff = staffs.get(rowIndex);
switch (columnIndex){
case 0:
return staff.getName();
case 1:
return staff.getSurname();
case 2:
return staff.getDate();
case 3:
return staff.getPosition();
case 4:
return staff.getSalary();
}
return "";
}
}
And your actionPerformed:
#Override
public void actionPerformed(ActionEvent e) {
Staff staff = new Staff();
staff.setName(JOptionPane.showInputDialog("Enter First Name"));
staff.setSurname(JOptionPane.showInputDialog("Enter Second Name"));
staff.setDate(JOptionPane.showInputDialog("Enter Date"));
staff.setPosition(JOptionPane.showInputDialog("Enter Position"));
staff.setSalary(JOptionPane.showInputDialog("Enter Salary"));
try {
Factory.getInstance().getStaffDAO().addStaff(staff);
((MyTableModel)model).add(staff);
} catch (SQLException e1) {
e1.printStackTrace();
}
}
Your class MyTableModel implements TableModel, but it has no event handling mechanism to connect the model to the view. Instead extend AbstractTableModel, as shown here and here. AbstractTableModel provides the fireTable* methods needed for this.
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
Well, first of all, find more about Observer pattern (http://en.wikipedia.org/wiki/Observer_pattern).
I suggest that you create a ObservableModel class that will have a list of PropertyChangeListeners. Your StaffDAO should extend this ObservableModel. When the new staff is added (i.e. addStaff is called) you should call ObservableModel's firePorpertyChange or something like that. firePropertyChange notifyies all propertyChangeListeners. One of those listeners should be registered in your Table, and its propertyChanged method should be implemented with refreshing of the table (hd1) had a good answer.
myTableModel.fireTableDataChanged(); should be just enough to force a refresh of your table. As usual, if you have further problems, do feel free to leave a comment.
For a more general solution you can use the Row Table Model and just implement the getValueAt() and setValueAt() methods.
Here should be some code that will be firing my table after adding new row!
The model is responsible for invoking the proper fireXXX method.
Use this type of casting.
((AbstractTableModel)student.getModel()).fireTableCellUpdated();

java: Get row data from popupmenu actionListener event

I'm having a little scenario here that maybe a duplicate. I have JTable where i show some data, i have a mouselistener that listens for right clicks on the table and displays a popup menu with one menuitem. My goal is that when the user clicks the menuitem, i get the values from the table and feed them into a custom dialog which has some fill in fields, so that the user doesn't have to feed the whole dialog by hand since i will feed the dialog with the values selected on the table. but my problem is that the menuitem actionevent doesn't have a way of getting the point so that i can use table.getRowAt(). i have read another comment (check here https://stackoverflow.com/a/4122082/1788917) where i have been told that i can save the row number in a variable that can then be accessed by the actionlistener for the menuitem.
i want it to look like this
theScrollPane.getViewport().add(myJTable, null);
JMenuItem menuItem = new JMenuItem(clickMe);
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
menuItemActionPerformed(e);
}
});
MouseListener popupListener = new PopupListener();
popupMenu.add(menuItem);
myJTable.addMouseListener(popupListener);
protected void menuItemActionPerformed (ActionEvent e) {
// what to do here to get the table row data
// and send it to my custom dialog via it's constructor ???
}
// a simple nested class for the popup
class PopupListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
int row = myJTable.rowAtPoint(e.getPoint());
int selectedRow = myJTable.getSelectedRow();
// just to make sure the popup appears only where the row is
// selected
if (row == selectedRow) {
showPopup(e);
}
}
public void mouseReleased(MouseEvent e) {
int row = myJTable.rowAtPoint(e.getPoint());
int selectedRow = myJTable.getSelectedRow();
if (row == selectedRow) {
showPopup(e);
}
}
private void showPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
}
so my question is, is saving the row number the only way that i can do this or is there a better way?
i have read another comment (check here https://stackoverflow.com/a/4122082/1788917) where i have been told that i can save the row number in a variable
You read the wrong comment.
If you read the answer above that link (ie. the one with 7 votes) you will see the solution is to select the row you clicked on BEFORE showing the popup menu. Then in your menu item Action you can reference
table.getSelectedRow();
I have tried your case referring to this case and I am able to get the row and show it in a JDialog. I just modified my old code to do this. I haven't thoroughly tested.
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class AllTableExample {
private JTabbedPane tabbedPane;
private JTable allTable;
private AllTableModel allTableModel;
public AllTableExample() {
List<TableData> data = new ArrayList<TableData>();
data.add(new TableData("John1", "A", "Maths", "Hellen1"));
data.add(new TableData("John2", "A", "Maths", "Hellen2"));
data.add(new TableData("John3", "A", "Maths", "Hellen3"));
data.add(new TableData("John4", "A", "Maths", "Hellen4"));
data.add(new TableData("John5", "A", "Maths", "Hellen5"));
allTableModel = new AllTableModel(data);
}
public void createUI() {
JFrame frame = new JFrame();
tabbedPane = new JTabbedPane();
tabbedPane.add("All", getAllTablePanel());
frame.add(tabbedPane);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Table Model Example.");
frame.pack();
frame.setVisible(true);
}
private JPanel getAllTablePanel() {
JPanel panel = new JPanel();
allTable = new JTable(allTableModel);
JScrollPane scroll = new JScrollPane(allTable);
panel.add(scroll);
allTable.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
int r = allTable.rowAtPoint(e.getPoint());
if (r >= 0 && r < allTable.getRowCount()) {
allTable.setRowSelectionInterval(r, r);
} else {
allTable.clearSelection();
}
int rowindex = allTable.getSelectedRow();
if (rowindex < 0)
return;
if (e.getComponent() instanceof JTable) {
JDialog dialog = new JDialog();
int selectedRow = allTable.getSelectedRow();
dialog.setTitle("Edit Row: " + selectedRow);
TableData data = ((AllTableModel) allTable.getModel()).getTableData().get(selectedRow);
List<TableData> tempData = new ArrayList<TableData>();
tempData.add(data);
AllTableModel tempModel = new AllTableModel(tempData);
JTable table = new JTable(tempModel);
dialog.add(new JScrollPane(table));
dialog.setVisible(true);
}
}
});
return panel;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new AllTableExample().createUI();
}
};
EventQueue.invokeLater(r);
}
}
class AllTableModel extends AbstractTableModel {
List<TableData> tableData = new ArrayList<TableData>();
Object[] columnNames = {"Name", "Grade", "Subject", "Staff"};
public AllTableModel(List<TableData> data) {
tableData = data;
}
public List<TableData> getTableData() {
return tableData;
}
#Override
public String getColumnName(int column) {
return columnNames[column].toString();
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public int getRowCount() {
return tableData.size();
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
TableData data = tableData.get(rowIndex);
switch (columnIndex) {
case 0:
return data.getName();
case 1:
return data.getGrade();
case 2:
return data.getSubject();
case 3:
return data.getStaff();
default:
return null;
}
}
}
class TableData {
private String name;
private String grade;
private String subject;
private String staff;
public TableData(String name, String grade, String subject, String staff) {
super();
this.name = name;
this.grade = grade;
this.subject = subject;
this.staff = staff;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getStaff() {
return staff;
}
public void setStaff(String staff) {
this.staff = staff;
}
}
Note: Store the row number of the table on which the pop-up opened such that after the changes in the popup dialog we have to update the original row.

Jtable update selected row

I have a jtable that has a edit button, when i select a row and clicked to edit button and edit fields, and click to save button, that row doesn't update, And i have to refresh my table to Change that row!
My code:
if (e.getSource() == editButton) {
selectedRow = uTable.getSelectedRow();
if (selectedRow >= 0) {
editUser(selectedRow);
} else {
JOptionPane.showMessageDialog(null, "Select a row");
}
}
public void editUser(int row) {
UserInformation userInf = userModel.getSelectedMember(row);
NewUserFrame_Edit edit = new NewUserFrame_Edit(userInf, row);
}
...
My NewUserFrame_Edit Class :
public class NewUserFrame_Edit extends javax.swing.JFrame {
private AllUser userModel;
private int selectedrow;
private String gender;
public NewUserFrame_Edit(AllUser userModel,UserInformation userinf, int row) {
...
this.userModel = userModel;
jTextField1.setText(userinf.getFname().toString().trim());
jTextField2.setText(userinf.getLname().toString().trim());
if (userinf.getGender().equals("Male")) {
jRadioButton1.setSelected(true);
} else {
jRadioButton2.setSelected(true);
}
jTextField3.setText(userinf.getDate());
selectedrow = row;
setVisible(true);
}
private void updateButtonActionPerformed(java.awt.event.ActionEvent evt) {
userinf = new UserInformation();
userinf.setFname(jTextField1.getText());
userinf.setLname(jTextField2.getText());
userinf.setGender(gender);
userinf.setDate(jTextField3.getText());
userModel.setValueAt(userinf.getFname() , selectedrow, 1);
userModel.setValueAt(userinf.getLname() , selectedrow, 2);
userModel.setValueAt(userinf.getGender(), selectedrow , 3);
userModel.setValueAt(userinf.getDate() , selectedrow, 4);
userModel.updateFile(userModel.Udata);
NewUserFrame_Edit.this.dispose();
}
...
}
My setValueAt() and updateFile() methods of my model Class:
public class AllUser extends AbstractTableModel {
...
#Override
public void setValueAt(Object value, int rowIndex, int columnIndex) {
UserInformation userInfo = Udata.get(rowIndex);
switch (columnIndex) {
case 0:
userInfo.setID((String) value);
break;
case 1:
userInfo.setFname((String) value);
break;
case 2:
userInfo.setLname((String) value);
break;
case 3:
userInfo.setGender((String) value);
break;
case 4:
userInfo.setDate((String) value);
break;
}
fireTableCellUpdated(rowIndex, columnIndex);
}
public void updateFile(ArrayList<UserInformation> data) {
PrintWriter pw;
try {
pw = new PrintWriter(new FileWriter("AllUserRecords.txt"));
for (UserInformation userinf : data) {
String line = userinf.getID()
+ " " + userinf.getFname()
+ " " + userinf.getLname()
+ " " + userinf.getGender()
+ " " + userinf.getDate();
pw.println(line);
}
pw.close();
} catch (IOException ioe) {
}
}
...
}
When i select a row and click to edit button, a new jframe is open that its text field is fill with older data, and i update data and click to save button.
Thus, my column is not certain.
I select a entire row, Not a cell!
Thanks.
For changing JTable entries, use TableModel#setValueAt. Calling fireTableDataChanged is unnecessary. This is for use internally within TableModel itself.
if (selectedRow >= 0) {
...
userModel.setValueAt(newValue, selectedRow, 0);
// ... more values for columns 1, 2, 3, etc.
} ...
You can create a method called updateRow(int index,String[] values) within your AbstractModel extending class and within it set new Value for each cell for that row using setValueAt(newValue,row,index). And within overridden setValue method of TableModel write fireTableCellUpdated(row, col).
Consider the Code Given below. Look at the updateRow and setValueAt method in MyModel class. And watch ((MyModel)myModel).updateRow(row,values);//update row written in MyMouseAdapter class.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.table.*;
class TableRowEdit extends JFrame
{
private JTable table;
private JScrollPane jsPane;
private TableModel myModel;
private JPanel dialogPanel;
private JTextField tf[];
private JLabel lbl[];
public void prepareAndShowGUI()
{
myModel = new MyModel();
table = new JTable(myModel);
jsPane = new JScrollPane(table);
table.getColumnModel().getColumn(2).setCellRenderer(new LabelCellRenderer());
table.addMouseListener(new MyMouseAdapter());
getContentPane().add(jsPane);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
prepareDialogPanel();
pack();
setVisible(true);
}
private void prepareDialogPanel()
{
dialogPanel = new JPanel();
int col = table.getColumnCount() - 1;
dialogPanel.setLayout(new GridLayout(col,2));
tf = new JTextField[col];
lbl = new JLabel[col];
for (int i = 0; i < col; i++)
{
lbl[i] = new JLabel(table.getColumnName(i));
tf[i] = new JTextField(10);
dialogPanel.add(lbl[i]);
dialogPanel.add(tf[i]);
}
}
private void populateTextField(String[] s)
{
for (int i = 0 ; i < s.length ; i++ )
{
tf[i].setText(s[i]);
}
}
public class LabelCellRenderer extends DefaultTableCellRenderer
{
public Component getTableCellRendererComponent(JTable table,Object oValue, boolean isSelected, boolean hasFocus, int row, int column)
{
Component c = super.getTableCellRendererComponent(table, oValue,isSelected, hasFocus,row, column);
String value = (String)oValue;
JLabel label =(JLabel)c;
label.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
label.setBackground(Color.lightGray);
label.setHorizontalTextPosition(SwingUtilities.CENTER);
label.setHorizontalAlignment(SwingUtilities.CENTER);
label.setText(value);
return label;
}
}
private class MyMouseAdapter extends MouseAdapter
{
#Override
public void mousePressed(MouseEvent evt)
{
int x = evt.getX();
int y = evt.getY();
int row = table.rowAtPoint(new Point(x,y));
int col = table.columnAtPoint(new Point(x,y));
if (col == 2)
{
String arr[] = new String[table.getColumnCount() - 1];
for (int i = 0 ; i < arr.length ; i++)
{
arr[i] = (String)table.getValueAt(row,i);
}
populateTextField(arr);
JOptionPane.showMessageDialog(TableRowEdit.this,dialogPanel,"Information",JOptionPane.INFORMATION_MESSAGE);
String[] values = new String[tf.length];
for (int i = 0 ; i < tf.length ; i++)
{
values[i] = tf[i].getText();
}
((MyModel)myModel).updateRow(row,values);//update row
}
}
}
private class MyModel extends AbstractTableModel
{
String[] columns = {
"Roll No.",
"Name",
"Action"
};
String[][] inData = {
{"1","Anthony Hopkins","Edit"},
{"2","James William","Edit"},
{"3","Mc. Donald","Edit"}
};
#Override
public void setValueAt(Object value, int row, int col)
{
inData[row][col] = (String)value;
fireTableCellUpdated(row,col);
}
#Override
public Object getValueAt(int row, int col)
{
return inData[row][col];
}
#Override
public int getColumnCount()
{
return columns.length;
}
#Override
public int getRowCount()
{
return inData.length;
}
#Override
public String getColumnName(int col)
{
return columns[col];
}
#Override
public boolean isCellEditable(int row ,int col)
{
return true;
}
//This method updates the Row of table
public void updateRow(int index,String[] values)
{
for (int i = 0 ; i < values.length ; i++)
{
setValueAt(values[i],index,i);
}
}
}
public static void main(String st[])
{
SwingUtilities.invokeLater( new Runnable()
{
#Override
public void run()
{
TableRowEdit td = new TableRowEdit();
td.prepareAndShowGUI();
}
});
}
}
UPDATE
Everything was fine with your original code. Keep the code as it was initially. The only problem was line userModel = new AllUser(); in method updateButtonActionPerformed. It was creating new object of AllUser instead of using the current one. So you should remove this line from updateButtonActionPerformed . and change the NewUserFrame_Edit constructor as follows:
public NewUserFrame_Edit(AllUser userModel/*Add this parameter*/,UserInformation userinf, int row) {
...
this.userModel = userModel;
jTextField1.setText(userinf.getFname().toString().trim());
jTextField2.setText(userinf.getLname().toString().trim());
if (userinf.getGender().equals("Male")) {
jRadioButton1.setSelected(true);
} else {
jRadioButton2.setSelected(true);
}
jTextField3.setText(userinf.getDate());
selectedrow = row;
setVisible(true);
}
change your as updateButtonActionPerformed follows:
private void updateButtonActionPerformed(java.awt.event.ActionEvent evt) {
//userModel = new AllUser();//Comment it.
userinf = new UserInformation();
userinf.setFname(jTextField1.getText());
userinf.setLname(jTextField2.getText());
userinf.setGender(gender);
userinf.setDate(jTextField3.getText());
userModel.setValueAt(userinf.getFname() , selectedrow, 1);
userModel.setValueAt(userinf.getLname() , selectedrow, 2);
userModel.setValueAt(userinf.getGender(), selectedrow , 3);
userModel.setValueAt(userinf.getDate() , selectedrow, 4);
userModel.updateFile(userModel.Udata);
NewUserFrame_Edit.this.dispose();
}
And changeeditUser(int row) method of class UserPage as follows:
public void editUser(int row)
{
UserInformation userInf = userModel.getSelectedMember(row);
NewUserFrame_Edit edit = new NewUserFrame_Edit(userModel,userInf, row);
}
Here is your updateFile methd:
public void updateFile(ArrayList<UserInformation> data) {
PrintWriter pw;
try {
pw = new PrintWriter(new FileWriter("AllUserRecords.txt"));
for (UserInformation userinf : data) {
String line = userinf.getID()
+ " " + userinf.getFname()
+ " " + userinf.getLname()
+ " " + userinf.getGender()
+ " " + userinf.getDate();
pw.println(line);
}
pw.close();
} catch (IOException ioe) {
}
}
Another way to implement changes through JTable is to use the code template below:
table.getModel().addTableModelListener(new TableModelListener(){
/**
* Called when table has been changed.
*/
#Override
public void tableChanged(TableModelEvent e) {
int row = e.getFirstRow();
int column = e.getColumn();
TableModel model = (TableModel) e.getSource();
String newdata = (String) model.getValueAt(row, column);
model.setValueAt(newdata, row, column);
// do your update with the newdata variable.
}
});
Here you can use the actual event to get the row and column of the cell that has been changed in the JTable variable.

Categories