I have implemented a custom TableModel that gets data from a database and then saves data to the database when a cell is edited.
Ie:
AbstractTableModel myModel = new AbstractTableModel(){
#Override public Object getValueAt(int r, int c){
//get value from the database, return it
}
#Override public setValueAt(Object val, int r, int c){
//update gui
//save change in database
}
//other methods here....
}
JTable tbl = new JTable(myModel);
This works fine, however in order for setValueAt() to be called you need to stop editing the cell, by default this only occurs when you select another cell, press enter, etc.
I then added the line:
tbl.putClientProperty("terminateEditOnFocusLost", true);
This means when I click away from the table setValueAt() is called and the database is updated, however if I edit a cell's value, then close the JFrame without the table losing focus or clicking another cell setValueAt() is never called and so the database is not updated, therefore any change you have made to that cell is lost.
Is there any way to prevent this and make the setValueAt() function be called?
I'm not sure if JTable can do the trick, but you can handle window closing event, where manually accept new value of editing cell.
frame.addWindowListener(new WindowAdapter(){
#Override
public void windowClosing(WindowEvent e) {
if(table.isEditing())
// This will dispose editor and call setValueAt() of your model as normally happens
table.getCellEditor().stopCellEditing();
}
});
Related
I created a simple mouse event. When the user clicks the JTable it will fetch the records in the JTable and display them in the JTextField. In this case I am trying to display the ID from the Table into the Text Field.
public void fetchRec() {
xtable.addMouseListener(new MouseAdapter() {
public void rowClicked(MouseEvent evt){
xtable =(JTable) evt.getSource();
int row = xtable.rowAtPoint( evt.getPoint() );
int column = xtable.columnAtPoint( evt.getPoint() );
String s=xtable.getModel().getValueAt(row, column)+"";
idLabelField.setText(s);
}
});
}
I am calling the method here but it keeps telling me that rowClicked method is unused. I don't understand how its unused? Everything else I am calling is working except this.
public void bookDimensions() throws Exception {
addTextLabels();
addTextFields();
addPanelButtons();
addRecord();
addTable();
fetchRec();
}
Turn on cell selection and listen to the selection model instead of mouse events. See java: how to select only one cell in a jtable and not the whole row
I have a JTable and I added a DefaultTabelModel to it. I created a popup menu that appears when users right click on a cell in the table. One of the items in the menu is "Rename." How can I make the selected cell editable when the Rename item is clicked? I have set up all the elements and the only missing piece here is making THE selected cell editable.
The isCellEditable(row, col) method in the DefaultTableModel is not helpful here because it sets a cell's editability based on its position (i.e. row and column) in the table, not the selection status of a cell.
I suspect that I will need TableCellEditor, but I am not sure how to use it. I would really appreciate a sample code on how to make this happen and/or explanations of how to use TableCellEditor for this purpose. Thank you in advance!!
Relevant pieces of my code:
class DataListTable extends JTable
mouseReleased():
int row = this.getSelectedRow();
popupmenu.show(this, event.getX(), event.getY());
class RenameDataMenuItem
actionPerformed():
//want to get the (row, col) of the selected cell here and make it editable
How can I make the selected cell editable when the Rename item is clicked?
The isCellEditable(...) method will determine if the cell can be edited via the table editor.
You can still change the data in the model by using the setValueAt(..) method of the JTable or the TableModel.
So what you can do is in your rename menu item you can display a JOptionPane to prompt for the new value. Then you just manually save the value using either of the above methods.
Try something along the lines of this:
public class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor {
JComponent component = new JTextField();
#Override
public Object getCellEditorValue() {
return ((JTextField)component).getText();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if(isSelected) {
((JTextField)component).setText((String)value);
}
return component;
}
}
I am working on Java the Application of Swing and which i am getting Data and i am using swing Jtable Render for render Image in that but when data is more its hanging all time so what can i do to prevent that?
example render that i am using.
public class DefaultTableCellRenderer extends javax.swing.table.DefaultTableCellRenderer {
JLabel jLabel;
public DefaultTableCellRenderer() {
jLabel = new JLabel();
}
public Component getTableCellRendererComponent(
JTable table, Object value, boolean selected, boolean focus, int row, int col) {
try {
if (row == 1) {
jLabel.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("blank.png"))));
jLabel.setText("Image Data");
jLabel.setBackground(Color.LIGHT_GRAY);
} else {
jLabel.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("blank.png"))));
jLabel.setText("Final");
}
//jLabel.setIcon(new ImageIcon(ImageIO.read(new File("blank"))));
return jLabel;
} catch (Exception e) {
e.printStackTrace();
}
return jLabel;
}
#Override
public boolean mouseEnter(Event evt, int x, int y) {
System.out.println(jLabel.getText());
return true;
}
}
This...
jLabel.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("blank.png"))));
Is an expensive call, each time it's called, a new ImageIcon class is created which is wrapping around the BufferedImage data been read. Unlike ImageIcon, ImageIO will not buffer images and re-use them, instead, it will read the resource a new.
This means, that each time the cell is rendered, the image is been fully reloaded.
Since, your loading the same image each time, simple load the image when you construct the class and make use of it when needed, for example...
public class DefaultTableCellRenderer extends javax.swing.table.DefaultTableCellRenderer {
private Icon icon;
public DefaultTableCellRenderer() throws IOException {
icon = new ImageIcon(ImageIO.read(getClass().getResource("blank.png");
}
public Component getTableCellRendererComponent(
JTable table, Object value, boolean selected, boolean focus, int row, int col) {
super.getTableCellRendererComponent(table, value, selected, focus, row, col);
setIcon(icon);
if (row == 1) {
setText("Image Data");
setBackground(Color.LIGHT_GRAY); // You may need to set the opaque state for this to work...
} else {
setText("Final");
}
return this;
}
}
Some suggestions for you:
You can load the images at the start of application using multithreading. Use the class Executors to do it. Important is: you must load all the images before you show your UI.
Another possibility is asynchronious loading of images. Use SwingWorker to load images. The loading must be implemented in the method doInBackground(). When some images are loaded you can use the methods publish()/process() to update your table model with new images.
You can combine both and use Executors in doInBackground() method.
I think, your problem is not the CPU load. Your problem is IO. Reading from hard disk is very slow and should be performed in background when it's possible.
I have a JTable, whose cell editors are JSpinners. I'm using a custom cell editor class to accomplish this. I have a few other components in my JPanel. My problem arises when the user is editing one of the cells (i.e. a JSpinner has focus) and then interacts with one of the other components without first pressing enter or losing focus. I want the JSpinner to immediately lose focus and commit the changes before running the code associated with the other components, but instead the JSpinner just retains its focus.
Ideally, I would like the JSpinner to lose focus immediately whenever the user clicks anywhere but inside the JSpinner itself. Here's my custom editor class:
public class PhyMappingTableCellEditor extends AbstractCellEditor implements TableCellEditor {
final JSpinner spinner = new JSpinner();
public PhyMappingTableCellEditor(ArrayList<String> phys) {
spinner.setModel(new SpinnerListModel(phys));
spinner.setBorder(new EmptyBorder(0,0,0,0));
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int row, int column) {
spinner.setValue(value);
return spinner;
}
#Override
public Object getCellEditorValue() {
return spinner.getValue();
}
}
Thanks in advance!
Assuming your custom editor works correctly when you tab from cell to cell then the problem is that you need to manually stop editing on the cell when the table loses focus.
Check out Table Stop Editing. It shows how to stop editing on a cell when the table loses focus. The solution will work for any cell that is being edited, not just your custom editor.
I had a similar problem. If the spinner value was edited using the keyboard and then you clicked another table cell with out first pressing enter, the edits were lost. I solved it by overriding AbstractCellEditor.stopCellEditing() like this:
#Override
public boolean stopCellEditing() {
try {
spinner.commitEdit();
}
catch (ParseException ex) {
// Do nothing
}
return super.stopCellEditing();
}
I have a cell table showing some data. For each row, I want to have two columns which contain edit / delete buttons. When each button is clicked, it should be able to notify a listener which button was clicked (and preferably also be able to pass in the object that row is associated with).
How can I do this? Specifically, I know how to render a button, but how can I process the on-click event and pass in the object which the user clicked to edit or delete?
This is the standard approach:
myTable.addCellPreviewHandler(new Handler<MyObject>() {
#Override
public void onCellPreview(CellPreviewEvent<MyObject> event) {
if ("click".equals(event.getNativeEvent().getType())) {
if (event.getColumn() == 0 || event.getColumn() == 1) {
MyObject object = event.getValue();
Window.alert("Column clicked: " + event.getColumn());
}
}
}
});
This is a more efficient solution, because you only have one handler attached to a table, instead of trying to attach a handler to each button in each row.
I think you can make a foreach through all the rows in the celltable (I never worked with celltables)
And then you can add your own ClickHandler to the Button.
Something like that (not tested):
final int row = myrow; // add the row value or a object identifier or similar
Button delete_button = new Button("delete");
delete_button.addClickHandler(new ClickHandler(){
#Override
public void onClick(ClickEvent event) {
// Insert your delete funciton
delete(row);
}
});
You mentioned a Listener, Listener are depreciated, use Handler instead.