how to set toggle button text value from db on jtable - java

how to set toggle button text value (depend on database) on jtable
Here is the code
private class CheckBoxCellEditor extends AbstractCellEditor implements
TableCellEditor, ItemListener {
protected JToggleButton toggle;
private String buttonValue;
public CheckBoxCellEditor() {
toggle = new JToggleButton("off");
toggle.setHorizontalAlignment(SwingConstants.CENTER);
toggle.addItemListener(this);
}
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
buttonValue = (value == null) ? "" : value.toString();
return toggle;
}
public Object getCellEditorValue() {
// System.out.println( buttonValue);
return buttonValue;
}
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
toggle.setText("On!");
System.out.println(buttonValue);
} else {
toggle.setText("Off");
System.out.println(buttonValue);
}
}
}
Here the image shows the toggle but it's not shows the text.
when i click the button the text shows then click next button the 1st one is not visible.
if you know the answer please share here..
with regards...

You've forgotten to set the value of the toggle button before returning it from the getTableCellEditorComponent
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
buttonValue = (value == null) ? "" : value.toString();
toggle.setText(buttonValue);
return toggle;
}
To be honest, I'm curious with what's wrong with returning Boolean from getColumnClass in the table model for the Return column and simply let the default renderer and editor deal with it...
Also...you're ignore the button value when you return it from the editor...
public Object getCellEditorValue() {
// System.out.println( buttonValue);
return buttonValue;
}
Frankly, probably better to use toggle.getText()...

Related

JTextField doesn't update on keypress

I have a JTable that uses a custom TableModel. I extended the AbstractCellEditor class and the cell correctly displays the text typed in to the textfield when I double-click the textfield. but when I just single-click select the cell in the table and start typing, the textfield receives the text but when I press enter, it doesn't update the text field. I attached a focus listener to the textfield to troubleshoot and found that it only gains and loses focus when I double click on the field. With a single-click it doesn't gain focus (even though it allows me to edit it). This boggles my mind! I've tried textField.grabFocus(), textField.requestFocusInWindow(), and all sorts of other things. Any suggestions? Thanks!
public class IndexerCellEditor extends AbstractCellEditor implements
TableCellEditor {
private JTextField textField;
private RecordValue currentValue;
public IndexerCellEditor(){
textField = new JTextField();
}
#Override
public boolean isCellEditable(EventObject e){
if(e instanceof MouseEvent){
return ((MouseEvent)e).getClickCount() >= 2;
}
return true;
}
#Override
public Object getCellEditorValue() {
return currentValue;
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
textField.setBorder(BorderFactory.createLineBorder(Color.black, 1));
currentValue = (RecordValue) value;
textField.setText(currentValue.getValue());
textField.addFocusListener(new FocusListener(){
#Override
public void focusGained(FocusEvent e) {
System.out.println("focus gained");
}
#Override
public void focusLost(FocusEvent e) {
System.out.println("focus lost");
}
});
textField.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
currentValue.setValue(((JTextField)e.getSource()).getText());
fireEditingStopped();
}
});
return textField;
}
}
OK so after about 8 more hours of banging my head against the wall, I found out 2 things:
I don't need an action listener on the jtextfield because the JTable takes care of that for me. When I hit enter after double clicking + typing OR single-click + typing, JTable automatically calls stopCellEditing(), which brings me to
I need to override stopCellEditing() in my IndexerCellEditor class to save the JTextField text before passing it up to the parent. The code I was missing:
#Override
public boolean stopCellEditing(){
currentValue = textField.getText();
return super.stopCellEditing();
}
Hope this helps anyone with the same problem.
EDIT
This works in my case because I also extended DefaultTableModel, which takes care of notifying the listeners with the method:
#Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
cells[rowIndex][columnIndex] = (String) aValue;
fireTableCellUpdated(rowIndex, columnIndex);
}
I tested this some more by building two different tables with the same extended DefaultTableModel. Placing them side-by-side in a JPanel, I could edit one cell in one table and upon pressing enter, it would update both the edited cell and its counterpart cell in the other table. In short, the listeners DO need to be notified with a fire... method call somewhere in the project.

How to select all text in JTable cell when editing but not when typing?

