Update JTable in SwingWorker - java

I have a JTable which populates data from DB. I want to refresh data in JTable every 10 minutes (for testing 10 sec is enough). I tried do it with a Thread, but I found that it is not good idea, and I need to use SwingWorker
public class Monitor extends JFrame{
JTable jtable = null;
JTabbedPane jtp = null;
JPanel jp1 = null;
JPanel jp2 = null;
JLabel label1 = null;
JLabel label2 = null;
public void setJTable(Vector data, Vector columnNames) {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jtable = new JTable(data, columnNames);
JScrollPane scrollPane = new JScrollPane(jtable);
jp1.add(scrollPane);
}
public void updateJTable(Vector data, Vector columnNames) {
jtable = new JTable(data, columnNames);
}
public Monitor() {
setTitle("Monitor System");
//Panel with tabs for navigation
jtp = new JTabbedPane();
getContentPane().add(jtp);
//tab1, info from dba_jobs
jp1 = new JPanel();
//tab2 info from QueueInfo
jp2 = new JPanel();
label1 = new JLabel();
label1.setText("tab1");
label2 = new JLabel();
label2.setText("tab2");
jp1.add(label1);
jp2.add(label2);
jtp.add("Tab1", jp1);
jtp.add("Tab2", jp2);
}
}
And my Demo class:
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Statement stmt = null;
Connection conn = null;
ResultSet rs = null;
Vector<String> columnNames = new Vector<String>();
Vector<Vector> rowData = new Vector<Vector>();
DBMonitor dbmonitor = new DBMonitor();
Monitor monitor = new Monitor();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
rowData = dbmonitor.getJobsData();
columnNames = dbmonitor.getColumnNames();
monitor.setJTable(rowData, columnNames);
monitor.setSize((int) dim.getWidth(), (int) dim.getHeight());
monitor.setVisible(true);
boolean interrupt = true;
while (interrupt) {
try {
rowData = dbmonitor.getJobsData();
columnNames = dbmonitor.getColumnNames();
monitor.updateJTable(rowData, columnNames);
try {
Thread.sleep(10000);
} catch (InterruptedException ie) {
return;
}
JOptionPane.showMessageDialog(null, "SLEEP!");
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage());
System.err.println(e.getMessage());
}
}
}
}
How I can do it with SwingWorker? I don't get a concept of that way.

In the doInBackground() method of the SwingWorker you have you while loop that:
retrieves the data from the database
creates your TableModel
use the publish() method of the SwingWorker to pass the TableModel to the 'process()` method of your SwingWorker
sleeps for 10 seconds
Then in the process() method of the SwingWorker you:
use the TableModel that was passed to the process() method to update your JTable.
Read the section from the Swing tutorial on Concurrency for more information and a working example or search the forum for more SwingWorker examples.

