How do I get the code for the line that I edited using the JTable and its listeners?
I'm doing this:
import java.util.Arrays;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
class TableListener implements TableModelListener {
#Override
public void tableChanged(TableModelEvent e) {
if ( e.getType() == TableModelEvent.UPDATE ) {
System.out.println("Updating ...\n");
TableModel model = (TableModel)e.getSource();
String columnName = model.getColumnName(e.getColumn());
Object data = model.getValueAt(e.getFirstRow(), e.getColumn());
System.out.println(Arrays.asList(data));
}
}
}
model.addTableModelListener(new TableListener());
CustomersList lista = new CustomersList();
final JTable table = lista.getTable();
table.setModel(model);
table.setColumnSelectionAllowed(false);
lista.setVisible(true);
I just do not have, or know of no method that returns only the code myself, I also block cell editing in the code ..
Yes, but this getting after edited
The model does not track before/after values. If you want this information you need to do it yourself.
Or, you can use the Table Cell Listener which does this for you.
Related
I would like to check the validity of user input every time they change a value on the JTable. The method I thought of is similar to this simplified sample code:
public static void main(String[] args) {
JFrame main = new JFrame();
JTable table = new JTable(6, 4);
table.setSize(300, 300);
table.getModel().addTableModelListener((TableModelEvent e) -> {
Object s = e.getSource();
TableModel d = (TableModel) s;
if(!checkValid(d.getValueAt(e.getFirstRow(), e.getColumn())))
{
d.setValueAt(" - ", e.getFirstRow(), e.getColumn());
}
});
main.add(table);
main.setSize(300,300);
main.setLocationRelativeTo(null);
main.setVisible(true);
main.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
The code will check the input if a change in the table occurs and will revert back to "-" if the input is invalid.
However, an error will occur stating that Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError.
a.) Could someone explain the error and how to solve the issue?
b.) Or is there a better way of implementing a listener that checks the user input BEFORE exiting editing mode or saving the table?
EDIT: I have tried implementing the CellEditorListener like the sample below:
table.getCellEditor().addCellEditorListener(new CellEditorListener() {
public void editingStopped(ChangeEvent e)
{
}
public void editingCanceled(ChangeEvent e)
{
}
});
This in turn prompted an error Exception in thread "main" java.lang.NullPointerException. There isn't that much of documentation on CellEditorListener and didn't quite understood on how it works and how to use it.
According to the corresponding section of the corresponding Java tutorials, you can override stopCellEditing of DefaultCellEditor to return false if the editor should not lose focus or true otherwise. Which means we can use it to check user input first and then, according to the user's input, return false if he/she enters invalid text (or true if he/she enters valid one).
In the following example code I'm using a JTextField, which lets the users type whatever they want and then checks the user's input in stopCellEditing to be non-empty (as defined by my static checkValid method, but you can obviously alter it according to your needs):
import java.awt.Toolkit;
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
public class Main {
public static boolean checkValid(final String text) {
return text != null && !text.trim().isEmpty(); //Your checks here...
}
public static class MyCellEditor extends DefaultCellEditor {
public MyCellEditor() {
super(new JTextField());
}
#Override
public boolean stopCellEditing() {
final JTextField field = (JTextField) getComponent();
if (checkValid(field.getText())) {
//field.setBackground(Color.WHITE);
return super.stopCellEditing(); //Fires 'editing stopped' event and returns true.
}
Toolkit.getDefaultToolkit().beep();
//field.setBackground(Color.ORANGE.darker());
JOptionPane.showMessageDialog(field, "You must enter a non-empty value!", "Oups!", JOptionPane.ERROR_MESSAGE);
return false;
}
}
public static void main(final String[] args) {
final JTable table = new JTable(new DefaultTableModel(10, 10));
table.setDefaultEditor(Object.class, new MyCellEditor());
final JFrame frame = new JFrame("JTable DefaultEditor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(table);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I use DefaultTableModel for easy initialization of the table. It also returns that each cell in the table is editable (we obviously need at least one cell to be editable, in order to check the validity of the program). Every cell starts initially empty, but the cell editor won't let you leave it empty, if you start an editing event.
An alternative solution could be to add an InputVerifier in the JTextField of the editor, but this would be a bit more tricky as I tested it, so I would rather not post it here in favor of the better above solution (and also suggested by the Java tutorial).
What could be the problem here why the static method doesn't print components names of components in a JPanel?
import java.awt.Component;
import java.awt.Window;
import javax.swing.*;
public class Users {
public static void saveUpdate(JPanel pnlUsers)
{
Component[] components = pnlUsers.getComponents();
for(int i=0;i<components.length;i++){
System.out.println("Component name - " + components[i].getName());
// For database update. Code will be added after fix.
}
}
}
components[i].getName() always returns null instead of the componenet's name.
I am trying to make a functionality for quick search of clients from database on some keystrokes from user, using an editable combobox. What i wanted to have is, user will put in some letters and if those lettters match with some clients, those clients will be remained in the current data model of the combobox.
The code is as follows.
Please fix the exception occuring in the code. Thanks in Advance !!
Exception in thread "AWT-EventQueue-0"
java.lang.IllegalStateException: Attempt to mutate in notification
import java.util.ArrayList;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
class ComboSearch extends JFrame implements CaretListener
{
private JComboBox mycombo;
private ArrayList<String> list;
private DefaultComboBoxModel<String> isolatemodel,model;
public ComboSearch()
{
setSize(400, 400);
setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
mycombo=new JComboBox();
mycombo.setEditable(true);
mycombo.setBounds(30,30, 350, 50);
isolatemodel=new DefaultComboBoxModel();
model=new DefaultComboBoxModel();
list=new ArrayList();
add(mycombo);
mycombo.setModel(isolatemodel);
((JTextField)mycombo.getEditor()
.getEditorComponent()).addCaretListener(this);
setVisible(true);}
private void addElements()
{
list.add("Rambhau, Vijay Nagar");
list.add("Surya, Ashok Puri");
list.add("Mourya, Shahjapur");
list.add("Kishorji & sons, Bhopal");
list.add("Fablica & jewels, Itanagar");
list.add("Guru Kripa,Ujjain");
list.add("Hariram Nai & Bakes, Indore");
list.add("Ganesh Sev Bhandar, Harda");
list.add("Greatsome Higs, Jabalpur");
list.add("Treks and hains, Nalanda");
list.add("Tata Indora, Hoshangabad");
list.add("Paankhai Seth, Madurai");
list.add("Katappa, Shikara");
list.add("Gunjan Samosa, Vijay Nagar");
list.add("Ramesh hustlers , Vijay Nagar");
}
public void makeModels()
{
addElements();
list.stream().forEach((client) -> {
isolatemodel.addElement(client);
});
}
#Override
public void caretUpdate(CaretEvent e)
{
String searchText=((JTextField)mycombo.getEditor()
.getEditorComponent()).getText();
if(!searchText.isEmpty())
{
for(int i=0; i<isolatemodel.getSize();i++)
{
if(isolatemodel.getElementAt(i).contains(searchText))
{
model.removeAllElements();
model.addElement(isolatemodel.getElementAt(i));
}
}
mycombo.setModel(model);
mycombo.showPopup();
}
else
{
mycombo.setModel(isolatemodel);
}
}
}
public class Execute
{
public static void main(String[] args)
{
ComboSearch searchIt=new ComboSearch();
searchIt.makeModels();
}
}
model.removeAllElements();
model.addElement(isolatemodel.getElementAt(i));
and if those lettters match with some clients, those clients will be remained in the current data model
Well, then it doesn't make sense to remove all the items every time you find a match. Then you will only ever have one entry left in the combo box.
You need to remove all the items BEFORE you start your loop processing and then just add back in the elements that match.
IllegalStateException:
You are trying to update the combo box model before processing of the typed event has finished processing.
Wrap the code in the listener in a SwingUtiltities.invokeLater(...) to the code will be executed after all processing has been finished.
Also, you would generally use a DocuementListener to be notified when the text of the editor has changed, not a CaretListener. The user could use the arrow keys to move the caret so there is no need to update the model in that case.
I want to make a JTable cell renderer which will be able to recognize a type of data and use a appropriate representation.
More specific, i want my table to be able to recognize if type of data is Collection and in that case to use JComboBox for representation (in other cases a standard representation: JCheckBox for boolean type and JLabel for other types and for that I'm using custom model's method getColumnClass())
I don't know the type of data in advance, in which column will be Collection or even is there will be Collection at all so I can't use a standard way of
JComboBox cell renderer TableColumn column = table.getColumnModel().getColumn(1);
or similar which I'm familiar with.
Please help :)
You can use the DefaultRendering mechanism inside JTable, reusing this mechanism to apply for each cell:
tableView.setDefaultRenderer(TitleViewCell.class, new TitleTableCellRenderer.class());
tableView.setDefaultRenderer(DataViewCell.class, new DataTableCellRenderer.class());
Here you can subclass a JTable into a JTableView for example:
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
public class JTableView extends JTable
{
private static final long serialVersionUID = -1350656893711208356L;
public JTableView(TableModel tableModel)
{
super(tableModel);
}
public TableCellRenderer getCellRenderer(int row, int column)
{
Object value = getValueAt(row, column);
if (value != null)
{
return getDefaultRenderer(value.getClass());
}
return super.getCellRenderer(row, column);
}
};
I have a panel where the user will search for a customer by entering a surname or ID. I want to implement some kind of table that displays each row of SQL query results. What's the best way to do this? The first thing that comes to my mind would be to use a multi-dimensional array and a JTextArea. What do you think?
Have you looked into a JTable?
Edit: This is my first time replying so I guess I'll notice when I do something wrong. I have recently created something similar to what you are aiming for, so this piece of code might set you on your way:
String[][] results = null;
if(query != null){
results = domeinController.Search(query);
} else {
results = domeinController.ReturnAllAccounts();
txtSearch.setText("");
}
TableModel table = new DefaultTableModel(results, new String[] {d("LBL_SERVICE"), d("LBL_ACC_NAME"), d("LBL_PASSWORD"), d("LBL_EMAIL")});
tblResults = new JTable(){
public boolean isCellEditable(int roxIndex, int colIndex){
return false;
}
};
jScrollPane1.setViewportView(tblResults);
tblResults.setModel(table);
tblResults.setAutoCreateRowSorter(true);
tblResults.setBounds(55, 145, 423, 228);
tblResults.getTableHeader().setAutoscrolls(true);
tblResults.getTableHeader().setReorderingAllowed(false);
tblResults.getTableHeader().setResizingAllowed(false);
tblResults.setShowVerticalLines(false);
tblResults.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
tblResultsMousePressed(evt);
}
});
Basically you create a tableModel with a 2D Array of data as your 1st parameter, and an array with headers for your 2nd parameter. After that you can specify behaviour to your table.
I highly recommend taking Glazed List into account.
It's a library which takes care of the most of the heavylifting related to presenting tabular data in a table with both filtering and sorting. It also provides a multithreading-safe datamodel. Using bare Swing and Java it's a lot lot harder to implement it all correctly.
Here is a nice tutorial provided. Once anybody starts writing CRUD GUIs, sooner or later all end up wanting so called "standard features" which all table oriented guis share in common. Why wasting time inventing it all and risking making a lot of mistakes, when you can build upon proven solutions. Especially, when it's so easy.
An example, displaying a XML based JTable:
import java.util.*;
import java.io.*;
import javax.swing.*;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
// a simple issues library
import ca.odell.issuezilla.*;
// glazed lists
import ca.odell.glazedlists.*;
import ca.odell.glazedlists.swing.*;
/**
* An IssueBrowser is a program for finding and viewing issues.
*
* #author <href="mailto:jesse#odel.on.ca">Jesse Wilson</a>
*/
public class IssuesBrowser {
/** event list that hosts the issues */
private EventList issuesEventList = new BasicEventList();
/**
* Create an IssueBrowser for the specified issues.
*/
public IssuesBrowser(Collection issues) {
issuesEventList.addAll(issues);
}
/**
* Display a frame for browsing issues.
*/
public void display() {
// create a panel with a table
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
EventListModel issuesListModel = new EventListModel(issuesEventList);
JList issuesJList = new JList(issuesListModel);
JScrollPane issuesListScrollPane = new JScrollPane(issuesJList);
panel.add(issuesListScrollPane, new GridBagConstraints(...));
// create a frame with that panel
JFrame frame = new JFrame("Issues");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(540, 380);
frame.getContentPane().add(panel);
frame.show();
}
/**
* Launch the IssuesBrowser from the commandline.
*/
public static void main(String[] args) {
if(args.length != 1) {
System.out.println("Usage: IssuesBrowser <file>");
return;
}
// load some issues
Collection issues = null;
try {
IssuezillaXMLParser parser = new IssuezillaXMLParser();
InputStream issuesInStream = new FileInputStream(args[0]);
issues = parser.loadIssues(issuesInStream, null);
issuesInStream.close();
} catch(IOException e) {
e.printStackTrace();
return;
}
// create the browser
IssuesBrowser browser = new IssuesBrowser(issues);
browser.display();
}
}