The default behavior of a JTable is to append to the contents when you start typing, and to place the caret at the clicked location when clicking. I want the behavior of both these things to change, so the contents is replaced when I edit a cell, either by typing or by clicking and then typing. When I click a cell and then change the caret position, however, I want the contents to stay so I can change it.
I know how to select all when the cell becomes editing, by replacing the cell editor with one that selects all inside a SwingUtilities.invokeLater (see elsewhere), but that causes the typing behavior to break. When I do this and start typing in a cell, first the typed character is appended to the string, then it is selected (but the selection is invisible!) and when typing another character the contents gets replaced by that.
Is there a way to replace the contents immediately when typing in a highlighted (but not editing) cell, but select all when clicking a cell?
Here is the code I use for the CellEditor:
public class TextFieldCellEditor extends JTextField implements TableCellEditor
{
private CellEditorListener cellEditorListener = null;
private boolean isInteger = false;
private Object oldValue;
// Start editing
#Override
public Component getTableCellEditorComponent(JTable table, Object obj, boolean isSelected, int row, int column)
{
Color color2 = DefaultLookup.getColor(this, ui, "Table.alternateRowColor");
super.setBackground(color2 != null && (row & 1) == 1? color2 : table.getBackground());
super.setForeground(table.getForeground());
super.setBorder(DefaultLookup.getBorder(this, ui, "Table.focusCellHighlightBorder"));
super.setText(obj.toString());
isInteger = obj instanceof Integer;
if (isInteger)
{
super.setHorizontalAlignment(SwingConstants.RIGHT);
oldValue = obj;
}
// SwingUtilities.invokeLater(new Runnable()
// {
// public void run()
// {
// TextFieldCellEditor.this.selectAll();
// }
// });
return this;
}
// Retrieve e dited value
#Override
public Object getCellEditorValue()
{
if (isInteger)
{
// Try to convert to integer. If input is invalid, revert.
try
{
return new Integer(super.getText());
}
catch (NumberFormatException e)
{
return oldValue;
}
}
return super.getText();
}
#Override
public boolean isCellEditable(EventObject e)
{
return true;
}
#Override
public boolean shouldSelectCell(EventObject e)
{
return true;
}
#Override
public boolean stopCellEditing()
{
cellEditorListener.editingStopped(new ChangeEvent(this));
return true;
}
#Override
public void cancelCellEditing()
{
cellEditorListener.editingCanceled(new ChangeEvent(this));
}
#Override
public void addCellEditorListener(CellEditorListener celleditorlistener)
{
cellEditorListener = celleditorlistener;
}
#Override
public void removeCellEditorListener(CellEditorListener celleditorlistener)
{
if (cellEditorListener == cellEditorListener) cellEditorListener = null;
}
}
In your getTableCellEditorComponent() implementation, add the following:
if (isSelected) {
this.selectAll();
}
As an aside, why not extend AbstractCellEditor or DefaultCellEditor(JTextField textField)? See also How to Use Tables: Using Other Editors.
Addendum: See also Table Select All Renderer and Table Select All Editor.
The cleanest solution I could find for this case was to overwrite the JTable's editCellAt and inform the CellEditor of how the edit was triggered:
#Override
public boolean editCellAt(int row, int column, EventObject e) {
cellEditor.setKeyTriggered(e instanceof KeyEvent);
return super.editCellAt(row, column, e);
}
And here is the relevant CellEditor code:
public class MyCellEditor extends DefaultCellEditor {
private boolean keyTriggered;
public MyCellEditor() {
super(new JTextField());
final JTextField textField = (JTextField) getComponent();
textField.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (!keyTriggered) {
textField.selectAll();
}
}
});
}
});
}
public void setKeyTriggered(boolean keyTriggered) {
this.keyTriggered = keyTriggered;
}
#Override
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column) {
final JTextField textField = (JTextField)
super.getTableCellEditorComponent(table, value, isSelected, row, column);
textField.selectAll();
return textField;
}
}

How to mark JTable cell input as invalid?

