Java Thread problem - updating GUI - java

I'm trying to use threads to run a lenghty operation in the background and update the UI.
Here's what i'm trying to do:
on a button click, display a popupjframe with a message "Inserting into DB"
create a new thread to insert 1000s of entries into a database.
when the entries are inserted, i want the popupjframe to disappear and display a joptionpane with yes, no buttons
on clicking the yes button i want to display another frame with a report/details about the insertion process
Here's my code:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//display popupframe first
jFrame1.pack();
jFrame1.setVisible(true);
jFrame1.setLocationRelativeTo(getFrame());
Thread queryThread = new Thread() {
public void run() {
runQueries();
}};
queryThread.start();
}
//runqueries method inserts into DB
private void runQueries() {
for (int i = 0; i <= 50000; i++) {
insertintoDB();
updateProgress(i);
}
}
//update the popupjframe
private void updateProgress(final int queryNo) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (queryNo == 50000) { //means insertion is done
jFrame1.setVisible(false);
int n = JOptionPane.showConfirmDialog(getFrame(), menuBar, null, JOptionPane.YES_NO_OPTION);
if (n == 1) { //NO option was selected
return;}
else
//display another popupframe with details/report of inserting process
}});
}
Is my approach correct??
How and when do i stop/interrupt the "queryThread"??
Is it correct if i make the popupjframe in the runqueries method itself (after the for loop) and display the joptionpane??
Thanks in advance.

Look at the documentation for SwingWorker. It does exactly what you are trying to do. Create a subclass, and call runQueries from doInBackground(), and then do what your runnable does (minus the if queryNo check) in done(). There are third party versions of this class if you are not using java 1.6.
class DbSwingWorker extends SwingWorker<Void, Integer> {
#Override
protected Void doInBackground() throws Exception {
for (int i = 0; i <= 50000; i++) {
insertintoDB();
publish(i); //if you want to do some sort of progress update
}
return null;
}
#Override
protected void done() {
int n = JOptionPane.showConfirmDialog(getFrame(), menuBar, null, JOptionPane.YES_NO_OPTION);
if (n == 1) { //NO option was selected
return;
} else {
//display another popupframe with details/report of inserting process
}
}
}
The original, non-1.6 version can be found here: https://swingworker.dev.java.net/

Related

SwingUtilities.invokeLater does nothing

My requirement is to use addDocumentListener, the doSearchCmb basically narrows down items in combobox, function is working if keypressed is used. If I remove the function Runnable doSearchCmb and put the narrowing down of items in insertUpdate without using invokeLater, I get an error of 'Attempt to mutate notification' exception.
In my current code, my screen freezes after I type a letter. After waiting several minutes, I get the error of java.lang.OutOfMemoryError: Java heap space.
I tried to add return; after combo.repaint();, my screen didn't freeze, there's no java heap space error but nothing happened at all. I attached the code without the return.
What can I do here to remain the use of addDocumentListener and the function which narrows down the items of the combobox?
TCombo combo = new TCombo();
JTextComponent editor = (JTextComponent) combo.getEditor().getEditorComponent();
editor.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent arg0) {
}
public void insertUpdate(DocumentEvent arg0) {
searchCmb();
}
public void removeUpdate(DocumentEvent arg0) {
searchCmb();
}
private void searchCmb() {
Runnable doSearchCmb = new Runnable() {
#Override
public void run() {
String item = combo.getEditor().getItem().toString().trim();
boolean isEmpty = item.equals("");
CmbElement[] foundList = null;
String toFind = "";
List list = new ArrayList(0);
if (!isEmpty) {
combo.removeAllItems();
combo.setItems(elements);
for (int i = 1; i < elements.length; i++) {
if (elements[i].getName().contains(toFind)) {
if (i == 1) {
list.add("");
}
list.add(elements[i]);
}
foundList = (CmbElement[]) list.toArray(new CmbElement[list.size()]);
}
if (list.size() > 0) {
combo.removeAllItems();
combo.setItems(foundList);
} else {
combo.removeAllItems();
if (toFind.equals("")) {
combo.setItems(elements);
}
list.add(new DCmbElement("", ""));
foundList = (CmbElement[]) list.toArray(new CmbElement[list.size()]);
combo.setItems(foundList);
}
combo.repaint();
}
}
};
SwingUtilities.invokeLater(doSearchCmb);
}
});
CmbElement:
public abstract interface CmbElement {
public abstract String getKey();
public abstract String getName();
}
Note: Narrow down items in combo box means when user inputs a letter, or paste a word, the items in combo box gets filtered using the current letter or word as parameter. It searches through the items and narrows it down.
For reference the behavior is like the image here: jcombobox filter in java - Look and feel independent
My function indicated in run() is working fine if keypressed of keylistener is used, but my requirement is to use addDocumentListener

