I tried hard to find a better title for this ticket but that was the best I could come up with.
I am having an issue with a JComboBox inside of a JTable. The program is a very scaled down version of the original. It pulls data from a database and puts that info into a combobox. When the data is pulled from the db it will overwrite the field. When the data is entered from a varible the issue is not present. I thought maybe that the small ammount of delay from the db was the issue, so I added some delay. I went all the way up to 20 seconds but still did not get the same results. There is a variable named DB. Set that to true and it will pull data from the db and false will use the local variable.
With the DB true go down to the last record and click in it, then just click once in the above fields. They were all 2 but now they are 1. Do the same thing but set the last field to 100 and follow the above steps. Then all records will be 100. This is not the expected behavior. The field should stay the same unless the user changes the value. With DB false it will operate as expected. I have tried all sorts of things to isolate the issue. The fact the original data comes from a db should not matter, it is just a string. There is another issue that I think is related to this same problem. If a field is blank opening the combo will overwrite the fieled and not allow the field to be cleared again.
I have prepared a jar file here, it has all of the source code and the db file. I'm not sure if there is a better way to attach the jar file. You will need to extract the code from the jar file, it will not work otherwise.
Here is the source code:
import java.io.*;
import java.lang.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
import javax.swing.table.*;
import java.util.ArrayList;
import java.util.Iterator;
public class ErrorDemo {
private String[][] comm = new String[3][6];
private int index = 0;
private JTable table;
private DefaultTableModel myData;
public String headers[] = new String[35];
private boolean DB = true;
// private boolean DB = false;
public ErrorDemo () {
Visual();
StartQuery();
}
public void Visual () {
final JFrame frame = new JFrame( "Automation" );
frame.setSize(800, 600);
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setVisible( true );
myData = new DefaultTableModel();
table = new JTable( );
table.setModel( myData );
table.setFillsViewportHeight(true);
JScrollPane scroll1 = new JScrollPane(table);
scroll1.setVisible( true );
frame.add(scroll1);
frame.repaint();
frame.setVisible( true );
}
public void StartQuery () {
// set the data to be placed into the fields
index = 2;
headers[1] = "Feild 1";
headers[2] = "Feild 2";
comm[1][1] = "aaaaaaaaaaaaaaaa2";
comm[1][2] = "aaaaaaaaaaaaaaaa2";
comm[1][3] = "aaaaaaaaaaaaaaaa2";
comm[1][4] = "aaaaaaaaaaaaaaaa2";
comm[1][5] = "aaaaaaaaaaaaaaaa2";
comm[2][1] = "aaaaaaaaaaaaaaaa2";
comm[2][2] = "aaaaaaaaaaaaaaaa2";
comm[2][3] = "aaaaaaaaaaaaaaaa2";
comm[2][4] = "aaaaaaaaaaaaaaaa2";
comm[2][5] = "aaaaaaaaaaaaaaaa2";
//set the name of the headers
for ( int i = 1 ; i <= index ; i++ )
myData.addColumn( headers[i] );
//place the data into the table
Vector v = new Vector();
for ( int i = 1; i <= 5; i++ ) {
v = new Vector();
v.addElement( comm[1][i] );
v.addElement( comm[2][i] );
myData.addRow( v );
}
//place the data into the combo box then place the combo box into the table
TableColumn Column1 = table.getColumnModel().getColumn( 0 );
JComboBox comboBox = new JComboBox();
String[] output = new String[61];
// if DB is true it pulls the data from the the database else it will use a static string.
if ( DB ) {
String comm1 = "SELECT data FROM Table1 ORDER BY data; ";
// change the following path to where ever to put it.
DBDemo dbl1 = new DBDemo( "U:/Users/Goff/java/rcc automation/GreatBeyond/db1.accdb" );
dbl1.GetQuery( comm1, 1, comboBox );
} else {
// gofflib STL = new gofflib();
// STL.sleeper( 20000 ); //a test to see if adding delay would produce the issue, it did not.
output = new String [] { "", "aaaaaaaaaaaaaaaa1", "aaaaaaaaaaaaaaaa2", "aaaaaaaaaaaaaaaa3", "aaaaaaaaaaaaaaaa4", "aaaaaaaaaaaaaaaa5", "aaaaaaaaaaaaaaaa6", "aaaaaaaaaaaaaaaa7", "aaaaaaaaaaaaaaaa8", "aaaaaaaaaaaaaaaa9", "aaaaaaaaaaaaaaaa10", "aaaaaaaaaaaaaaaa11", "aaaaaaaaaaaaaaaa12", "aaaaaaaaaaaaaaaa13", "aaaaaaaaaaaaaaaa14", "aaaaaaaaaaaaaaaa15", "aaaaaaaaaaaaaaaa16", "aaaaaaaaaaaaaaaa17", "aaaaaaaaaaaaaaaa18", "aaaaaaaaaaaaaaaa19", "aaaaaaaaaaaaaaaa20", "aaaaaaaaaaaaaaaa21", "aaaaaaaaaaaaaaaa22", "aaaaaaaaaaaaaaaa23", "aaaaaaaaaaaaaaaa24", "aaaaaaaaaaaaaaaa25", "aaaaaaaaaaaaaaaa26", "aaaaaaaaaaaaaaaa27", "aaaaaaaaaaaaaaaa28", "aaaaaaaaaaaaaaaa29", "aaaaaaaaaaaaaaaa30", "aaaaaaaaaaaaaaaa31", "aaaaaaaaaaaaaaaa32", "aaaaaaaaaaaaaaaa33", "aaaaaaaaaaaaaaaa34", "aaaaaaaaaaaaaaaa35", "aaaaaaaaaaaaaaaa36", "aaaaaaaaaaaaaaaa37", "aaaaaaaaaaaaaaaa38", "aaaaaaaaaaaaaaaa39", "aaaaaaaaaaaaaaaa40", "aaaaaaaaaaaaaaaa41", "aaaaaaaaaaaaaaaa42", "aaaaaaaaaaaaaaaa43", "aaaaaaaaaaaaaaaa44", "aaaaaaaaaaaaaaaa45", "aaaaaaaaaaaaaaaa46", "aaaaaaaaaaaaaaaa47", "aaaaaaaaaaaaaaaa48", "aaaaaaaaaaaaaaaa49", "aaaaaaaaaaaaaaaa50", "aaaaaaaaaaaaaaaa51", "aaaaaaaaaaaaaaaa52", "aaaaaaaaaaaaaaaa53", "aaaaaaaaaaaaaaaa54", "aaaaaaaaaaaaaaaa55", "aaaaaaaaaaaaaaaa56", "aaaaaaaaaaaaaaaa57", "aaaaaaaaaaaaaaaa58", "aaaaaaaaaaaaaaaa59", "aaaaaaaaaaaaaaaa60", "aaaaaaaaaaaaaaaa61", "aaaaaaaaaaaaaaaa62", "aaaaaaaaaaaaaaaa63", "aaaaaaaaaaaaaaaa64", "aaaaaaaaaaaaaaaa65", "aaaaaaaaaaaaaaaa66", "aaaaaaaaaaaaaaaa67", "aaaaaaaaaaaaaaaa68", "aaaaaaaaaaaaaaaa69", "aaaaaaaaaaaaaaaa70", "aaaaaaaaaaaaaaaa71", "aaaaaaaaaaaaaaaa72", "aaaaaaaaaaaaaaaa73", "aaaaaaaaaaaaaaaa74", "aaaaaaaaaaaaaaaa75", "aaaaaaaaaaaaaaaa76", "aaaaaaaaaaaaaaaa77", "aaaaaaaaaaaaaaaa78", "aaaaaaaaaaaaaaaa79", "aaaaaaaaaaaaaaaa80", "aaaaaaaaaaaaaaaa81", "aaaaaaaaaaaaaaaa82", "aaaaaaaaaaaaaaaa83", "aaaaaaaaaaaaaaaa84", "aaaaaaaaaaaaaaaa85", "aaaaaaaaaaaaaaaa86", "aaaaaaaaaaaaaaaa87", "aaaaaaaaaaaaaaaa88", "aaaaaaaaaaaaaaaa89", "aaaaaaaaaaaaaaaa90", "aaaaaaaaaaaaaaaa91", "aaaaaaaaaaaaaaaa92", "aaaaaaaaaaaaaaaa93", "aaaaaaaaaaaaaaaa94", "aaaaaaaaaaaaaaaa95", "aaaaaaaaaaaaaaaa96", "aaaaaaaaaaaaaaaa97", "aaaaaaaaaaaaaaaa98", "aaaaaaaaaaaaaaaa99", "aaaaaaaaaaaaaaaa100" };
for ( int i = 1; i <= 100; i++ ) {
comboBox.addItem( output[i] );
}
}
Column1.setCellEditor(new DefaultCellEditor(comboBox));
table.repaint();
table.revalidate();
}
public static void main(String[] args) {
new ErrorDemo();
}
}
Here is DBDemo
import java.sql.*;
import net.ucanaccess.jdbc.JackcessOpenerInterface;
import com.healthmarketscience.jackcess.Database;
import com.healthmarketscience.jackcess.DatabaseBuilder;
import net.ucanaccess.converters.TypesMap.AccessType;
import net.ucanaccess.ext.FunctionType;
import net.ucanaccess.jdbc.UcanaccessConnection;
import net.ucanaccess.jdbc.UcanaccessDriver;
import org.apache.commons.lang.builder.*;
import org.apache.commons.logging.*;
import org.hsqldb.jdbc.*;
import java.util.*;
import javax.swing.table.*;
import javax.swing.*;
public class DBDemo {
private Connection con;
private Statement st;
private ResultSet rs;
private String db;
private String comm = "";
private int index = 0;
private String Path = "";
public DBDemo ( String arg1 ) {
Path = arg1;
}
public void GetQuery ( String comm, int index, JComboBox comb ) {
try {
String output = "";
String path = new java.io.File(Path).getAbsolutePath();
db = "jdbc:ucanaccess://" + path;
Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");
con = DriverManager.getConnection(db);
st = con.createStatement();
output = "";
rs = st.executeQuery( comm );
while (rs.next()) {
for ( int i = 1; i <= index; i++ ) {
Object o = rs.getObject(i);
String t;
t = ( o == null ? "" : o.toString() );
output += t + " ";
}
comb.addItem( output );
output = "";
}
rs.close();
st.close();
con.close();
} catch( NullPointerException | SQLException | ClassNotFoundException ex ){
ex.printStackTrace();
}
}
}
I have tried to make the code as concise as possible.
With DB = true or DB = false, either processes the same data into a string and then puts it into the combo box. How could this elicit different behavior?
UPDATE: here is the new code that uses a custom cell renderer.
import java.io.*;
import java.lang.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
import javax.swing.table.*;
import java.util.ArrayList;
import java.util.Iterator;
public class ErrorDemo {
private String[][] comm = new String[3][6];
private int index = 0;
private JTable table;
private DefaultTableModel myData;
public String headers[] = new String[35];
private boolean DB = true;
// private boolean DB = false;
public ErrorDemo () {
Visual();
StartQuery();
}
public void Visual () {
final JFrame frame = new JFrame( "Automation" );
frame.setSize(800, 600);
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setVisible( true );
myData = new DefaultTableModel();
table = new JTable( );
table.setModel( myData );
table.setFillsViewportHeight(true);
JScrollPane scroll1 = new JScrollPane(table);
scroll1.setVisible( true );
frame.add(scroll1);
frame.repaint();
frame.setVisible( true );
}
public void StartQuery () {
// set the data to be placed into the fields
index = 2;
headers[1] = "Feild 1";
headers[2] = "Feild 2";
comm[1][1] = "aaaaaaaaaaaaaaaa2";
comm[1][2] = "aaaaaaaaaaaaaaaa2";
comm[1][3] = "aaaaaaaaaaaaaaaa2";
comm[1][4] = "aaaaaaaaaaaaaaaa2";
comm[1][5] = "aaaaaaaaaaaaaaaa2";
comm[2][1] = "aaaaaaaaaaaaaaaa2";
comm[2][2] = "aaaaaaaaaaaaaaaa2";
comm[2][3] = "aaaaaaaaaaaaaaaa2";
comm[2][4] = "aaaaaaaaaaaaaaaa2";
comm[2][5] = "aaaaaaaaaaaaaaaa2";
//set the name of the headers
for ( int i = 1 ; i <= index ; i++ )
myData.addColumn( headers[i] );
//place the data into the table
Vector v = new Vector();
for ( int i = 1; i <= 5; i++ ) {
v = new Vector();
v.addElement( comm[1][i] );
v.addElement( comm[2][i] );
myData.addRow( v );
}
//place the data into the combo box then place the combo box into the table
TableColumn Column1 = table.getColumnModel().getColumn( 0 );
// JComboBox comboBox = new JComboBox();
MyComboBoxRenderer comboBox = new MyComboBoxRenderer();
String[] output = new String[61];
// if DB is true it pulls the data from the the database else it will use a static string.
if ( DB ) {
String comm1 = "SELECT data FROM Table1 ORDER BY data; ";
// change the following path to where ever to put it.
DBDemo dbl1 = new DBDemo( "U:/Users/Goff/java/rcc automation/GreatBeyond/db1.accdb" );
dbl1.GetQuery( comm1, 1, comboBox );
} else {
gofflib STL = new gofflib();
// STL.sleeper( 20000 ); //a test to see if adding delay would produce the issue, it did not.
output = new String [] { "", "aaaaaaaaaaaaaaaa1", "aaaaaaaaaaaaaaaa2", "aaaaaaaaaaaaaaaa3", "aaaaaaaaaaaaaaaa4", "aaaaaaaaaaaaaaaa5", "aaaaaaaaaaaaaaaa6", "aaaaaaaaaaaaaaaa7", "aaaaaaaaaaaaaaaa8", "aaaaaaaaaaaaaaaa9", "aaaaaaaaaaaaaaaa10", "aaaaaaaaaaaaaaaa11", "aaaaaaaaaaaaaaaa12", "aaaaaaaaaaaaaaaa13", "aaaaaaaaaaaaaaaa14", "aaaaaaaaaaaaaaaa15", "aaaaaaaaaaaaaaaa16", "aaaaaaaaaaaaaaaa17", "aaaaaaaaaaaaaaaa18", "aaaaaaaaaaaaaaaa19", "aaaaaaaaaaaaaaaa20", "aaaaaaaaaaaaaaaa21", "aaaaaaaaaaaaaaaa22", "aaaaaaaaaaaaaaaa23", "aaaaaaaaaaaaaaaa24", "aaaaaaaaaaaaaaaa25", "aaaaaaaaaaaaaaaa26", "aaaaaaaaaaaaaaaa27", "aaaaaaaaaaaaaaaa28", "aaaaaaaaaaaaaaaa29", "aaaaaaaaaaaaaaaa30", "aaaaaaaaaaaaaaaa31", "aaaaaaaaaaaaaaaa32", "aaaaaaaaaaaaaaaa33", "aaaaaaaaaaaaaaaa34", "aaaaaaaaaaaaaaaa35", "aaaaaaaaaaaaaaaa36", "aaaaaaaaaaaaaaaa37", "aaaaaaaaaaaaaaaa38", "aaaaaaaaaaaaaaaa39", "aaaaaaaaaaaaaaaa40", "aaaaaaaaaaaaaaaa41", "aaaaaaaaaaaaaaaa42", "aaaaaaaaaaaaaaaa43", "aaaaaaaaaaaaaaaa44", "aaaaaaaaaaaaaaaa45", "aaaaaaaaaaaaaaaa46", "aaaaaaaaaaaaaaaa47", "aaaaaaaaaaaaaaaa48", "aaaaaaaaaaaaaaaa49", "aaaaaaaaaaaaaaaa50", "aaaaaaaaaaaaaaaa51", "aaaaaaaaaaaaaaaa52", "aaaaaaaaaaaaaaaa53", "aaaaaaaaaaaaaaaa54", "aaaaaaaaaaaaaaaa55", "aaaaaaaaaaaaaaaa56", "aaaaaaaaaaaaaaaa57", "aaaaaaaaaaaaaaaa58", "aaaaaaaaaaaaaaaa59", "aaaaaaaaaaaaaaaa60", "aaaaaaaaaaaaaaaa61", "aaaaaaaaaaaaaaaa62", "aaaaaaaaaaaaaaaa63", "aaaaaaaaaaaaaaaa64", "aaaaaaaaaaaaaaaa65", "aaaaaaaaaaaaaaaa66", "aaaaaaaaaaaaaaaa67", "aaaaaaaaaaaaaaaa68", "aaaaaaaaaaaaaaaa69", "aaaaaaaaaaaaaaaa70", "aaaaaaaaaaaaaaaa71", "aaaaaaaaaaaaaaaa72", "aaaaaaaaaaaaaaaa73", "aaaaaaaaaaaaaaaa74", "aaaaaaaaaaaaaaaa75", "aaaaaaaaaaaaaaaa76", "aaaaaaaaaaaaaaaa77", "aaaaaaaaaaaaaaaa78", "aaaaaaaaaaaaaaaa79", "aaaaaaaaaaaaaaaa80", "aaaaaaaaaaaaaaaa81", "aaaaaaaaaaaaaaaa82", "aaaaaaaaaaaaaaaa83", "aaaaaaaaaaaaaaaa84", "aaaaaaaaaaaaaaaa85", "aaaaaaaaaaaaaaaa86", "aaaaaaaaaaaaaaaa87", "aaaaaaaaaaaaaaaa88", "aaaaaaaaaaaaaaaa89", "aaaaaaaaaaaaaaaa90", "aaaaaaaaaaaaaaaa91", "aaaaaaaaaaaaaaaa92", "aaaaaaaaaaaaaaaa93", "aaaaaaaaaaaaaaaa94", "aaaaaaaaaaaaaaaa95", "aaaaaaaaaaaaaaaa96", "aaaaaaaaaaaaaaaa97", "aaaaaaaaaaaaaaaa98", "aaaaaaaaaaaaaaaa99", "aaaaaaaaaaaaaaaa100" };
for ( int i = 1; i <= 100; i++ ) {
comboBox.addItem( output[i] );
}
}
// Column1.setCellEditor(new DefaultCellEditor(comboBox));
Column1.setCellEditor( new MyComboBoxEditor(comboBox) );
// Column1.setCellRenderer(new DefaultTableCellRenderer());
Column1.setCellRenderer( comboBox );
table.repaint();
table.revalidate();
}
public static void main(String[] args) {
new ErrorDemo();
}
}
class MyComboBoxRenderer extends JComboBox implements TableCellRenderer {
// public MyComboBoxRenderer(String[] items) {
public MyComboBoxRenderer() {
// super(items);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setSelectedItem(value);
return this;
}
}
class MyComboBoxEditor extends DefaultCellEditor {
// public MyComboBoxEditor(String[] items) {
public MyComboBoxEditor( JComboBox items ) {
// public MyComboBoxEditor( MyComboBoxRenderer items ) {
// super(new JComboBox(items));
super( items );
}
}
With the new code and DB = true, the field is overwritten when it is finished loading. I can see it start off as "aaaaaaaaaaaaaaaa2" then when the drop down button appears it changes to "aaaaaaaaaaaaaaaa1". If I change the value of one and then click in another box and another then those boxes are now the same as the first.
With the new code and DB = false, the initail value stays the same but when I change one field and click into another it is overwritten.