If I take a JTable and specify a column's classtype on it's model as follows:
DefaultTableModel model = new DefaultTableModel(columnNames, 100) {
#Override
public Class<?> getColumnClass(int columnIndex) {
return Integer.class;
}};
Then whenever a user tries to enter a double value into the table, Swing automatically rejects the input and sets the cell's outline to red.
I want the same effect to occur when someone enters a 'negative or 0' input to the cell. I've got this:
#Override
public void setValueAt(Object val, int rowIndex, int columnIndex) {
if (val instanceof Number && ((Number) val).doubleValue() > 0) {
super.setValueAt(val, rowIndex, columnIndex);
}
}
}
This prevents the cell from accepting any non-positive values, but it doesn't set the color to red and leave the cell as editable.
I tried looking into how JTable's doing the rejection by default, but I can't seem to find it.
How can I make it reject the non-positive input the same way it rejects the non-Integer input?
The private static class JTable.GenericEditor uses introspection to catch exceptions raised by constructing specific Number subclasses with invalid String values. If you don't need such generic behavior, consider creating PositiveIntegerCellEditor as a subclass of DefaultCellEditor. Your stopCellEditing() method would be correspondingly simpler.
Addendum: Updated to use RIGHT alignment and common error code.
Addendum: See also Using an Editor to Validate User-Entered Text.
private static class PositiveIntegerCellEditor extends DefaultCellEditor {
private static final Border red = new LineBorder(Color.red);
private static final Border black = new LineBorder(Color.black);
private JTextField textField;
public PositiveIntegerCellEditor(JTextField textField) {
super(textField);
this.textField = textField;
this.textField.setHorizontalAlignment(JTextField.RIGHT);
}
#Override
public boolean stopCellEditing() {
try {
int v = Integer.valueOf(textField.getText());
if (v < 0) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
textField.setBorder(red);
return false;
}
return super.stopCellEditing();
}
#Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
textField.setBorder(black);
return super.getTableCellEditorComponent(
table, value, isSelected, row, column);
}
}
I figured it out. Override the DefaultCellEditor and return false / set the border to red if the number given is not positive.
Unfortunately, since JTable.GenericEditor is static w/ default scope, I'm unable to override the GenericEditor to provide this functionality and have to re-implement it w/ a few tweaks, unless someone has a better way of doing this, which I'd like to hear.
#SuppressWarnings("serial")
class PositiveNumericCellEditor extends DefaultCellEditor {
Class[] argTypes = new Class[]{String.class};
java.lang.reflect.Constructor constructor;
Object value;
public PositiveNumericCellEditor() {
super(new JTextField());
getComponent().setName("Table.editor");
((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
}
public boolean stopCellEditing() {
String s = (String)super.getCellEditorValue();
if ("".equals(s)) {
if (constructor.getDeclaringClass() == String.class) {
value = s;
}
super.stopCellEditing();
}
try {
value = constructor.newInstance(new Object[]{s});
if (value instanceof Number && ((Number) value).doubleValue() > 0)
{
return super.stopCellEditing();
} else {
throw new RuntimeException("Input must be a positive number.");
}
}
catch (Exception e) {
((JComponent)getComponent()).setBorder(new LineBorder(Color.red));
return false;
}
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected,
int row, int column) {
this.value = null;
((JComponent)getComponent()).setBorder(new LineBorder(Color.black));
try {
Class type = table.getColumnClass(column);
if (type == Object.class) {
type = String.class;
}
constructor = type.getConstructor(argTypes);
}
catch (Exception e) {
return null;
}
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
public Object getCellEditorValue() {
return value;
}
}
This code is a small improvement of the accepted answer. If the
user does not enter any value, clicking on another cell should
allow him to select another cell. The accepted solution does not
allow this.
#Override
public boolean stopCellEditing() {
String text = field.getText();
if ("".equals(text)) {
return super.stopCellEditing();
}
try {
int v = Integer.valueOf(text);
if (v < 0) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
field.setBorder(redBorder);
return false;
}
return super.stopCellEditing();
}
This solution checks for empty text. In case of an empty text, we call the stopCellEditing() method.
So first I created an analogy to make this topic easier to be understood.
We have a pen(editor). This pen will need some ink(The component that the editor use, an example of a component is JTextField,JComboBox and so on) to write.
Then this is a special pen when we want to write something using the pen, we speak(typing behavior in the GUI) to tell it to write something(write in the model). Before writing it out, the program in this pen will evaluate whether the word is valid(which being set in stopCellEditing() method), then it writes the words out on paper(model).
Would like to explain #trashgod's answer since I have spent 4 hours on the DefaultCellEditor Section.
//first, we create a new class which inherit DefaultCellEditor
private static class PositiveIntegerCellEditor extends DefaultCellEditor {
//create 2 constant to be used when input is invalid and valid
private static final Border red = new LineBorder(Color.red);
private static final Border black = new LineBorder(Color.black);
private JTextField textField;
//construct a `PositiveIntegerCellEditor` object
//which use JTextField when this constructor is called
public PositiveIntegerCellEditor(JTextField textField) {
super(textField);
this.textField = textField;
this.textField.setHorizontalAlignment(JTextField.RIGHT);
}
//basically stopCellEditing() being called to stop the editing mode
//but here we override it so it will evaluate the input before
//stop the editing mode
#Override
public boolean stopCellEditing() {
try {
int v = Integer.valueOf(textField.getText());
if (v < 0) {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
textField.setBorder(red);
return false;
}
//if no exception thrown,call the normal stopCellEditing()
return super.stopCellEditing();
}
//we override the getTableCellEditorComponent method so that
//at the back end when getTableCellEditorComponent method is
//called to render the input,
//set the color of the border of the JTextField back to black
#Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
textField.setBorder(black);
return super.getTableCellEditorComponent(
table, value, isSelected, row, column);
}
}
Lastly, use this line of code in your class that initialise JTable to set your DefaultCellEditor
table.setDefaultEditor(Object.class,new PositiveIntegerCellEditor(new JTextField()));
The Object.class means which type of column class you wish to apply the editor
(Which part of paper you want to use that pen. It can be Integer.class,Double.class and other class).
Then we pass new JTextField() in PositiveIntegerCellEditor() constructor(Decide which type of ink you wish to use).
If anything that I misunderstood please tell me. Hope this helps!

JSpinner Update

I creates a dataTable and cellEditor form one column. This column is simple jSpinner. I have the following problem. When I enter some value in the spinner and select the another row, the value in the previous row won't be changed. If I press , it'll done. If I select or button, it will done too. But if I enter value and change selection, it won't be done. Help, please. Here is the CellEditor code.
public class DurationTableCellEditor extends AbstractCellEditor implements TableCellEditor{
final JSpinner spinner = new JSpinner();
// Initializes the spinner.
public DurationTableCellEditor() {
spinner.setModel(new SpinnerNumberModel(1,1,50000,1));
}
// Prepares the spinner component and returns it.
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
spinner.setValue(new Integer(value.toString()).intValue());
spinner.setCursor(null);
return spinner;
}
// Enables the editor only for double-clicks.
#Override
public boolean isCellEditable(EventObject evt) {
if (evt instanceof MouseEvent) {
return ((MouseEvent)evt).getClickCount() >= 1;
}
return true;
}
// Returns the spinners current value.
public Object getCellEditorValue() {
return spinner.getValue();
}
}
It's not clear how you're updating your data model, but one approach would be to implement ChangeListener in your CellEditor, much as this example implements ItemListener. For reference, see How to Use Tables: Using Other Editors. In particular, look at fireEditingStopped(). Finally, you'll need a corresponding TableCellRenderer.
do commitEdit()
// Returns the spinners current value.
public Object getCellEditorValue() {
spinner.commitEdit();
return spinner.getValue();
}

Problem with removing last row of JTable

This is my first time asking here so forgive me if something isn't appropriate, and sorry if my English isn't very good.
Well, to make it short, currently I'm developing a Java desktop app with Swing and I have a problem using table. I have rows with each row have a button to delete the row. Everything is okay (i can delete rows with no problem) until i try to delete the last row. The last row can be deleted but apparently there is an exception, something like this:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 4 >= 4
at java.util.Vector.elementAt(Vector.java:427)
at javax.swing.table.DefaultTableModel.setValueAt(DefaultTableModel.java:648)
at javax.swing.JTable.setValueAt(JTable.java:2710)
at javax.swing.JTable.editingStopped(JTable.java:4712)
at javax.swing.AbstractCellEditor.fireEditingStopped(AbstractCellEditor.java:125)
From the stack trace, it seems that "4" is my previously deleted last row index, but i have no idea how to deal with this. I already search for solution but i still can't solve it. Note that there are still other rows when i delete the last row, and after that i can't delete the others rows. The same exception also resulted when i click the delete button.
Oh. and I use removeRow() from DefaultTableModel to delete the row. Any help will be appreciated. Thanks.
EDIT
These are the code I use.
public class ViewDetail extends JInternalFrame implements ActionListener {
...
String column[] = { "Aaa", "Bbb", "Delete This"};
tableModel = new DefaultTableModel();
Object row[][] = new Object[size][column.length];
//fill the data from db
int r = 0;
for (int i = 0; i < size; i++) {
row[r][0] = ...;
row[r][1] = ...;
row[r][2] = "Delete";
r++;
}
tableModel.setDataVector(row, column);
table = new JTable(tableModel);
tableColumn = table.getColumn("Aaa");
tableColumn.setPreferredWidth(75);
tableColumn = table.getColumn("Bbb");
tableColumn.setPreferredWidth(75);
tableColumn = table.getColumn("Delete This");
tableColumn.setPreferredWidth(75);
tableColumn.setCellRenderer(new ButtonRenderer());
tableColumn.setCellEditor(new ButtonEditor(new JCheckBox());
...
}
public class ButtonRenderer extends JButton implements TableCellRenderer {
public ButtonRenderer() {
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(UIManager.getColor("Button.background"));
}
setText((value == null) ? "" : value.toString());
return this;
}
}
public class ButtonEditor extends DefaultCellEditor {
protected JButton button;
private String label;
private boolean isPushed;
private JTable table;
public ButtonEditor(JCheckBox checkBox) {
super(checkBox);
button = new JButton();
button.setOpaque(true);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (isSelected) {
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setForeground(table.getForeground());
button.setBackground(table.getBackground());
}
label = (value == null) ? "" : value.toString();
button.setText(label);
isPushed = true;
this.table = table;
return button;
}
public Object getCellEditorValue() {
if (isPushed) {
DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
tableModel.removeRow(table.getSelectedRow());
}
isPushed = false;
return new String(label);
}
public boolean stopCellEditing() {
isPushed = false;
return super.stopCellEditing();
}
protected void fireEditingStopped() {
super.fireEditingStopped();
}
}
Swing is trying to set the new value into the row you remove! Try moving the remove code into a Runnable and use invokeLater in the swing utility class to execute it.
could you post the code where you init, add elements and delete in your JTable?
My first guess is that you are either doing the classical mistake
"I have 4 elements in my table so to delete the last one I remove(4)" when you your table goes from 0 to 3 in indices
or you are trying to remove several object in the same loop like
for(int i = 0; i<lenght; i++){
if(i%2==0){//every even number
tab.remove(i);
}
}
then your are modifying the size of your table, the elements are shifted but your not taking it in account when removing.
those are just guesses/pointer to what might cause the problem. please post your code if this doesn't solve it
The Table Button Column shows how you can render a column as a button and how to add an Action that is executed when the button is clicked. The example Action just happens to show how to delete a row.
Here you need to remove only 0 th row that should be iterated
private void refreshTable() {
int rowCount= model.getRowCount();
// System.out.println(rowCount);
for(int i=0;i<rowCount;i++ ){
model.removeRow(0);
//System.out.println(i);
}
}
you can add new vaiable and check to fireEditingStopped() :
public class ButtonEditor extends DefaultCellEditor {
//create new variable
private boolean isDeleteRow = false;
/////////////////
protected JButton button;
private String label;
private boolean isPushed;
private JTable table;
public ButtonEditor(JCheckBox checkBox) {
super(checkBox);
button = new JButton();
button.setOpaque(true);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (isSelected) {
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
} else {
button.setForeground(table.getForeground());
button.setBackground(table.getBackground());
}
label = (value == null) ? "" : value.toString();
button.setText(label);
isPushed = true;
this.table = table;
// set false when click to button
isDeleteRow = false;
/////////////////
return button;
}
public Object getCellEditorValue() {
if (isPushed) {
// set true when isPushed button
isDeleteRow = true;
/////////////////
}
isPushed = false;
return new String(label);
}
public boolean stopCellEditing() {
isPushed = false;
return super.stopCellEditing();
}
protected void fireEditingStopped() {
super.fireEditingStopped();
//check if isDeleteRow, remove row
if(isDeleteRow)
{
DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
tableModel.removeRow(table.getSelectedRow());
}
/////////////////
}
}

Categories