Reputation: 2951
I am fairly new to java, so please excuse me for any foolish mistakes i make ...
I have a JTable of 2 columns in which the 2nd column can have 4 types :
The column types are dynamically since they depend on the data being received.
All types work fine, except the JCheckBox. When I replace the JCheckBox with a JComboBox with 2 choices, then it works fine. So i guess there is a problem in the code for the JCheckBox.
The problem is :
An example project (as small as i can make it) :
import java.awt.Component;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class frmCheck extends JApplet
{
JTable mgrdData;
DefaultTableModel mtableModel;
public void init()
{
mtableModel = new DefaultTableModel();
mtableModel.setColumnCount(2);
mtableModel.setRowCount(4);
mgrdData = new JTable(mtableModel);
mgrdData.getSelectionModel().addListSelectionListener(new RowListener());
add(mgrdData);
for (int i=1;i<mtableModel.getRowCount();i++)
{
addCheck(1);
}
}
private class RowListener implements ListSelectionListener
{
public void valueChanged(ListSelectionEvent event)
{
if (event.getValueIsAdjusting()) return;
}
}
private void addCheck(int intCol)
{
mgrdData.getColumnModel().getColumn(intCol).setCellRenderer(new TableCellRenderer()
{
public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean isFocused,int row,int col)
{
JCheckBox rendererComponent = new JCheckBox();
String strVal="";
if (value!=null) strVal = value.toString();
if (strVal.equals("1"))
{
rendererComponent.setSelected(true);
} else
{
rendererComponent.setSelected(false);
}
return rendererComponent;
}
});
DefaultCellEditor cellEditor = new DefaultCellEditor(new JCheckBox());
cellEditor.setClickCountToStart(1);
cellEditor.addCellEditorListener(new CellEditorListener()
{
public void editingCanceled(ChangeEvent e) {}
public void editingStopped(ChangeEvent e)
{
JCheckBox checkBox = (JCheckBox)((DefaultCellEditor)e.getSource()).getComponent();
System.out.println("isSelected = " + checkBox.isSelected());
if (checkBox.isSelected())
{
System.out.println("Sent 0");
} else
{
System.out.println("Sent 1");
}
}
});
mgrdData.getColumnModel().getColumn(intCol).setCellEditor(cellEditor);
}
}
The html page which i use to view the Applet is :
<html>
<body>
<applet code="frmCheck.class" width="1016" height="822"></applet>
</body>
</html>
To make it an executable (application) you can add the following main() function to it (above the init() function, and below the declaration of mtableModel)
public static void main(String[] args) {
frmCheck myApplet = new frmCheck(); // define applet of interest
Frame myFrame = new Frame("Applet Holder"); // create frame with title
// Call applet's init method (since Java App does not
// call it as a browser automatically does)
myApplet.init();
// add applet to the frame
myFrame.add(myApplet, BorderLayout.CENTER);
myFrame.pack(); // set window to appropriate size (for its elements)
myFrame.setVisible(true); // usual step to make frame visible
}
When you click on an unchecked checkbox, then the console shows :
isSelected = true
Sent 0
after that the checkbox is still unchecked when i click the checkbox again (thus for a second time), then the console shows :
isSelected = false
Sent 1
the checkbox flashes as checked for a short time, and then becomes unchecked again when i then click the checkbox again (thus for a third time), then it behaves like being clicked for the first time
I want the checkbox to : - send 1 when unchecked and clicked - Send 0 when checked and clicked
The real project is a bit more complex : by checking the JCheckBox I send a message to a device, which answers with its current state, which is processed and shown as a checked JCheckBox. The processing works fine as when I change the state in the device via another channel, then the JCheckBox shows the current state perfectly
I would like the JCheckBox to respond to 1 click :
Ok here is the code i have so far :
The JTable is created as follows :
JTable mgrdData;
DefaultTableModel mtableModel;
mtableModel = new DefaultTableModel(null,new String[0]);
mgrdData = new JTable(mtableModel);
mgrdData.getSelectionModel().addListSelectionListener(new RowListener());
mgrdData.setFillsViewportHeight(true);
String[] strHeader = {"Naam","Waarde"};
mtableModel.setColumnIdentifiers(strHeader);
The columns are configured as follows :
addReadOnly(0);
// addCombo(1,new String[]{"UIT","AAN"}); //this works fine
addCheck(1);
Column 0 is readonly, and column 1 has 2 possible values where addCombo(1,new String[]{"UIT","AAN"}); perfectly works
The functions addReadOnly and addCombo and addCheck are as follows :
private void addReadOnly(int intCol)
{
JTextField txtField = new JTextField();
txtField.setEditable(false);
DefaultCellEditor cellEditor = new DefaultCellEditor(txtField);
mgrdData.getColumnModel().getColumn(intCol).setCellEditor(cellEditor);
}
private void addCombo(int intCol,final String[] strItems)
{
//add combobox
mgrdData.getColumnModel().getColumn(intCol).setCellRenderer(new TableCellRenderer()
{
public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean isFocused,int row,int col)
{
JComboBox rendererComponent = new JComboBox(strItems);
if (value!=null) rendererComponent.setSelectedItem(value.toString());
return rendererComponent;
}
});
DefaultCellEditor cellEditor = new DefaultCellEditor(new JComboBox(strItems));
cellEditor.setClickCountToStart(1);
cellEditor.addCellEditorListener(new CellEditorListener()
{
private boolean blnChanged=false;
public void editingCanceled(ChangeEvent e) {}
public void editingStopped(ChangeEvent e)
{
if (blnChanged==true)
{
JComboBox comboBox = (JComboBox)((DefaultCellEditor)e.getSource()).getComponent();
sendVal(String.valueOf(comboBox.getSelectedIndex()));
blnChanged = false;
} else
{
blnChanged = true;
}
}
});
mgrdData.getColumnModel().getColumn(intCol).setCellEditor(cellEditor);
}
private void addCheck(int intCol)
{
//add checkbox
mgrdData.getColumnModel().getColumn(intCol).setCellRenderer(new TableCellRenderer()
{
public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean isFocused,int row,int col)
{
JCheckBox rendererComponent = new JCheckBox();
String strVal="";
if (value!=null) strVal = value.toString();
// if (strVal.equals("AAN"))
if (strVal.equals("1"))
{
rendererComponent.setSelected(true);
} else
{
rendererComponent.setSelected(false);
}
return rendererComponent;
}
});
DefaultCellEditor cellEditor = new DefaultCellEditor(new JCheckBox());
cellEditor.setClickCountToStart(1);
cellEditor.addCellEditorListener(new CellEditorListener()
{
public void editingCanceled(ChangeEvent e) {}
public void editingStopped(ChangeEvent e)
{
JCheckBox checkBox = (JCheckBox)((DefaultCellEditor)e.getSource()).getComponent();
System.out.println("isSelected = " + checkBox.isSelected());
if (checkBox.isSelected())
{
sendVal("0");
System.out.println("Sent 0");
} else
{
sendVal("1");
System.out.println("Sent 1");
}
}
});
mgrdData.getColumnModel().getColumn(intCol).setCellEditor(cellEditor);
}
Test results after 3 times clicking :
JCheckBox is checked, result after 1 click :
isSelected = true
Sent : REG SCH 4 = 0
Sent 0
After this the JCheckBox is unchecked
JCheckBox is unchecked, result after 1 click :
isSelected = true
Sent : REG SCH 4 = 0
Sent 0
After this the JCheckBox is still unchecked
JCheckBox is unchecked but clicked once already, result after the second click :
isSelected = false
Sent : REG SCH 4 = 1
Sent 1
After this the JCheckBox is checked
I search and found solution for when you always needed 2 clicks, or solutions with fixed checkboxes instead of dynamically, but not a case like mine ....
could anyone please shed a light ?
Upvotes: 1
Views: 3721
Reputation: 5929
Problem was that you were treating the checkbox value as a String when it's a boolean.
Working code is the following:
Boolean val = new Boolean(false);
if (value != null){
val = (Boolean) value;
}
if (val.booleanValue()) {
rendererComponent.setSelected(true);
}else{
rendererComponent.setSelected(false);
}
return rendererComponent;
I'm still looking at it, but I think the problem might be due to the fact that the JCheckBox
is selected or not depending on:
if (strVal.equals("AAN"))
{
rendererComponent.setSelected(true);
} else
{
rendererComponent.setSelected(false);
}
Isn't "AAN"
a value for the dropbox instead than for the checkbutton?
An also, you're creating a new JCheckBox each time.
Maybe a SSCCE could be useful.
Upvotes: 2
Reputation: 8865
The problem with your code is in getTableCellRendererComponent
method. Here you are always creating a new component with JCheckBox
. So every time it is taking a new JCheckBox
and rendering the column.
In addition to that there is no need to render a column to Boolean
. JTable
it self will render that. You just need to specify the column type as Boolean.class.
Overwrite the getColumnClass
method in the model (DefaultTableModel, like I have shown) and say that column-1 is a Boolean.
import javax.swing.DefaultCellEditor;
import javax.swing.JApplet;
import javax.swing.JCheckBox;
import javax.swing.JTable;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
public class frmCheck extends JApplet
{
JTable mgrdData;
DefaultTableModel mtableModel;
public void init()
{
mtableModel = new DefaultTableModel() {
@Override
public Class<?> getColumnClass(int arg0) {
if(arg0 == 1) {
return Boolean.class;
} else {
return super.getColumnClass(arg0);
}
}
};
mtableModel.setColumnCount(2);
mtableModel.setRowCount(4);
mgrdData = new JTable(mtableModel);
// mgrdData.getSelectionModel().addListSelectionListener(new RowListener());
add(mgrdData);
for (int i=1;i<mtableModel.getRowCount();i++)
{
addCheck(1);
}
}
private class RowListener implements ListSelectionListener
{
public void valueChanged(ListSelectionEvent event)
{
if (event.getValueIsAdjusting()) return;
}
}
private void addCheck(int intCol)
{
DefaultCellEditor cellEditor = new DefaultCellEditor(new JCheckBox());
mgrdData.getColumnModel().getColumn(1).getCellEditor();
cellEditor.setClickCountToStart(1);
cellEditor.addCellEditorListener(new CellEditorListener()
{
public void editingCanceled(ChangeEvent e) {}
public void editingStopped(ChangeEvent e)
{
JCheckBox checkBox = (JCheckBox)((DefaultCellEditor)e.getSource()).getComponent();
System.out.println("isSelected = " + checkBox.isSelected());
if (checkBox.isSelected())
{
System.out.println("Sent 0");
} else
{
System.out.println("Sent 1");
}
}
});
mgrdData.getColumnModel().getColumn(intCol).setCellEditor(cellEditor);
}
}
P.S: I have removed the unused code.
Upvotes: 1