Using SwingWorker Threading Mode
It is important for swing developers to use the concurrency mechanism with care. A good swing program uses the concurrency mechanism to create a user interface that does not lose its response-regardless of the user interaction, the program can always respond to it. To create a responsive program, developers must learn how to use multithreading in the swing framework.
A swing developer will deal with the following types of threads:
(1) Initial threads (initial thread), which executes the initialization application code.
(2) The event dispatch thread (event-distributing threads), where all incident-handling code is executed. Most code that interacts with the swing framework must also execute this thread.
(3) Worker threads (worker threads), also known as background threads (background threads), which perform all tasks that consume time.
Developers do not need to explicitly create these threads in code: they are provided by the runtime or swing framework. The developer's job is to use these threads to create a responsive, persistent swing program.
As with all other programs running on the Java platform, a swing program can create additional threads and thread pools, which require the methods that are introduced in this article. This article will introduce the above three kinds of threads. The discussion of worker threads will involve the use of the Javax.swing.SwingWorker class. This class has many useful features, including communication and collaboration between worker thread tasks and other thread tasks.
1. Initial thread
Each program generates a series of threads at the beginning of the application logic. In a standard program, there is only one thread: This thread will invoke the main method in the program main class. The initial thread in the applet is the constructor of the applet object, which invokes the Init method, which may be executed in a single thread, or in two or three different threads, depending on the Java platform's implementation. In this article, we call this type of thread the initial thread (initial threads).
In a swing program, there's not much to do with the initial thread. Their most basic task is to create a Runnable object that initializes the GUI and the order of objects that are used to perform events in the event-distributing thread. Once the GUI is created, the program will be driven primarily by the GUI event, where each event driver will cause an event to be executed in the event-issuing thread. Program code can orchestrate additional tasks for event-driven threads (provided they are executed quickly, so that they do not interfere with event processing) or create worker threads (for tasks that consume time).
An initial thread choreography GUI creation task is by invoking Javax.swing.SwingUtilities.invokeLater or javax.swing.SwingUtilities.invokeAndWait. Both of these methods have a unique argument: runnable is used to define new tasks. The only difference is that Invokerlater simply choreography the task and returns, invokeandwait waits until the task has finished executing before returning.
Look at the following example:
Swingutilities.invokelater (New Runnable ()) {public
void run () {
Createandshowgui ()}
}
In an applet, the task of creating a GUI must be placed in the Init method and used invokeandwait, otherwise the initial process will likely be completed before the GUI is created, which could cause problems. In other cases, the Orchestration GUI creation task is usually the last executed in the initial thread, so it is possible to use either Invokelater or invokeandwait.
Why does the initial thread not create the GUI directly? Because almost all of the code used to create and interact with swing components must be executed in the event-issuing thread. This constraint is discussed in the following article.
2. Event Distribution Thread
The handling code for the swing event executes in a special thread called the event-distributing thread. Most of the code that calls the swing method is executed in this thread. This is necessary because most swing objects are "not thread safe."
The execution of the code can be imagined as performing a series of short tasks in the event-distributing thread. Most tasks are called by the event-handling method, such as actionlistener.actionperformed. The rest of the tasks will be programmed by program code, using Invokelater or invokeandwait. The task in the event-distributing thread must be able to be executed quickly, and if not, the user interface will become "unresponsive" if the backlog of unhandled events is not achieved.
If you need to determine if your code is executing in an event-issuing thread, call Javax.swing.SwingUtilities.isEventDispatchThread.
3. Worker Threads and SwingWorker
When a swing program needs to perform a long task, it is usually done using a worker thread. Each task executes in a worker thread, which is an instance of a Javax.swing.SwingWorker class. The SwingWorker class is an abstract class; You have to define its subclasses to create a SwingWorker object; You typically use anonymous inner classes to do this.
SwingWorker provides some characteristics of communication and control:
(1) SwingWorker subclasses can define a method, done. When the background task completes, it will automatically be called by the event-issuing thread.
(2) SwingWorker class realizes java.util.concurrent.Future. This interface allows background tasks to provide a return value to other threads. The methods in this interface also provide the ability to allow background tasks to be undone and to determine whether the background task is completed or revoked.
(3) Background tasks can provide intermediate results by calling Swingworker.publish, which is called by the event-issuing thread.
(4) Background tasks can define binding properties. The change of the binding property triggers the event, and the event-issuing thread invokes the event handler to handle the triggered events.
4. A simple background task
Here's an example of a very simple task, but it's a potentially time-consuming task. The Tumbleitem applet imports a series of picture files. If these picture files are imported through the initial thread, there will be a delay before the GUI appears. If these picture files are imported in the event-issuing thread, the GUI will likely be temporarily unresponsive.
To solve these problems, the Tumbleitem class creates and executes an instance of the Stringworker class when it initializes. The Doinbackground method of this object, executed in a worker thread, imports a picture into a ImageIcon array, and returns a reference to it. Then the Done method executes in the event-distributing thread, gets the returned reference, and places it in the member variable IMGs of the applet class. Doing so allows the Tumbleitem class to create the GUI immediately without having to wait for the picture to be imported.
The following example code defines and implements a SwingWorker object.
SwingWorker worker = new swingworker<imageicon[], void> () {@Override public Ima
Geicon[] Doinbackground () {final imageicon[] Innerimgs = new Imageicon[nimgs];
for (int i = 0; i < Nimgs i++) {Innerimgs[i] = LoadImage (i+1);
return INNERIMGS;
@Override public void Do () {//remove the "Loading Images" label.
Animator.removeall ();
Loopslot =-1;
try {IMGs = get ();
The catch (Interruptedexception ignore) {} catch (Java.util.concurrent.ExecutionException e) {String why = null;
Throwable cause = E.getcause ();
if (cause!= null) {why = Cause.getmessage ();
else {why = E.getmessage ();
} System.err.println ("Error Retrieving file:" + why);
}
}
};
all inherited SwingWorker subclasses must implement doinbackground; implementation of the Done method is optional.
Note that swingworker is a generic class with two parameters. The first type parameter specifies the return type of the Doinbackground. It is also the type of a get method that can be called by other threads to obtain a return value from Doinbackground. The second type parameter specifies the type of intermediate result, and this example does not return intermediate results, so it is set to void.
using the Get method, you can make the object IMGs reference (created in the worker thread) available in the event-distributing thread. This allows you to share objects between threads. The
actually has two methods to get the object returned by the Doinbackground class. The
(1) Call Swingworker.get has no arguments. If the background task does not complete, the Get method blocks until it completes. The
(2) invokes the Swingworker.get with the parameter designation timeout. If the background task does not complete, block until it completes-unless the timeout expires, in which case the get will throw java.util.concurrent.TimeoutException.
5. A task with intermediate results
is useful for providing intermediate results for a background task that is working. Background tasks can call the Swingworker.publish method to do this. This method accepts many parameters. Each parameter must be one specified by the second type parameter of SwingWorker. The
can overwrite (override) Swingworker.process to hold the results provided by the Publish method. This method is invoked by the event-issuing thread. The result set from the publish method is usually collected by a process method.
Let's take a look at the examples provided by Filpper.java. This program generates a series of random Boolean test java.util.Random through a background task. It's like a coin test. In order to report its results, the background task uses an object Flippair.
private static class Flippair {
Private final long heads, total;
Flippair (long heads, long total) {
this.heads = heads;
This.total = total;
}
Heads represents the result of true; Total represents the overall number of throws.
The background program is an Filptask instance:
Private class Fliptask extends Swingworker<void, flippair> {
Because the task does not return a final result, there is no need to specify what the first type parameter is, using void. The task calls publish after each "throw":
@Override
protected Void doinbackground () {
long heads = 0;
Long total = 0;
Random Random = new Random ();
while (!iscancelled ()) {
total++;
if (Random.nextboolean ()) {
heads++
}
Publish (new Flippair (heads, total);
}
return null;
}
Since publish is often invoked, many flippair values are collected before the process method is called by the event-issuing thread; The process only focuses on the last set of values returned each time, using it to update the GUI:
protected void process (List pairs) {
Flippair pair = Pairs.get (Pairs.size ()-1);
Headstext.settext (String.Format ("%d", pair.heads));
Totaltext.settext (String.Format ("%d", pair.total));
Devtext.settext (String.Format ("%.10g", (
Double) pair.heads)/(double pair.total)-0.5);
}
6. Cancel background tasks
Call Swingworker.cancel to cancel a background task that is being performed. The task must be consistent with its own revocation mechanism. There are two ways to do this:
(1) When a interrupt is received, it is terminated.
(2) Call swingworker.iscanceled, and if SwingWorker calls Cancel, the method returns True.
7. Binding properties and State methods
SwingWorker supports bound properties, which is useful when communicating with other threads. Provides two binding properties: progress and state. Progress and state can be used to trigger event-handling tasks in the event-distributing thread.
By implementing a property change listener, a program can capture changes to progress,state or other binding properties.
7.1The Progress Bound Variable
The progress binding variable is an integer variable ranging from 0 to 100. It predefined the setter (the protected swingworker.setprogress) and the getter (the public swingworker.getprogress) method.
7.2The State Bound Variable
The change of State binding variable reflects the process of SwingWorker object's change in its lifecycle. The variable contains an enumerated type of swingworker.statevalue. The possible values are:
(1) PENDING
The duration of this state is known from the establishment of the object that the Doinbackground method is called.
(2) started
This state lasts for a time before the Doinbackground method is invoked until the done method is called before the moment.
(3) Done
The remaining time that the object exists will remain this state.
You need to return the value of the current state to invoke Swingworker.getstate.
7.3Status Methods
Two methods provided by the future interface can also report the status of background tasks. IsCancelled returns True if the task is canceled. In addition, if the task completes, that is, either the normal completion or the cancellation, Isdone returns True.
using top-level containers
Swing offers 3 top-tier container classes: Jframe,jdialog,japplet. When using these three classes, you must pay attention to the following points:
(1). In order to be displayed on the screen, each GUI component must be part of the containing hierarchy (containment hierarchy). The containment hierarchy is a tree-shaped structure of the component, and the topmost container is its root.
(2). Each GUI component can only be included once. If a component is already in a container and then attempts to add it to a new container, the component is removed from the first container and added to the second container.
(3). Each top-level container has a Content Panel (pane), which typically contains visual components (directly or indirectly) of all top-level container GUIs.
(4). You can add a menu bar to the top-level container. Usually this menu bar is placed in the top-level container, but outside the content panel.
1. Top-level container and inclusion hierarchy
Each program that uses swing components has at least one top-level container. This top-level container is the root node that contains the hierarchy-this layer contains all the swing components that will appear in this top-level container.
Typically, a single application based on the swing GUI has at least one level of inclusion, and its root node is jframe. For example, if an application has a window and two dialog boxes, then the application will have three levels of inclusion, and there will be three top-level containers. A containing hierarchy will jframe as its root node, and each of the two containing layers has a jdialog as its root node.
A small program (applet) based on a swing component has at least one containing hierarchy, and it is possible to determine that one must have a japplet as its root node. For example, a small program with a dialog box will have two levels of inclusion. The component in the browser window will be placed at an inclusive level, and its root node is a JApplet object. The dialog box has a hierarchy whose root node is a JDialog object.
2. Adding components to the content panel
The following code actions are the contents panel of the frame in the above example and add the yellow label:
Frame.getcontentpane (). Add (Yellowlabel, borderlayout.center);
As the code shows, you must first find the content panel of the top-level container, implemented by means of Getcontentpane. The default content panel is a simple intermediate container that inherits from JComponent and uses a borderlayout as its panel manager.
Customizing a content panel is simple-set the panel manager or add a border. It is important to note that the Getcontentpane method returns a container object instead of the JComponent object. This means that if you need to take advantage of some of the functionality of the jcomponent, you must also convert the return value to a type or create your own component as a content panel. Our example usually uses the second approach. Because the second method is more clear and clearer. Another way we sometimes use it is simply to add a custom component to the content panel, completely obscuring the content panel.
If you create your own content panel, be careful to make sure it is opaque. An opaque jpanel will be a good choice. Note that JPanel's layout management is FlowLayout by default, and you may want to replace it with another layout manager.
To make a component a content panel, you need to use the Setcontentpane method of the top-level container, for example:
Create a panel and add components to it.
JPanel ContentPane = new JPanel (new BorderLayout ());
Contentpane.setborder (Someborder);
Contentpane.add (Somecomponent, borderlayout.center);
Contentpane.add (Anothercomponent, borderlayout.page_end);
Make it the content pane.
Contentpane.setopaque (true);
Toplevelcontainer.setcontentpane (ContentPane);
Note: Do not use transparent containers as content panels, such as JScrollPane, JSplitPane, and JTabbedPane. . A transparent content panel will cause component clutter. Although you can make any transparent swing component opaque by Setopaque (true), when some components are set to be completely opaque, it looks like something is wrong. For example, a label panel.
3. Add a menu bar (adding a menu bars)
theoretically, each top-level container can have a menu bar. However, the fact that the menu bar appears only in frame or applet. To add a menu bar to the top level container, you need to create a JMenuBar object, assemble some menus, and then call the Setjmenubar method. The Topleveldemo instance adds a menu bar to its frame by using the following code.
Frame.setjmenubar (Cyanmenubar);
4. Root container (the root Pane)
each top-level container relies on an implicit intermediate container called the root container. The root container manages the content Panel and menu bar, along with two or more two other containers (see layered pane, etc.). You don't usually need to know about the use of swing component root containers. However, if you want to intercept mouse clicks or paint on multiple components, you need to know the root container.
The content panel and the optional menu bar are described above and are not repeated here. The other two components contained in the root container are the layout panel and the glass panel. The layout panel directly contains the menu bar and content panel, and allows you to sort the other components that you add to the z-coordinate. Glass panels are typically used to intercept input actions that occur at the top level and can also be used to paint on multiple components.