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! :)
Related
Well I'm making a simple program to see how works swing elements. Main problem is that when I change the data of table's model not updates the view. I'm using MVP and I've tried "fireTableDataChanged", "fireTableStructureChanged", "repaint", "validate"...
So here's the presenter with "registerStudent" method:
public class StudentPresenter {
private List<Student> students;
private StudentView view;
public StudentPresenter(StudentView view) {
students = new ArrayList<>();
this.view = view;
}
public void run() {
JFrame frame = new JFrame("Students Registrator");
frame.setContentPane(view.getMainFrame());
frame.setLocationRelativeTo(null);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void registerStudent() {
students.add(new Student("Nuevo", 1, 2));
students.add(new Student("Otro", 3, 4));
((TableModel) view.getTable().getModel()).setData(students);
((TableModel) view.getTable().getModel()).refresh();
view.getTable().repaint();
}
}
TableModel with "refresh" method:
public class TableModel extends AbstractTableModel {
private String[] columnNames = {"Nombre", "Edad", "Curso"};
private List<Student> data = new ArrayList<>();
public TableModel() {
data.add(new Student("Ejemplo", 0, 0));
}
public void setData(List<Student> data) {
this.data = data;
}
public void refresh() {
fireTableDataChanged();
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public String getColumnName(int column) {
return columnNames[column];
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
switch(columnIndex) {
case 0:
return data.get(rowIndex).getName();
case 1:
return data.get(rowIndex).getAge();
case 2:
return data.get(rowIndex).getCourse();
default:
return null;
}
}
}
StudentView:
public class StudentView {
private StudentPresenter presenter;
private JMenuBar menuBar;
private JScrollPane scrollPane;
private JPanel mainFrame;
private JTable table;
private JButton registerButton;
public StudentView() {
createUIComponents();
}
private void createUIComponents() {
buildMenu();
buildButtons();
buildTable();
}
private void buildMenu() {
menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem exitItem = new JMenuItem("Salir");
exitItem.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
fileMenu.add(exitItem);
JMenu editMenu = new JMenu("Edit");
menuBar.add(fileMenu);
menuBar.add(editMenu);
}
private void buildButtons() {
registerButton = new JButton();
registerButton.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
presenter.registerStudent();
}
});
}
private void buildTable() {
table = new JTable(new TableModel());
table.setFillsViewportHeight(true);
table.setBackground(Color.LIGHT_GRAY);
table.setForeground(Color.gray);
table.setFont(new Font("Arial", Font.PLAIN, 12));
table.setRowHeight(30);
scrollPane = new JScrollPane(table);
}
public void setPresenter(StudentPresenter presenter) {
this.presenter = presenter;
}
public JPanel getMainFrame() {
return mainFrame;
}
public JTable getTable() {
return table;
}
}
I am dynamically creating JTextField based on click event on '+' button. Below is screen shot.
The problem is when I click '+' button, fields created but not shown on JFrame. When I put the cursor on next row under 'item Name', text field becomes visible.
Where is the problem?
Below is my code.
CreateBill()
{
jf = new JFrame("Create Bill");
jf.getContentPane().setLayout(null);
jf.setExtendedState(JFrame.MAXIMIZED_BOTH);
jf.setBounds(0, 0, d1.width, d1.height);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
createRow(); // This will create first row by default.
jf.pack();
jf.setVisible(true);
}
private void createRow() {
textField = new JTextField();
textField.setToolTipText("item name");
textField.setBounds(143, 46+j, 288, 20);
textField.setColumns(10);
textField.getDocument().addDocumentListener(new DocumentListener()
{
#Override
public void insertUpdate(DocumentEvent e) {
updatePrice();
}
#Override
public void removeUpdate(DocumentEvent e) {
}
#Override
public void changedUpdate(DocumentEvent e) {
updatePrice();
}
});
AutoCompleteDecorator.decorate(textField, names, true);
jf.getContentPane().add(comboComplete);
jf.getContentPane().add(textField);
comboComplete.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
String ItemSel = textField.getText().trim();
for(Item s:items)
{
if(s.getItemName().equals(ItemSel))
{
textField_1.setText(String.valueOf(s.getUnitPrice()));
}
}
}
});
textFields.add(textField);
textField_1 = new JTextField();
textField_1.setEditable(false);
textField_1.setBounds(639, 46+j, 175, 20);
jf.getContentPane().add(textField_1);
textField_1.setColumns(10);
qty = new JTextField();
qty.setBounds(455, 46+j, 156, 20);
jf.getContentPane().add(qty);
qty.setColumns(10);
qty.getDocument().addDocumentListener(new DocumentListener()
{
#Override
public void insertUpdate(DocumentEvent e) {
getTotal();
}
#Override
public void removeUpdate(DocumentEvent e) {
}
#Override
public void changedUpdate(DocumentEvent e) {
getTotal();
}
});
textFields.add(qty);
textFields.add(textField_1);
textField_3 = new JTextField();
textField_3.setEditable(false);
textField_3.setBounds(1038, 46+j, 156, 20);
jf.getContentPane().add(textField_3);
textField_3.setColumns(10);
textFields.add(textField_3);
JButton button = new JButton("+");
button.setBounds(1235, 45+j, 89, 23);
jf.getContentPane().add(button);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("value of J"+j);
createRow(); // after pressing '+' button i am calling same method again. by changing value of j.
}
});
j=j+22;
jf.setVisible(true);
}
I want my all 4 text fields appear simultaneously.
You need to call repaint() on the container after adding a component to it. You also should call revalidate() too, before calling repaint, since this tells the layout managers to layout the new component, but you're using null layouts, something that you really want to avoid doing.
So my suggestion is to either 1) use nested JPanels with appropriate layout managers, and call revalidate and repaint on your containers after adding or removing components, or 2) yeah, use a Cardlayout to swap views as Andrew Thompson astutely recommends. You can have your second JPanel have a JTextField that uses the same Document as the previous JPanel, so it looks like both are using the same JTextField (as the top JTextField).
On looking further at your images, I have to wonder if a JTable might be an even better solution overall. And yeah, after you start using the layout managers, do also call pack() on your top level window after adding all components and before setting it visible.
For an example of a JTable implementation of this, something along the lines of...
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
#SuppressWarnings("serial")
public class CreateRowGui extends JPanel {
private static final Item[] ITEMS = {
new Item("Light Bulb", 2.00),
new Item("Toilet Paper", 3.00),
new Item("Toothpaste", 1.50),
new Item("Aspirin", 3.75) };
private ItemTableModel tableModel = new ItemTableModel();
private JTable table = new JTable(tableModel);
private AddRowAction addRowAction = new AddRowAction("Add Row", KeyEvent.VK_A);
public CreateRowGui() {
TableCellRenderer moneyRenderer = new DefaultTableCellRenderer() {
private NumberFormat currFormat = NumberFormat.getCurrencyInstance();
#Override
protected void setValue(Object value) {
if (value != null) {
value = currFormat.format(value);
}
super.setValue(value);
}
};
table.getColumnModel().getColumn(2).setCellRenderer(moneyRenderer);
table.getColumnModel().getColumn(3).setCellRenderer(moneyRenderer);
JPanel btnPanel = new JPanel();
btnPanel.add(new JButton(addRowAction));
btnPanel.add(new JButton("Remove Row")); // TODO: need Action for this
setLayout(new BorderLayout());
add(new JScrollPane(table));
add(btnPanel, BorderLayout.PAGE_END);
}
class AddRowAction extends AbstractAction {
private NewRowPanel newRowPanel = new NewRowPanel(ITEMS);
public AddRowAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
newRowPanel.reset();
int reply = JOptionPane.showConfirmDialog(table,
newRowPanel.getMainPanel(),
"Select Item and Quantity",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE);
if (reply == JOptionPane.OK_OPTION) {
Item item = newRowPanel.getSelectedItem();
int quantity = newRowPanel.getQuantity();
tableModel.addRow(item, quantity);
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("CreateRowGui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new CreateRowGui());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class NewRowPanel {
private JPanel mainPanel = new JPanel();
private JComboBox<Item> itemsCombo;
private JSpinner quantitySpinner = new JSpinner(new SpinnerNumberModel(0, 0, 20, 1));
#SuppressWarnings("serial")
public NewRowPanel(Item[] items) {
itemsCombo = new JComboBox<>(items);
itemsCombo.setRenderer(new DefaultListCellRenderer(){
#Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
if (value != null) {
value = ((Item) value).getName();
} else {
value = "";
}
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
});
mainPanel.add(new JLabel("Item:"));
mainPanel.add(itemsCombo);
mainPanel.add(Box.createHorizontalStrut(15));
mainPanel.add(new JLabel("Quantity"));
mainPanel.add(quantitySpinner);
}
public void reset() {
itemsCombo.setSelectedIndex(-1);
quantitySpinner.setValue(0);
}
public JPanel getMainPanel() {
return mainPanel;
}
public Item getSelectedItem() {
return (Item) itemsCombo.getSelectedItem();
}
public int getQuantity() {
return (int) quantitySpinner.getValue();
}
}
class ItemTableModel extends AbstractTableModel {
private static final String[] COL_NAMES = { "Item Name", "Quantity", "Unit Price", "Total" };
private static final long serialVersionUID = 1L;
private List<ItemWithCount> itemsWithCount = new ArrayList<>();
#Override
public int getColumnCount() {
return 4;
}
#Override
public int getRowCount() {
return itemsWithCount.size();
}
#Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return super.getColumnClass(columnIndex);
case 1:
return Integer.class;
case 2:
case 3:
return Double.class;
}
return super.getColumnClass(columnIndex);
}
#Override
public String getColumnName(int column) {
return COL_NAMES[column];
}
#Override
public Object getValueAt(int row, int column) {
ItemWithCount itemWithCount = itemsWithCount.get(row);
switch (column) {
case 0:
return itemWithCount.getItem().getName();
case 1:
return itemWithCount.getCount();
case 2:
return itemWithCount.getItem().getUnitPrice();
case 3:
return itemWithCount.getCount() * itemWithCount.getItem().getUnitPrice();
}
return null;
}
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
ItemWithCount itemWithCount = itemsWithCount.get(rowIndex);
switch (columnIndex) {
case 1:
itemWithCount.setCount((int) aValue);
fireTableRowsUpdated(rowIndex, rowIndex);
break;
default:
break;
}
}
#Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 0 || columnIndex == 1;
}
public void addRow(Item item, int quantity) {
ItemWithCount itemWithCount = new ItemWithCount(item, quantity);
itemsWithCount.add(itemWithCount);
int row = itemsWithCount.size() - 1;
fireTableRowsInserted(row, row);
}
private class ItemWithCount {
private Item item;
private int count;
public ItemWithCount(Item item, int count) {
this.item = item;
this.count = count;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public Item getItem() {
return item;
}
}
}
class Item {
private String name;
private double unitPrice;
public Item(String name, double unitPrice) {
this.name = name;
this.unitPrice = unitPrice;
}
public String getName() {
return name;
}
public double getUnitPrice() {
return unitPrice;
}
public void setUnitPrice(double unitPrice) {
this.unitPrice = unitPrice;
}
#Override
public String toString() {
return "Item [name=" + name + ", unitPrice=" + unitPrice + "]";
}
}
The JDialog isn't showing the JPanel after closing of the dialog and then if the user immediately repeats the action it isn't showing a panel at all but a dialog that is solid black with a small white box in the top left corner. I have tried creating a SSCCE but couldn't develop one. If I remove the window adapter in MainControl class it will just keep adding another panel to the dialog after closing and repeating the opening of the dialog. Below is the code of the SSCCE that I tried creating but it still behaves the same. The code below is the minimal amount needed to run the dialog.
public class CreateAndShowUI {
public static void createUI() {
JFrame frame = new JFrame();
MainPanel mainPanel = new MainPanel();
Dialog dialog = new Dialog();
MainControl mainControl = new MainControl(frame, mainPanel,
dialog);
frame.getContentPane().add(mainPanel.getMainPanel());
frame.setUndecorated(true);
frame.setPreferredSize(new Dimension(1100, 550));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
createUI();
}
}
public class MainControl {
private JFrame frame;
private MainPanel mainPanel;
private Dialog dialog;
public MainControl(JFrame frame, MainPanel panel, Dialog dialog) {
this.frame = frame;
this.mainPanel = panel;
this.dialog = dialog;
mainPanel.getTable().addMouseListener(new MouseListener());
dialog.getDialog().addWindowListener(new DialogWindowListener());
}
public class MouseListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent evt) {
if (evt.getButton() == MouseEvent.BUTTON3) {
dialog.showDialog(new KeywordPanel().getKeywordPanel(),
evt.getXOnScreen(), evt.getYOnScreen());
}
}
}
public class DialogWindowListener extends WindowAdapter {
#Override
public void windowClosing(final WindowEvent event) {
dialog.getDialog().dispose();
dialog.getDialog().removeAll();
}
}
}
public class MainPanel {
private JPanel mainPanel;
private JScrollPane listScrollPane;
private JTable table;
public MainPanel() {
mainPanel = new JPanel(new MigLayout("", "", "[]13[]"));
table = new JTable(new ProductTableModel());
listScrollPane = new JScrollPane(table,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
listScrollPane.setPreferredSize(new Dimension(850, 990));
mainPanel.add(listScrollPane, "cell 0 1");
}
public JPanel getMainPanel() {
return mainPanel;
}
public JTable getTable() {
return table;
}
}
public class KeywordPanel {
private JPanel keywordPanel;
private JLabel searchLbl;
public KeywordPanel() {
searchLbl = new JLabel("KeyWords");
keywordPanel = new JPanel();
keywordPanel.add(searchLbl);
}
public JPanel getKeywordPanel() {
return keywordPanel;
}
}
public class Dialog {
private JDialog dialog = new JDialog();
public Dialog() {
dialog.setLayout(new MigLayout());
}
public void showDialog(JPanel panel, int x, int y) {
dialog.add(panel);
dialog.pack();
dialog.setVisible(true);
}
public JDialog getDialog() {
return dialog;
}
}
public class ProductTableModel extends AbstractTableModel {
private ArrayList<Object> list = new ArrayList<Object>();
private String[] columnNames = { "ID", "Description", "Inventory",
"Minimum Quantity", "Cost", "Order Quantity" };
public ProductTableModel() {
list.add(new Product("Sup", "Sup", "Sup", 10, 20, "null"));
}
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public String getColumnName(int column) {
switch (column) {
case 0:
return "<html>ID<br></html>";
case 1:
return "<html>Description<br></html>";
case 2:
return "<html>Inventory<br></html>";
case 3:
return "<html>Minimum<br>Quantity</html>";
case 4:
return "<html>Cost<br></html>";
case 5:
return "<html>Order<br>Quantity</html>";
default:
return null;
}
}
#Override
public int getRowCount() {
return list.size();
}
#Override
public boolean isCellEditable(int row, int column) {
return true;
}
#Override
public Object getValueAt(int row, int column) {
if (list.get(row) instanceof Product) {
Product product = (Product) list.get(row);
switch (column) {
case 0:
return product.getId();
case 1:
return product.getProductDescription();
case 2:
return product.getQtyOnHand();
case 3:
return product.getMinQty();
case 4:
return product.getCost();
case 5:
return product.getOrderQty();
default:
throw new IndexOutOfBoundsException();
}
} else {
return null;
}
}
}
public class Product {
private int minQty;
private double cost;
private String productDescription, id, category, qtyOnHand, orderQty;
public Product(String id, String productDescription, String qtyOnHand,
int minQty, double cost, String orderQty) {
this.setQtyOnHand(qtyOnHand);
this.setOrderQty(orderQty);
this.setId(id);
this.setMinQty(minQty);
this.setCost(cost);
this.setProductDescription(productDescription);
}
public String getQtyOnHand() {
return qtyOnHand;
}
public void setQtyOnHand(String qtyOnHand) {
this.qtyOnHand = qtyOnHand;
}
public String getOrderQty() {
return orderQty;
}
public void setOrderQty(String orderQty) {
this.orderQty = orderQty;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public double getCost() {
return cost;
}
public void setCost(double cost) {
this.cost = cost;
}
public String getProductDescription() {
return productDescription;
}
public void setProductDescription(String productDescription) {
this.productDescription = productDescription;
}
public int getMinQty() {
return minQty;
}
public void setMinQty(int minQty) {
this.minQty = minQty;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
}
You should use
dialog.getContentPane().add(panel);
and
dialog.getDialog().getContentPane().removeAll();
And you also must NOT dispose the dialog,
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)
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();