How do I change values in a continuous thread in java fx?

With the following code,the thread is activated on button click in the controller class. Thing is, I want to be able to change the values in he Line array, to have to anchor pane erase old lines and add new lines.This is in the controller.java after main in launched.
static startVal = -1,endVal = -1;
Lines L;//this is supposed to store new lines after some methods are called
//this method is called on button click and I want it to start again every time the button is clicked
public void drawPath(){
Task task = new Task<Void>() {
#Override
public Void call() throws Exception {
while(true){
int i = 0;
while (i<5) {
final int finalI = i;
Platform.runLater(new Runnable() {
#Override
public void run() {
anchPane.getChildren().add(L[finalI]);
if(startVal == -1)
startVal = anchPane.getChildren.size()-1;
else
endVal = anchPane.getChildren().size()-1;
}
});
i++;
Thread.sleep(2000);
}
//removeLines();
anchPane.getChildren().remove(startVal,endVal);
}
}
};
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
}

JPopupMenu doesn't disappear like it should

I have a Java application used to run tournaments in which I built an auto-suggestion feature that gets names from a database and displays them in a JPopupMenu. I haven't been able to replicate this bug on demand, but once in a while one of the JPopupMenus will disappear like normal with the exception that an outline of where it was is still on the screen and is displayed over everything including other programs even if my application is minimized.
Here is a screenshot of what I'm talking about:
You can see that underneath "Espinoza" some remnant of the JPopupMenu is still being displayed. This sometimes contains text inside and other times just has the background color only in an empty box. This remnant is purely cosmetic and I haven't found any way of interacting with it either physically or programatically (hot-coding).
Here is the method I'm using to display the JPopupMenu:
private void resetLastNamePopup() {
Thread t = new Thread() {
#Override
public void run() {
lnPopup.setVisible(false);
lnPopup.removeAll();
if(DBHSDatabaseIntermediary.isConnected()) {
if(!(fnTextField.getText().equals("") && lnTextField.getText().equals(""))) {
JMenuItem item = null;
String[] names = DBHSDatabaseIntermediary.getLastNames(fnTextField.getText(), lnTextField.getText());
for(int i=0; i < names.length; i++) {
if(!names[i].equals(lnTextField.getText().trim())) {
item = new JMenuItem(names[i]);
item.addActionListener(lnActionListener);
item.addMouseListener(NewPlayerPanel.this);
lnPopup.add(item);
}
}
if(names.length > 0 && !names[0].equals("")) {
lnPopup.setVisible(true);
}
lnPopup.grabFocus();
}
}
}// ends run()
};
t.start();
}
Thank you in advance.
Swing methods and constructors must be called on the AWT event dispatch thread. You are calling those methods on a different thread. The result is “undefined behavior”—which usually means things will work sometimes, but not all the time.
You need to separate Swing calls from database calls, which is done using EventQueue.invokeLater (or its alias, SwingUtilities.invokeLater):
private void resetLastNamePopup() {
lnPopup.setVisible(false);
lnPopup.removeAll();
final String fn = fnTextField.getText();
final String ln = lnTextField.getText();
Thread t = new Thread() {
#Override
public void run() {
if(DBHSDatabaseIntermediary.isConnected()
&& !fn.isEmpty() && !ln.isEmpty()) {
final String[] names =
DBHSDatabaseIntermediary.getLastNames(fn, ln);
// Rebuild JPopupMenu in AWT event thread.
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
for (String name : names) {
if (!name.equals(ln)) {
JMenuItem item = new JMenuItem(name);
item.addActionListener(lnActionListener);
lnPopup.add(item);
}
}
if (names.length > 0 && !names[0].isEmpty()) {
lnPopup.setVisible(true);
lnPopup.grabFocus();
}
}
});
}
}// ends run()
};
t.start();
}
For more information, see the javax.swing package contract, and Concurrency in Swing in the Java Tutorials.

