87574

JFrame only shows components at first creation

Question:

When I start my application it opens a JFrame (the main window) and a JFilechooser to select an input directory, which is then scanned.

The scan method itself creates a new JFrame which contains a JButton and a JProgressBar and starts a new Thread which scans the selected Directory. Up until this point everything works fine.

Now I change the Directory Path in my Main Window, which calls the scan method again. This time it creates another JFrame which should contain the JProgressBar and the JButton but it shows up empty (The JFrame Title is still set).

update: minimal example

public class MainWindow { private JFrame _frame; private JTextArea _textArea; private ProgressBar _progress; public MainWindow() throws InterruptedException, ExecutionException { _frame = new JFrame("Main Window"); _textArea = new JTextArea(); _frame.add(_textArea); _frame.setSize(200, 200); _frame.setVisible(true); _textArea.setText(doStuffinBackground()); _progress.dispose(); } private String doStuffinBackground() throws InterruptedException, ExecutionException { setUpProgressBar(); ScanWorker scanWorker = new ScanWorker(); scanWorker.execute(); return scanWorker.get(); } private void setUpProgressBar() { // Display progress bar _progress = new ProgressBar(); } class ProgressBar extends JFrame { public ProgressBar() { super(); JProgressBar progressBar = new JProgressBar(); progressBar.setIndeterminate(true); progressBar.setStringPainted(false); add(progressBar); setTitle("Progress Window"); setSize(200, 200); toFront(); setVisible(true); } } class ScanWorker extends SwingWorker<String, Void> { @Override public String doInBackground() throws InterruptedException { int j = 0; for (int i = 0; i < 10; i++) { Thread.sleep(1000); j += 1; } return String.valueOf(j); } } public static void main(String[] args) throws InvocationTargetException, InterruptedException { SwingUtilities.invokeAndWait(new Runnable() { public void run() { // Start the main controller try { new MainWindow(); } catch (InterruptedException | ExecutionException e) {} } }); } }

Answer1:

From the basic looks of your scan method, you are blocking the Event Dispatching Thread, when you scan the directory, which is preventing it from updating the UI.

Specifically, you don't seem to truly understand what Callable and FutureTask are actually used for or how to use them properly...

Calling FutureTask#run will call the Callable's call method...from within the current thread context.

Take a look at <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/" rel="nofollow">Concurrency in Swing</a> for more details...

Instead of trying to use FutureTask and Callable in this manner, consider using a SwingWorker, which is designed to do this kind of work (and uses Callable and FutureTask internally)

Have a look at <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html" rel="nofollow">Worker Threads and SwingWorker</a> for more details

Now, before you jump down my throat and tell me that "it works the first time I ran it", that's because you're not starting your UI properly. All Swing UI's should be create and manipulated from within the context of the Event Dispatching Thread. You main method is executed in, what is commonly called, the "main thread", which is not the same as the EDT. This is basically setting up fluke situation in where the first time you call scan, you are not running within the context of the EDT, allowing it to work ... and breaking the single thread rules of Swing in the process...

Take a look at <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html" rel="nofollow">Initial Threads</a> for more details...

I would also consider using a JDialog instead of another frame, even if it's not modal, it makes for a better paradigm for your application, as it really should only have a single main frame.

<strong>Updated based on new code</strong>

So, basically, return scanWorker.get(); is a blocking call. It will wait until the doInBackground method completes, which means it's block the EDT, still...'

Instead, you should be making use of the publish, process and/or done methods of the SwingWorker

<img alt="Worker" class="b-lazy" data-src="https://i.stack.imgur.com/GTnXf.gif" data-original="https://i.stack.imgur.com/GTnXf.gif" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" />

import java.util.ArrayList; import java.util.List; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; public class MainWindow { private JFrame _frame; private JTextArea _textArea; private ProgressBar _progress; public MainWindow() { _frame = new JFrame("Main Window"); _textArea = new JTextArea(); _frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); _frame.add(new JScrollPane(_textArea)); _frame.setSize(200, 200);; _frame.setVisible(true); doStuffinBackground(); } private void doStuffinBackground() { // _progress = new ProgressBar(); // ScanWorker scanWorker = new ScanWorker(); // scanWorker.execute(); // return scanWorker.get(); _progress = new ProgressBar(); ScanWorker worker = new ScanWorker(_textArea, _progress); worker.execute(); _progress.setVisible(true); } class ProgressBar extends JDialog { public ProgressBar() { super(_frame, "Scanning", true); JProgressBar progressBar = new JProgressBar(); progressBar.setIndeterminate(true); progressBar.setStringPainted(false); add(progressBar); setTitle("Progress Window"); pack(); setLocationRelativeTo(_frame); } } class ScanWorker extends SwingWorker<List<String>, String> { private JTextArea textArea; private ProgressBar progressBar; protected ScanWorker(JTextArea _textArea, ProgressBar _progress) { this.textArea = _textArea; this.progressBar = _progress; } @Override protected void process(List<String> chunks) { for (String value : chunks) { textArea.append(value + "\n"); } } @Override public List<String> doInBackground() throws Exception { System.out.println("..."); int j = 0; List<String> results = new ArrayList<>(25); for (int i = 0; i < 10; i++) { Thread.sleep(1000); j += 1; System.out.println(j); results.add(Integer.toString(j)); publish(Integer.toString(j)); } return results; } @Override protected void done() { progressBar.dispose(); } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new MainWindow(); } }); } }

Recommend

  • In python, why does 0xbin() return False? [duplicate]
  • Memory error: numpy.genfromtxt()
  • How to use loop in Jquery to add table multiple times into div
  • jQuery Accordion Functionality panel opens when it shouldn't be opening
  • Do elements with “position: absolute;” behave as block-level elements?
  • globals() vs locals() mutability
  • Is it possible to print a function as a string in Python? [duplicate]
  • how do I Sort and organize data from csv file in php
  • What's the difference between list() and [] [duplicate]
  • Scapy sniff() in a class that subclassess threading.Thread()
  • navigator.notification.alert fires 4 alerts for 1 call on IOS - jquery mobile - phonegap 2.2.0
  • How and where to install a module in python from github
  • PHP shell_exec running a shellscript with ssh
  • Lucene Query Boosting
  • Unpickling mid-stream (python)
  • Converting a PEM private key file to a JAVA PrivateKey Object
  • Security issues with PHP's Readfile method
  • Creating Java object from class name with constructor, which contains parameters [duplicate]
  • how to avoid repetitive constructor in children
  • onBackPressed() not being executed
  • Highlight and Bold text in JTextPane
  • Change multiple background-images with jQuery
  • how to do an event when i swipe from fragment to the other
  • Deleting and Updating values from a cusrsor adapter
  • Align navbar back button on right side
  • Possible to stop flickering java tooltip in heavyweight mode?
  • Window Size for Mac application
  • Delete MySQLi record without showing the id in the URL
  • Akka Routing: Reply's send to router ends up as dead letters
  • VB.net deserialize, JSON Conversion from type 'Dictionary(Of String,Object)' to type '
  • unknown Exception android
  • EntityFramework adding new object to nested object collection
  • Checking variable from a different class in C#
  • Django query for large number of relationships
  • Programmatically clearing map cache
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • How can I use `wmic` in a Windows PE script?
  • failed to connect to specific WiFi in android programmatically
  • How to push additional view controllers onto NavigationController but keep the TabBar?
  • How can I use threading to 'tick' a timer to be accessed by other threads?