• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1282
  • Last Modified:

Java GUI with repaint problems... should be simple.

ok, I am running into a very stupid problem, and most likely because I am a bit rusty with Java.

I have two forms, both designed in NetBeans...

first one have a JList and a combo box. the combo box, on properties change, triggers a method call, which then would go to a ODBC connector, asking for information and add those information to the JList box.

i have another button on this form, basically, it is an edit button, which allows me to select items from the JList box and edit them.

Due to the complexity, the edit button pops up a new Jframe, with its own input boxes. At the end of the day, there is a 'DONE" button on this new JFrame, and when pushed, it updates the Database via ODBC.

Now the problem arises, for some strange reasons, I cannot update the jList box on my first form.

I have passed the frame along and called it localCopyMainWindow
and i've called it to repaint(), I've even attempted to call the method.

(A side note, if I leave an JOptionPane.showMessageBox in the method, it works nicely, just an annoying popup)

any thoughts?
0
SamsonChung
Asked:
SamsonChung
  • 15
  • 13
1 Solution
 
CEHJCommented:
You need to update gui components on the EDT. Use the well-documented SwingWorker
0
 
SamsonChungAuthor Commented:
Ok, I am a bit confused...

that's an underlying thread right?

so it is a Thread that updates the SWING?

So I can't force an update like I was doing?
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
SamsonChungAuthor Commented:
Oh, as a side note, I didn't need it to be 'multithreaded' yet.

I am just wondering if I am forgetting something, to update the JList object.

it is just some strange reasons that the GUI portion would not 'refresh'
0
 
CEHJCommented:
>>Oh, as a side note, I didn't need it to be 'multithreaded' yet.

You do i'm afraid, or it almost certainly won't work properly

The odbc bit should be done on the worker thread and one of its methods would do the gui update
0
 
SamsonChungAuthor Commented:
i see..

So Java's GUI side is better done with underlying threads then actual Events triggers.

While Events are good, for data manipulation, would you suggest that all semi-automatic tasks be done via background threads?
0
 
CEHJCommented:
>>While Events are good, for data manipulation,

Actually they're mainly good for visual stuff.


>>would you suggest that all semi-automatic tasks be done via background threads?

Processing, particularly intensive processing, should be done in background threads. This means they should never be done *directly* in event handlers - you would start the background thread there only
0
 
SamsonChungAuthor Commented:
Ok, CEHJ

I have tried this...

Added a thread, the thread goes in and do the SQL db stuff, then it is paused.
When the second form is disposed, it re-activate the thread with a 120 millisec delay.

There is no change. the main window did not get refresh, nor did the JList got refreshed.
0
 
CEHJCommented:
OK. Please post your new SwingWorker code and i'll see what we can do
0
 
SamsonChungAuthor Commented:
Its not 'swingworker' per se...

 I just went with an normal Thread.....

if you suggest that I should construct a SwingWorker, I'll attempt that.


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
 
package webctcrosslister;
 
import java.sql.Connection;
 
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import webctcrosslister.gui.MainWindow;
 
/**
 *
 * @author Samson Chung
 */
public class mwListUpdateThread extends Thread {
 
	public mwListUpdateThread(MainWindow aThis){
		this.localCopyMW = aThis;
		this.killSwitch = true;
		this.active = true;
		this.sleepMillis = 0;
	}
 
	@Override
	public void run(){
		while (killSwitch){
			while (active){
				try {
					this.sleep(this.sleepMillis);
				} catch (InterruptedException ex) {
					Logger.getLogger(mwListUpdateThread.class.getName()).log(Level.SEVERE, null, ex);
				}
				String selectedTerm = this.localCopyMW.getSelectedItem();
				try{
					Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
					Connection c = DriverManager.getConnection( "jdbc:odbc:webctCrosslister", "", "" );
					Statement stmnt = c.createStatement();
					String query = "SELECT * FROM CrossedCourses WHERE Term = '" + selectedTerm + "';";
					//JOptionPane.showMessageDialog(this, query);
					ResultSet rs = stmnt.executeQuery( query );
					Vector test1 = new Vector();
					while( rs.next() ){
						String temp =  rs.getString("xlistCode")  + "  [" + rs.getString("Results") + "]  " + rs.getString("CourseName");
						test1.add(temp);
					}
					//String tempArray[] = (String[]) test1.toArray();
					this.localCopyMW.setLstDisplay(test1);
 
					c.close();
					//rs.close();
					stmnt.close();
				}catch(Exception e){
					e.printStackTrace();
				}
				this.localCopyMW.repaint();
				this.active = false;
				this.sleepMillis = 0;
			}
		}
	}
	
	/***************************************************************************
	 * input Secs, method will times it by 60
	 * 
	 **************************************************************************/
	public void setSleepMillis(int sec){
		this.sleepMillis = sec * 60;
	}
 
	public void setEnabled(boolean in){
		this.active = in;
	}
	public void endThread(){
		this.active = false;
		this.killSwitch = false;
	}
 
	private MainWindow localCopyMW;
	private boolean active;
	private boolean killSwitch;
	private int sleepMillis;
}

Open in new window

0
 
