Swing initialization and loading approach

I have made quite a few different Swing applications, and their loading time usually varies from a few seconds to several minutes depending on the size of the user interface / data. Also in some cases, loading application data is mixed with loading a user interface.

A download time of a few seconds is not a problem, but when it is longer than 10 seconds, it is obvious that some kind of loading screen should be displayed until the user interface / data is completely initialized.

What would you usually do - first create a loading screen (for example, a window with a logo and some label that is updated during application loading), and update it from various download points in your application.

The problem is that the application usually loads in a single call queued in the EDT and it is difficult to split it into multiple calls on the EDT without complicating the application code. Since application loading is performed in one call queued for EDT, you simply cannot correctly update the loading screen - the update will not be displayed until the application is initialized, since the EDT is busy loading the application.

Thus, in order to implement the loading screen, in some cases I transferred the initialization of the user interface of the application outside the EDT and designed them so that no information about updating the user interface was performed during the loading. The display of the application frame and all actions of the application user interface will still be performed in the EDT. This is not too good, but after many tests and looking at the Swing code, I know for sure that it does not cause any problems even in large applications. However, this is not good at all, even if it does not cause any problems.

So the question is: What approaches can be used to correctly display and update the application loading screen while maintaining application initialization in EDT?

I hope it is not too wide.

"dummy", "" :

import javax.swing.*;
import java.awt.*;

public class DummyApplication extends JFrame
{
    private static JDialog loadingDialog;
    private static JLabel loadingProgress;

    public DummyApplication ()
    {
        super ( "Dummy application" );

        dummyProgressUpdate ( "Loading content...", 3000 );

        final JLabel label = new JLabel ( "Custom content" );
        label.setBorder ( BorderFactory.createEmptyBorder ( 100, 100, 100, 100 ) );
        getContentPane ().add ( label );

        dummyProgressUpdate ( "Loading settings...", 3000 );

        setDefaultCloseOperation ( WindowConstants.EXIT_ON_CLOSE );
        pack ();
        setLocationRelativeTo ( null );

        dummyProgressUpdate ( "Opening application...", 1000 );
    }

    private static void dummyProgressUpdate ( final String status, final int time )
    {
        SwingUtilities.invokeLater ( () -> loadingProgress.setText ( status ) );
        dummyLoadTime ( time );
    }

    private static void dummyLoadTime ( final long time )
    {
        try
        {
            Thread.sleep ( time );
        }
        catch ( final InterruptedException e )
        {
            e.printStackTrace ();
        }
    }

    public static void main ( final String[] args ) throws Exception
    {
        // Displaying loading screen from EDT first
        SwingUtilities.invokeAndWait ( () -> {
            loadingDialog = new JDialog ( ( Window ) null, "Loading screen" );
            loadingProgress = new JLabel ( "Initializing application...", JLabel.CENTER );
            loadingProgress.setBorder ( BorderFactory.createLineBorder ( Color.LIGHT_GRAY ) );
            loadingDialog.getContentPane ().setLayout ( new BorderLayout () );
            loadingDialog.getContentPane ().add ( loadingProgress );
            loadingDialog.setUndecorated ( true );
            loadingDialog.setAlwaysOnTop ( true );
            loadingDialog.setModal ( false );
            loadingDialog.setSize ( 400, 100 );
            loadingDialog.setLocationRelativeTo ( null );
            loadingDialog.setVisible ( true );
        } );

        // Initializing application outside of the EDT
        final DummyApplication applicationFrame = new DummyApplication ();

        // Displaying application from the EDT
        SwingUtilities.invokeLater ( () -> {
            loadingDialog.setVisible ( false );
            applicationFrame.setVisible ( true );
        } );
    }
}

, JDK7:
http://sellmic.com/blog/2012/02/29/hidden-java-7-features-secondaryloop/

SecondaryLoop EDT-, . , JDialog EDT.

, , , :

import javax.swing.*;
import java.awt.*;

public class DummyApplication extends JFrame
{
    private static JDialog loadingDialog;
    private static JLabel loadingProgress;

    public DummyApplication ()
    {
        super ( "Dummy application" );

        dummyProgressUpdate ( "Loading content...", 3000 );

        final JLabel label = new JLabel ( "Custom content" );
        label.setBorder ( BorderFactory.createEmptyBorder ( 100, 100, 100, 100 ) );
        getContentPane ().add ( label );

        dummyProgressUpdate ( "Loading settings...", 3000 );

        setDefaultCloseOperation ( WindowConstants.EXIT_ON_CLOSE );
        pack ();
        setLocationRelativeTo ( null );

        dummyProgressUpdate ( "Displaying application...", 1000 );
    }

    private static void dummyProgressUpdate ( final String status, final int time )
    {
        // Use SecondaryLoop to block execution and force loading screen update
        final SecondaryLoop loop = Toolkit.getDefaultToolkit ().getSystemEventQueue ().createSecondaryLoop ();
        SwingUtilities.invokeLater ( () -> {
            loadingProgress.setText ( status );
            loop.exit ();
        } );
        loop.enter ();

        // Perform dummy heavy operation
        dummyLoadTime ( time );
    }

    private static void dummyLoadTime ( final long time )
    {
        try
        {
            Thread.sleep ( time );
        }
        catch ( final InterruptedException e )
        {
            e.printStackTrace ();
        }
    }

    public static void main ( final String[] args ) throws Exception
    {
        // Displaying loading screen from EDT first
        SwingUtilities.invokeAndWait ( () -> {
            loadingDialog = new JDialog ( ( Window ) null, "Loading screen" );
            loadingProgress = new JLabel ( "Initializing application...", JLabel.CENTER );
            loadingProgress.setBorder ( BorderFactory.createLineBorder ( Color.LIGHT_GRAY ) );
            loadingDialog.getContentPane ().setLayout ( new BorderLayout () );
            loadingDialog.getContentPane ().add ( loadingProgress );
            loadingDialog.setUndecorated ( true );
            loadingDialog.setAlwaysOnTop ( true );
            loadingDialog.setModal ( false );
            loadingDialog.setSize ( 400, 100 );
            loadingDialog.setLocationRelativeTo ( null );
            loadingDialog.setVisible ( true );
        } );

        // Initializing and displaying application from the EDT
        SwingUtilities.invokeLater ( () -> {
            final DummyApplication applicationFrame = new DummyApplication ();
            loadingDialog.setVisible ( false );
            applicationFrame.setVisible ( true );
        } );
    }
}

- dummyProgressUpdate - - , EDT, , , EDT, .

- , , - . , , , () , - ​​ .

+4
2

, SwingWorker , setProgress PropertyChangeListener.

process/publish, , done / PropertyChangeListener , ,

, , , .

, , , , , .

, CardLayout JTabbedPane, , , .

, , , , , , ...

+3

, SwingWorker, publish() EDT process(). PropertyChangeListener . , ; , StateValue - DONE. ,

  • .
  • .
  • GUI .

, -, . JTable, JList, JTextArea .. , .

+3

All Articles