First, I would start with a Timer of some sort, I'm going to use a Swing Timer as it easy, but you could use a java.util.Timer instead...
private Timer updateTimer;
//...
updateTimer = new Time(10000, new ActionListener() {
public void actionListener(ActionEvent e) {
}
});
updateTimer.setRepeats(false);
updateTimer.start();
This allows you to be notified in about 10 seconds time...
Then you need a SwingWorker that can do the actual work...
public class UpdateWorker extends SwingWorker<TableModel, Void> {
private Monitor monitor;
private Timer updateTimer;
public UpdateWorker(Monitor monitor, Timer updateTimer) {
this.monitor = monitor;
this.updateTimer = updateTimer;
}
#Override
protected TableModel doInBackground() throws Exception {
Vector<Vector> rowData = dbmonitor.getJobsData();
Vector columnNames = dbmonitor.getColumnNames();
DefaultTableModel model = new DefaultTableModel(rowData, columnNames);
return model;
}
#Override
protected void done() {
try {
TableModel model = get();
monitor.updateTable(model);
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
updateTimer.restart();
}
}
Now in the actionPerformed method of the ActionListener assigned to the timer, you would do something like..
public void actionListener(ActionEvent e) {
UpdateWorker worker = new UpdateWorker(monitor, this);
worker.execute();
}
To execute the worker. The reason for having a non-repeating timer is to ensure that the next update is set for n seconds from when the update completes, so you don't get overlapping updates
Oh, and this will require to update your Monitor to accept a TableModel rather then the Vectors you are using to create one, it's just simpler that way...

Related

JTable (BeanTableModel) not updating/refreshing - Java Swing

I've 2 panels. One where the user inserts the data and the other with a JTable where the results will be shown.
My problem is when the user press's the ok (in my case apply) JButton the data is computed but is not shown on the JTable, nothing changes in the JTable.
For my JTable I'm using the Bean Table Model from tips4Java (http://tips4java.wordpress.com/2008/11/27/bean-table-model/).
One weird thing is if I send data (lets call this data 'A') to the table when the program starts it is shown on the table and if later on I try to update the table, the table does not update. But when I don't send data to the table at start up but try to update/send the table with data 'A' it does not update.
So my question is, why is not the JTable showing whatever data I send to?
Here's my code:
JButton listenere that starts the processing and sends the data to the table:
crashForm.setFormListener(new FormListener() {
#Override
public void formEvent(OptionsFormEvent oe) {
String readTable = oe.getReadFromTable();
int access = oe.getAccess();
int transition = oe.getTransition();
boolean smooth = oe.isTrainCrash();
ArrayList<String> allTrains = new ArrayList<>();
List crashedTrainList = new ArrayList<>();
try {
allTrains = controller.getUniqueTrains(controller.connectServer(), readTable, "trainid");
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "An error occured while getting trains data\n"
+ "Error description: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
try {
for (int i = 0; i < allTrains.size(); i++)
{
ArrayList<Train> trainDataList = new ArrayList<>();
ArrayList<Train> crashedProccessedData = new ArrayList<>();
String query = "the sql query...";
trainDataList = controller.getTrainData(controller.connectServer(), readTable, query);
crashedProccessedData = controller.detectCrash(access, transition, trainDataList);
crashedTrainList.addAll(crashedProccessedData);
}
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "An error occured while detecting a crash.\n"
+ "Error description: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
System.out.println("Total crashes detected:" + crashedTrainList.size());
tablePanel.createTable(Train.class, crashedTrainList, true, false, tableLabels);
tablePanel.fireTableDataChanged();
}
});
}
And here's my tablePanel class:
public TablePanel() {
}
public void createTable(Class c, List data, boolean toolBarUp,
boolean toolBarBottom, ArrayList<String> labelsCheckBox) {
beanTableModel = new BeanTableModel(c, data);
columnModel = new XTableColumnModel();
table = new JTable(beanTableModel);
table.setColumnModel(columnModel);
table.createDefaultColumnsFromModel();
if(toolBarUp == true)
{
final JToolBar toolBarTop = new JToolBar();
// Create the Show ALL
JButton reset = new JButton("Reset");
reset.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for(Component c : toolBarTop.getComponents()){
if(c instanceof JCheckBox){
JCheckBox checkBox = (JCheckBox) c;
checkBox.setSelected(false);
columnModel.setAllColumnsVisible();
}
}
int numberOfColumn = columnModel.getColumnCount();
for(int aux = 0; aux < numberOfColumn; aux++)
{
int num = columnModel.getColumnCount();
TableColumn column = columnModel.getColumnByModelIndex(aux);
columnModel.setColumnVisible(column, true);
}
}
});
toolBarTop.add(reset);
// Create a JCheckBox for each column
for(int i = 0; i < labelsCheckBox.size(); i++)
{
final int index = i;
toolBarTop.add(new JCheckBox(new AbstractAction(labelsCheckBox.get(i)) {
#Override
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(index);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
}
setLayout(new BorderLayout());
add(toolBarTop, BorderLayout.NORTH);
add(new JScrollPane(table), BorderLayout.CENTER);
// add(toolBarDown, BorderLayout.SOUTH);
}
final JToolBar toolBarDown = new JToolBar();
toolBarDown.add(new JButton(new AbstractAction("Save Table") {
#Override
public void actionPerformed(ActionEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
}));
}
public void createTable(Class c, Class cAncestor) {
beanTableModel = new BeanTableModel(c, cAncestor);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
}
public void createTable(Class c, Class cAncestor, List data) {
beanTableModel = new BeanTableModel(c, cAncestor, data);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
beanTableModel.fireTableDataChanged();
}
public void createTable(Class c) {
beanTableModel = new BeanTableModel(c);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
}
public void createTable(Class c, List data)
{
beanTableModel = new BeanTableModel(c, data);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
}
//to refresh the table everytime there is an update
public void fireTableDataChanged()
{
beanTableModel.fireTableDataChanged();
}
So again, my question is: Isn't my JTable not updated with the new results every time I send new data to it?
You should never invoke fireTableDataChanged manually. Only the TableModel is responsible for invoking this event.
From your code it looks like you are creating a new TableModel, JTable and JScrollPane every time you make a change. Any time you add a component to a visible GUI the basic code should be:
panel.add(....);
panel.revalidate();
panel.repaint();
By default all components have a size of zero so since you don't invoke revalidate() then never get a proper size and there is nothing to paint. Also, it is never a good idea to simply keep adding components to the CENTER of your panel since the old component are still part of the container.
However, there is a better solution. There is no need to keep creating new components. All you need to do is create an new TableModel and then use:
table.setModel( newlyCreatedModel );
and the model will be added to the table and the table will repaint itself automatically.

How do I fill data in a JTable?

I am trying to update my table, but it is not working. The table does not show up until the entire program calling it is done. How can I change this? Upon opening the window, I would like to fill the JTable with data. If I stop the execution of the code, the table is filled with data. Do I need a thread? How would I use one correctly? My code is below.
public class TestGUI extends DefaultTableCellRenderer implements TeststepEventListener {
public JFrame frame;
private JTable testcase_table;
private JTable teststep_table;
/**
* Create the application.
*/
public TestGUI() {
initialize();
frame.setVisible(true);
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JProgressBar progressBar = new JProgressBar();
progressBar.setBounds(50, 68, 700, 14);
frame.getContentPane().add(progressBar);
JTextPane txtpnAutomotiveHmi = new JTextPane();
txtpnAutomotiveHmi.setText("Automotive HMI");
txtpnAutomotiveHmi.setBounds(362, 21, 205, 20);
frame.getContentPane().add(txtpnAutomotiveHmi);
testcase_table = new JTable();
testcase_table.setBounds(50, 125, 350, 426);
frame.getContentPane().add(testcase_table);
teststep_table = new JTable();
teststep_table.setBounds(399, 125, 350, 426);
frame.getContentPane().add(teststep_table);
}
private boolean testcase = true;
#Override
public void myEventOccurred(TeststepEvent event) {
TeststepData data = event.data();
if (testcase) {
set_values(data.getDoc(), data.getTestcase());
}
testcase = false;
}
private int i = 0;
LinkedList names = new LinkedList();
private void set_values(Document doc, int testcase) {
frame.setTitle("Wuratbrot" + i);
i++;
Element element = doc.getRootElement();
names.clear();
if (element != null) {
List<Element> testCases = element.getChildren();
//testcase_table.removeAll();
//String[] title = {"Testcases"};
for (Element testCase : testCases) {
names.add(testCase.getAttributeValue("name"));
}
DisplayData(names);
}
testcase_table.revalidate();
frame.validate();
}
private void DisplayData(List<String> Testcases) {
DefaultTableModel aModel = new DefaultTableModel() {
//setting the jtable read only
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
//setting the column name
Object[] tableColumnNames = new Object[1];
tableColumnNames[0] = "TestCases";
aModel.setColumnIdentifiers(tableColumnNames);
if (Testcases == null) {
testcase_table.setModel(aModel);
return;
}
Object[] objects = new Object[1];
ListIterator<String> lstrg = Testcases.listIterator();
//populating the tablemodel
while (lstrg.hasNext()) {
String newcus = lstrg.next();
objects[0] = newcus;
aModel.addRow(objects);
}
//binding the jtable to the model
testcase_table.setModel(aModel);
}
}
SwingWorker is intended for this. Data acquisition can take place asynchronously in doInBackground(), while process() safely updates the TableModel on the event dispatch thread via publish(). In particular, see the section entitled Sample Usage and this tutorial. Moreover, DefaultTableModel fires the appropriate update events for which the JTable listens. No additional code should be required. As an aside, use layouts rather than setBounds().
You need the function fireTableDataChanged. You should call it upon your table model after changing the values of table cells.

JComboBox show value

Need help with JComboBox component. I've load data from MySQL database and write this data into combo. I use four combo boxes with ItemListener. When one combo box change all children combo boxes reload data from database. First and two works fine but third and four don't show value normal, but good value is there. Only I don't show it. When I select empty field in combo box after then I see good result.
Source code:
public class Vyhladat extends Okno {
private static final long serialVersionUID = 1L;
JComboBox nominalBOX,statBOX,podpisBOX,tlacDoskaBOX;
Font sherif = new Font("Sherif",Font.BOLD,20);
Font normal = new Font("Sherif",Font.PLAIN,20);
JFrame uh = new JFrame();
private String adresa="jdbc:mysql://localhost:3306/jarodb";
private String meno="JKARAK";
private String heslo="bankovka";
String nominal,stat,podpis,tlacDoska,statH;
private String nominalSQL = "SELECT DISTINCT(nominal) FROM prehlad";
private String statSQL = "SELECT DISTINCT(concat(stat,'/',seria)) FROM prehlad WHERE nominal=? ORDER BY stat";
private String podpisSQL = "SELECT DISTINCT(podpis) FROM prehlad WHERE nominal=? AND stat=? ";
private String tlacDoskaSQL = "SELECT DISTINCT(doska) FROM prehlad WHERE nominal=? AND stat=? AND podpis=? ";
Vector nominalV=new Vector();
Vector statV=new Vector();
Vector podpisV=new Vector();
Vector tlacDoskaV=new Vector();
Vyhladat()
{
vlozPopis(nominalLAB,"NOMIN\u00C1L EUROBANKOVKY: ",0,0,sherif);
vlozPopis(statLAB,"\u0160T\u00C1T/S\u00C9RIA:",0,1,sherif);
vlozPopis(podpisLAB,"PODPIS:",0,2,sherif);
vlozPopis(tlacDoskaLAB,"TLA\u010COV\u00C1 DOSKA:",0,3,sherif);
gbc.gridx=1;
gbc.gridy=0;
nacitajVyber(nominalSQL,nominalBOX,nominalV,false,false,false);
nominalBOX = new JComboBox(nominalV);
nominalBOX.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
nominal = (String)nominalBOX.getSelectedItem();
if(nominal!=" ")
{
nacitajVyber(statSQL,statBOX,statV,true,false,false);
}
else{
statBOX.removeAllItems();
podpisBOX.removeAllItems();
tlacDoskaBOX.removeAllItems();
}
}
});
nominalBOX.setPrototypeDisplayValue("500");
nominalBOX.setFont(normal);
nominalBOX.setSelectedIndex(0);
nominalBOX.setToolTipText("Vyber z mo\u017Enost\u00ED nomin\u00E1lu bankoviek 5,10,20,50.");
add(nominalBOX,gbc);
gbc.gridx=1;
gbc.gridy=1;
statV.add(" ");
statBOX= new JComboBox(statV);
statBOX.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
stat = (String)statBOX.getSelectedItem();
if(stat!=null)
{
String [] statM= stat.split("/");
statH = statM[0];
}
if(stat!=" " & stat!=null)
{
nacitajVyber(podpisSQL,podpisBOX,podpisV,false,true,false);
}
else{
podpisBOX.removeAllItems();
tlacDoskaBOX.removeAllItems();
}
}
});
statBOX.setPrototypeDisplayValue("Portugalsko/E");
statBOX.setFont(normal);
statBOX.setSelectedIndex(0);
statBOX.setToolTipText("Vyber z mo\u017Enost\u00ED \u0161t\u00E1t/s\u00E9riu.");
add(statBOX,gbc);
gbc.gridx=1;
gbc.gridy=2;
podpisV.add(" ");
podpisBOX = new JComboBox(podpisV);
podpisBOX.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
podpis = (String)podpisBOX.getSelectedItem();
if(podpis!=" " & podpis!=null)
{
nacitajVyber(tlacDoskaSQL,tlacDoskaBOX,tlacDoskaV,false,false,true);
}
else{
tlacDoskaBOX.removeAllItems();
}
}
});
podpisBOX.setPrototypeDisplayValue("Jean-Claude Trichet ");
podpisBOX.setFont(normal);
podpisBOX.setSelectedIndex(0);
podpisBOX.setToolTipText("Vyber z mo\u017Enost\u00ED troch podpisov.");
add(podpisBOX,gbc);
gbc.gridx=1;
gbc.gridy=3;
tlacDoskaV.add(" ");
tlacDoskaBOX = new JComboBox(tlacDoskaV);
tlacDoskaBOX.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
tlacDoska = (String)tlacDoskaBOX.getSelectedItem();
if((nominal!=" " & nominal!=null) & (statH!=" " & statH!=null) & (podpis!=" " & podpis!=null) & (tlacDoska!=" " & tlacDoska!=null))
{
zobraz.setEnabled(true);
}
}
});
tlacDoskaBOX.setPrototypeDisplayValue("E010");
tlacDoskaBOX.setFont(normal);
tlacDoskaBOX.setSelectedIndex(0);
tlacDoskaBOX.setToolTipText("Vyber z mo\u017Enost\u00ED tla\u010Dov\u00FDch dosiek.");
add(tlacDoskaBOX,gbc);
}
private void nacitajVyber(String sqlDotaz, JComboBox chr,Vector v,
boolean jedna,boolean dva, boolean tri)
{
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(adresa,meno,heslo);
PreparedStatement stmt = conn.prepareStatement(sqlDotaz);
if(jedna==true)
{
chr.removeAllItems();
stmt.setString(1, nominal);
}
if(dva==true)
{
chr.removeAllItems();
stmt.setString(1, nominal);
stmt.setString(2, statH);
}
if(tri==true)
{
chr.removeAllItems();
stmt.setString(1, nominal);
stmt.setString(2, statH);
stmt.setString(3, podpis);
}
ResultSet rs = stmt.executeQuery();
v.addElement(" ");
while (rs.next())
{v.addElement(rs.getString(1).trim());
System.out.println(rs.getString(1));}
validate();
rs.close();
stmt.close();
conn.close();
}
catch(Exception e){
JOptionPane.showMessageDialog(uh,e.toString(),
"Chyba pripojenia",
JOptionPane.ERROR_MESSAGE);
}
}
}
JComboBox doesn't know somehow then underlaying Vector is changed, have to reinitialize this array for JComboBox on the fly, but this is wrong way,
for any changes on the runtime to use XxxComboBoxModel for storing Items for JComboBox
for JDBC or FileIO there could be Concurency issue, Swing JComponents required to all updates (in this case JComboBox and its XxxComboBoxModel) must be done on EDT
invoke Database event from the Runnable#Thread or SwingWorker, redirect this (potentionally) hard and long running task to the Workers Thread, otherwise Swing GUi will be freeze or unresponsive (for mouse and key events) untill JDBC ended
SwingWorkers methods publish(), process() and done() quite good quaranteed that all output wil be done on EDT
for example
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class ComboBoxTwo extends JFrame implements ActionListener, ItemListener {
private static final long serialVersionUID = 1L;
private JComboBox mainComboBox;
private JComboBox subComboBox;
private Hashtable<Object, Object> subItems = new Hashtable<Object, Object>();
public ComboBoxTwo() {
String[] items = {"Select Item", "Color", "Shape", "Fruit"};
mainComboBox = new JComboBox(items);
mainComboBox.addActionListener(this);
mainComboBox.addItemListener(this);
//prevent action events from being fired when the up/down arrow keys are used
//mainComboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
getContentPane().add(mainComboBox, BorderLayout.WEST);
subComboBox = new JComboBox();// Create sub combo box with multiple models
subComboBox.setPrototypeDisplayValue("XXXXXXXXXX"); // JDK1.4
subComboBox.addItemListener(this);
getContentPane().add(subComboBox, BorderLayout.EAST);
String[] subItems1 = {"Select Color", "Red", "Blue", "Green"};
subItems.put(items[1], subItems1);
String[] subItems2 = {"Select Shape", "Circle", "Square", "Triangle"};
subItems.put(items[2], subItems2);
String[] subItems3 = {"Select Fruit", "Apple", "Orange", "Banana"};
subItems.put(items[3], subItems3);
// mainComboBox.setSelectedIndex(1);
}
#Override
public void actionPerformed(ActionEvent e) {
String item = (String) mainComboBox.getSelectedItem();
Object o = subItems.get(item);
if (o == null) {
subComboBox.setModel(new DefaultComboBoxModel());
} else {
subComboBox.setModel(new DefaultComboBoxModel((String[]) o));
}
}
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
if (e.getSource() == mainComboBox) {
if (mainComboBox.getSelectedIndex() != 0) {
FirstDialog firstDialog = new FirstDialog(ComboBoxTwo.this,
mainComboBox.getSelectedItem().toString(), "Please wait, Searching for ..... ");
}
}
}
}
private class FirstDialog extends JDialog { //sipmle simulation of JDBC events, by using Swing Timer
private static final long serialVersionUID = 1L;
FirstDialog(final Frame parent, String winTitle, String msgString) {
super(parent, winTitle);
setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
JLabel myLabel = new JLabel(msgString);
JButton bNext = new JButton("Stop Processes");
add(myLabel, BorderLayout.CENTER);
add(bNext, BorderLayout.SOUTH);
bNext.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
setVisible(false);
}
});
javax.swing.Timer t = new javax.swing.Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
t.setRepeats(false);
t.start();
setLocationRelativeTo(parent);
setSize(new Dimension(400, 100));
setVisible(true);
}
}
public static void main(String[] args) {
JFrame frame = new ComboBoxTwo();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
The GUI probably can't redraw properly. You are doing all of your hard work on the Event Dispatch Thread. This thread calls your itemStateChanged. But this thread is also responsible for redrawing the GUI. You are stopping it from doing that, because you are making it do your hard work in the database.
Instead, you can use a different thread to do your hard work.
public void itemStateChanged(ItemEvent e)
{
new Thread(new Runnable() {
public void run() {
.... your code...
}
}).start();
}
Or take a look at SwingWorker, which does this in a nicer way.
Also, itemStateChanged could be called twice for each selection - this might be causing you problems. Use "e.getStateChange()" to check what TYPE of event you just received. You should receive a selected and an unselected (from the old item).

Update JTable with Separate Thread

The purpose of the application is to query a table, and take that information and update a JTable. Right now the ThreadTask() is able to query the table and obtain the information. My question is how do I update the JTable GUI object with the information obtained from the database?
public class AdminManager extends JFrame {
public static void main(String[] args) throws InterruptedException {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
AdminManager frame = new AdminManager();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
// Setup connection pool
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(new ThreadTask(connection), 2000, 100, TimeUnit.MILLISECONDS);
}
/**
* Create the frame.
*/
public AdminManager() {
// Setup GUI
DefaultTableModel model = new DefaultTableModel();
model.addColumn("#");
tableQueue = new JTable(model);
tableQueue.getColumnModel().getColumn(0).setPreferredWidth(3);
scrollPane.setViewportView(tableQueue);
}
class updateTable extends SwingWorker<Void, String> {
#Override
protected Void doInBackground() throws Exception {
model.addRow(new Object[]{order_num});
return null;
}
}
}
class grabData implements Runnable {
private Connection connection;
private DefaultTableModel model;
private String order_num;
public grabData(Connection c, DefaultTableModel m) {
connection = c;
model = m;
}
#Override
public void run() {
System.out.println("Working ... ");
String sql = "SELECT * FROM order_queue;";
Statement st;
try {
st = connection.createStatement();
ResultSet rs = st.executeQuery(sql);
while(rs.next()) {
order_num = rs.getString("order_num");
System.out.println(order_num);
updateTable.execute()
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
If you are adding rows to a TableModel object that is held by a visualized JTable, then you must do so on the Swing event thread, the EDT. If you're creating a completely new TableModel one that isn't visualized, then I think it is safe to fill it off of the EDT, and then set it as the JTable's model on the EDT.
One consideration, if you want to add rows the JTable as they become available, consider using a SwingWorker<Void, RowObject>, and then pass the RowObject obtained in the while (rs.next()) { via a publish/process method pair.
Edit:
You could just skip the SwingWorker and just queue up adding the table's row on the EDT:
while(rs.next()) {
final String order_num = rs.getString("order_num");
// System.out.println(order_num);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
model.addRow(new Object[]{order_num});
}
});
}

how to set an image for jtable fixed column, when i am running, it's getting an image path only

I created a program to set an imageIcon in jtable fixed column, i created a jtable and getting a database records, then set a first column as fixed column. i set an image icon in fixed column. when i am compiling this program, i am getting only a path of the imageicon not getting an image. I fixed an imageIcon in project package folder.
This is the code i used
public void Frm_FlxD_Database() {
try{
TmpRow=0;
TmpMainPrj.PRJ_DB_CONNECTION_ASSGN();
TmpFlxMdl =(DefaultTableModel)FlxD.getModel();
TmpFlxDRow = 0;
TmpFlxSt=TmpGPrjVarDec.GContn.createStatement();
TmpFlxDRs=TmpFlxSt.executeQuery("SELECT * from activitymaster");
PRJ_FLX_DEFTL_ASSGN(FlxD, "BEGIN");
TmpFlxDRs.first();
do {
FlxD.setValueAt(TmpFlxDRs.getString("ACTVTYDESC"), TmpRow,1);
FlxD.setValueAt(TmpFlxDRs.getString("ACTVTYCODE"), TmpRow,2);
FlxD.setValueAt(TmpFlxDRs.getString("DISPSTATUS"), TmpRow,3);
FlxD.setValueAt(TmpFlxDRs.getString("ACTVTYID"), TmpRow,4);
TmpFlxMdl.addRow(new Object[]{""});
TmpRow = TmpRow + 1;
}while(TmpFlxDRs.next());
FRM_FLXD_PTR_DATA_ASSGN(TmpFlxDRow);
}
catch(Exception e){
System.out.println(e);
}
}
private void FRM_FLXD_PTR_DATA_ASSGN(int PFlxRow) {
TmpFlxDRow = PRJ_FLX_PTR_ASSGN(FlxD, PFlxRow, TmpFlxDRow);
}
private int PRJ_FLX_PTR_ASSGN(JTable PFlx, int PCurRow, int PPrvRow) {
ImageIcon TmpIcon;
System.out.println(PCurRow);
System.out.println(PPrvRow);
if (PCurRow != PPrvRow){
TmpIcon = new ImageIcon(getClass().getResource("Blank.gif"));
PFlx.setValueAt(TmpIcon,PPrvRow,0);
System.out.println(TmpIcon);
}
TmpIcon = new ImageIcon(getClass().getResource("Pointer.gif"));
PFlx.setValueAt(TmpIcon,PCurRow,0);
System.out.println(TmpIcon);
return(PCurRow);
}
JTable knows Icon/ImageIcon, simple example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.*;
import javax.swing.table.*;
public class TableIcon extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
private JTable table;
private JLabel myLabel = new JLabel("waiting");
private int pHeight = 40;
private boolean runProcess = true;
private int count = 0;
public TableIcon() {
ImageIcon errorIcon = (ImageIcon) UIManager.getIcon("OptionPane.errorIcon");
ImageIcon infoIcon = (ImageIcon) UIManager.getIcon("OptionPane.informationIcon");
ImageIcon warnIcon = (ImageIcon) UIManager.getIcon("OptionPane.warningIcon");
String[] columnNames = {"Picture", "Description"};
Object[][] data = {{errorIcon, "About"}, {infoIcon, "Add"}, {warnIcon, "Copy"},};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
table = new JTable(model) {
private static final long serialVersionUID = 1L;
// Returning the Class of each column will allow different
// renderers to be used based on Class
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
table.setRowHeight(pHeight);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
myLabel.setPreferredSize(new Dimension(200, pHeight));
myLabel.setHorizontalAlignment(SwingConstants.CENTER);
add(myLabel, BorderLayout.SOUTH);
EventQueue.invokeLater(new Runnable() {
public void run() {
}
});
new Thread(this).start();
}
public void run() {
while (runProcess) {
try {
Thread.sleep(750);
} catch (Exception e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ImageIcon myIcon = (ImageIcon) table.getModel().getValueAt(count, 0);
String lbl = "JTable Row at : " + count;
myLabel.setIcon(myIcon);
myLabel.setText(lbl);
count++;
if (count > 2) {
count = 0;
}
}
});
}
}
public static void main(String[] args) {
TableIcon frame = new TableIcon();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setLocation(150, 150);
frame.pack();
frame.setVisible(true);
}
}
You should not add an icon in your data model. You should add data (a boolean indicator, a String, whatever), and use a renderer for this column that will display the appropriate icon based on the data of the column.
See http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#editrender for information and examples about cell renderers.
And please, learn the Java naming conventions and stick to them. Your code is unreadable. See http://www.oracle.com/technetwork/java/codeconv-138413.html
Without getting to much into your code my guess is it has something to do with your tablemodel getColumnClass() method. There are plenty of tutorials how to fix that. Currently its probably rendered by tables defaultrenderer for object.
This thread should be helpful to you.
Good news is, you dont have to obfuscate your code, its already really hard to read and even harder to understand. You might want to read some java code guidelines to improve your code.

Categories