CEHJCommented:
>>this.localCopyMW.setLstDisplay(test1);

I assume that's you updating the gui? If so, you're updating it on the wrong thread. That's why it's better to use a SwingWorker ;-)
0
 
SamsonChungAuthor Commented:
o_O??

localCopyMW.setLstDisplay(Vector vect); is a method in MainWindow Class.....

0
 
CEHJCommented:
>>is a method in MainWindow Class.....

...which does this?:

>>Now the problem arises, for some strange reasons, I cannot update the jList box on my first form.
0
 
SamsonChungAuthor Commented:
yep.

the method then goes in and say

this.jListbox.setDataList(test1);
0
 
SamsonChungAuthor Commented:
er, I meant setListData...
0
 
CEHJCommented:
That's why i said:

>>I assume that's you updating the gui?

- because that's what you/re doing. You need to update the gui on the EDT. SwingWorker is specifically designed to make that easier and to coordinate threads
0
 
SamsonChungAuthor Commented:
Ok,

I'll give SwingWorker a quick try....

0
 
CEHJCommented:
If you wanted to do it in the code you've got you could call EventQueue.invokeLater, but that's messier
0
 
SamsonChungAuthor Commented:
Ok,

Now I've recoded the thread class in SwingWorker.

do I have to create a new one everyone I want to 'execute()' it?
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
 
package webctcrosslister;
 
import java.sql.Connection;
 
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Vector;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingWorker;
import webctcrosslister.gui.MainWindow;
 
/**
 *
 * @author Samson Chung
 */
public class mwListUpdateThread extends SwingWorker<Vector, Integer> {
 
	public mwListUpdateThread(MainWindow aThis){
		this.localCopyMW = aThis;
		this.killSwitch = true;
		this.active = true;
		this.sleepMillis = 0;
	}
 
	@Override
	public Vector doInBackground(){
		String selectedTerm = this.localCopyMW.getSelectedItem();
		Vector test1 = new Vector();
		try{
			Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );
			Connection c = DriverManager.getConnection( "jdbc:odbc:webctCrosslister", "", "" );
			Statement stmnt = c.createStatement();
			String query = "SELECT * FROM CrossedCourses WHERE Term = '" + selectedTerm + "';";
			//JOptionPane.showMessageDialog(this, query);
			ResultSet rs = stmnt.executeQuery( query );
 
			while( rs.next() ){
				String temp =  rs.getString("xlistCode")  + "  [" + rs.getString("Results") + "]  " + rs.getString("CourseName");
				test1.add(temp);
			}
			c.close();
			//rs.close();
			stmnt.close();
		}catch(Exception e){
			e.printStackTrace();
		}
		return test1;
	}
		
	@Override
	public void done(){
		try {
			this.localCopyMW.setLstDisplay(get());
		} catch (InterruptedException ex) {
			Logger.getLogger(mwListUpdateThread.class.getName()).log(Level.SEVERE, null, ex);
		} catch (ExecutionException ex) {
			Logger.getLogger(mwListUpdateThread.class.getName()).log(Level.SEVERE, null, ex);
		}
	}
 
	private MainWindow localCopyMW;
	private boolean active;
	private boolean killSwitch;
	private int sleepMillis;
}

Open in new window

0
 
CEHJCommented:
That looks good. Yes, create a new one every time you want to do an upate. Is it working?
0
 
SamsonChungAuthor Commented:
same problem.

When the second form is disposed, it calls the first form's method which launches the SwingWorker thread..

but no change whatsoever on the gui side.
0
 
SamsonChungAuthor Commented:
Here is a snippet from MainWindow class....

I got a feeling i am doing something REALLY Stupid ;)

(* A small note, if i were to generate a POP up box, it will actually refresh the GUI)
public class MainWindow extends javax.swing.JFrame {
 
    /** Creates new form MainWindow */
    public MainWindow() {
        initComponents();
		this.updateForm();
    }
 
	public String getSelectedItem() {
		return this.cmbTerm.getSelectedItem().toString();
	}
 
	public void setLstDisplay(Vector test1) {
		this.lstDisplay.setListData(test1);
	}
	public void updateForm() {
		(new mwListUpdateThread(this)).execute();
	}

Open in new window

0
 
CEHJCommented:
You should be setting a new ListModel on the List with that Vector - is that what you're doing?
0
 
CEHJCommented:
IOW, what does this do:

>>setListData(test1);

and is it getting called?
0
 
SamsonChungAuthor Commented:
For some strange reasons, the Data is not updated.

Vector test1's data is old data.

Would that have something to do with JDBC connector to ODBC being 'not fast enough' ?

ie, I just did an update before doing this select, on the same table. Should I give it some time for the DATA to be updated?
0
 
SamsonChungAuthor Commented:
Thanks,

 I found out why..

I forgot to close the Query driver..... of course the Data will be updated, only after the method have completely finished and resources released.

However, since we are already doing a secondary Select, it never got the updated information.

HAHAHAHAHA <- Went insane....
0
 
CEHJCommented:
OK. :-)
0
 
SamsonChungAuthor Commented:
stupid cursors!!!!
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 15
  • 13
Tackle projects and never again get stuck behind a technical roadblock.
Join Now