java swingworker thread to update main Gui

hi id like to know whats the best way to add text to a jtextarea from a swingworkerthread, ive created another class which a jbutton calls by Threadsclass().execute();
and the thread runs in parallel fine with this code
public class Threadsclass extends SwingWorker<Object, Object> {
#Override
protected Object doInBackground() throws Exception {
for(int x = 0; x< 10;x++)
try {
System.out.println("sleep number :"+ x);
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(eftcespbillpaymentsThreads.class.getName()).log(Level.SEVERE, null, ex);
}
throw new UnsupportedOperationException("Not supported yet.");
}
}
now what id like to do is add the value of x to the text area on the main gui, any ideas much appreciated.
There is an excellent example from the JavaDocs
class PrimeNumbersTask extends
SwingWorker<List<Integer>, Integer> {
PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
//initialize
}
#Override
public List<Integer> doInBackground() {
List<Integer> numbers = new ArrayList<Integer>(25);
while (!enough && !isCancelled()) {
number = nextPrimeNumber();
numbers.add(number);
publish(number);
setProgress(100 * numbers.size() / numbersToFind);
}
return numbers;
}
#Override
protected void process(List<Integer> chunks) {
for (int number : chunks) {
textArea.append(number + "\n");
}
}
}
JTextArea textArea = new JTextArea();
final JProgressBar progressBar = new JProgressBar(0, 100);
PrimeNumbersTask task = new PrimeNumbersTask(textArea, N);
task.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer)evt.getNewValue());
}
}
});
task.execute();
System.out.println(task.get()); //prints all prime numbers we have got
Take a look at publish and process
The underlying intention is that you need to update the UI from only within the Event Dispatching Thread, by passing the data you want to updated to the UI via the publish method, SwingWorker will call process for you within the context of the EDT
Within doInBackground(), use publish(V... chunks) to send data to process(List<V> chunks).
See How SwingWorker works.

press x on top right corner Event for eclipse-rcp

I am working on an eclipse-rcp project. I want to implement an EventListener (or something like that), which is called, when the user presses the x on the top right corner of the window.
Any idea where/how I can implement this?
Thanks to all!
There are different ways to do so, depending on what you need. If you want to forbid closing of the main shell under some circumstances, you might want to use preWindowShellClose() method in your WorkbenchWindowAdvisor. http://help.eclipse.org/helios/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fui%2Fapplication%2FWorkbenchWindowAdvisor.html .
If you just want to perform some action when main window is closed, you could add a shutdownHook like this (see also this thread: What is the correct way to add a Shutdown Hook for an Eclipse RCP application?):
public class IPEApplication implements IApplication {
public Object start(IApplicationContext context) throws Exception {
final Display display = PlatformUI.createDisplay();
Runtime.getRuntime().addShutdownHook(new ShutdownHook()); }
// start workbench...
}
}
private class ShutdownHook extends Thread {
#Override
public void run() {
try {
final IWorkbench workbench = PlatformUI.getWorkbench();
final Display display = PlatformUI.getWorkbench()
.getDisplay();
if (workbench != null && !workbench.isClosing()) {
display.syncExec(new Runnable() {
public void run() {
IWorkbenchWindow [] workbenchWindows =
workbench.getWorkbenchWindows();
for(int i = 0;i < workbenchWindows.length;i++) {
IWorkbenchWindow workbenchWindow =
workbenchWindows[i];
if (workbenchWindow == null) {
// SIGTERM shutdown code must access
// workbench using UI thread!!
} else {
IWorkbenchPage[] pages = workbenchWindow
.getPages();
for (int j = 0; j < pages.length; j++) {
IEditorPart[] dirtyEditors = pages[j]
.getDirtyEditors();
for (int k = 0; k < dirtyEditors.length; k++) {
dirtyEditors[k]
.doSave(new NullProgressMonitor());
}
}
}
}
}
});
display.syncExec(new Runnable() {
public void run() {
workbench.close();
}
});
}
} catch (IllegalStateException e) {
// ignore
}
}
}
Hope this helps.

Categories