This article discusses threads and swing components. The purpose is not only to help you use the Swing API in a thread safe manner, but also explains why we choose the thread solution now. This article includes the following:
SLR Rule: Swing thread can only be accessed by one thread at the same time. In general, this thread is event-dispatching thread. Exceptions to the rules: Some operations are guaranteed to be threaded. Event distribution: If you need to access the UI from a place handle or draw code, you can use the invokelater () or invokeAndwait () method of the Swingutilities class. Create a thread: If you need to create a thread-such as working for some cost-consuming capacity or affected by I / O capabilities - you can use a thread tool class such as SwingWorker or Timer. Why do we implement Swing: We use some background information about Swing threads to end this article.
Swing rules are: Once the Swing component is now a realized, all code that may affect or depend on the component status should be executed in the event delivery. This rule may sound a bit scary, but for many simple programs, you can not worry about thread problems. Before we write Swing code, let us first define two terms: realized and event distribution threads (event-dispatching thread). It is also possible to form a Paint () method that is already or may be called. A SWING component as a top window will be added when the following method is called: setvisible (true), show () or (possibly surprised) Pack (). When a window is already chemically, all components therebet are already chemically. Another way to develop a component is to put it into an existing container. You will see some examples of the components later. The event dispatching thread is a thread that performs drawing and event processing. For example, the Paint () and an ActionPerformed () method will automatically be executed in the event dispatch. Another way to put the code in the event dispatching process is the invokelater () method of the Swingutilities class. All code that may affect a dedicated Swing component must be executed in an event dispatch. But this rule has some exceptions:
Some methods are thread safety: In the Swing API document, thread security methods are marked with the following text: This method is thread Safe, Although Most Swing Methods Are Not. (This method is thread safe, although most swing methods Not.) The GUI of an application can often build and display in the main thread: The following typical code is safe, as long as the Swing or other) components are added: public class myapplication {public static void main (String " ] Args) {jframe f = new jframe ("labels"); // Add each component // to the main frame ... f.pack (); f.show (); // Don't do any GUI work ...}}
The code shown above is all running in the "main" thread. The call to f.PACK () makes the components below JFrames have been chemically. This means that f.show () call is unsafe and should be executed in the event dispatching process. Despite this, as long as the program does not have a way you see the GUI, JFRAME, or the components inside it almost impossible to receive a PAINT () call before f .Show () returns. Because there is no longer any GUI code after f.show (), all GUI work is transferred from the main thread to the event distribution thread, so the code discussed earlier is actually threaded. The GUI of an applet can be constructed and displayed in the init () method: existing browsers do not draw it before an applet's init () and start () methods are called. Thus, constructing the GUI is secure in an init () method of an applet, as long as you do not call the show () or setvisible method for an object in the applet. By the way, if the SWING component is used in the applet, you must implement subclasses for japplets. Also, the components should be added to the JApplet Content Pane, not directly to the Japplet. For any applet, you should not perform the initialization operation at the time of the init () or start () method; and should start a thread to perform the fee. The following JComponent methods are secure and can be called from any thread: repaint (), revALIDATE (), and invalidate (). The repaint () and revALIDATE () methods are queued for the event distribution thread and call the Paint () and validate () methods separately. The invalidate () method only tag a component and all of its direct ancestors only when you need to confirm. The listener list can be modified by any thread: call addListenertypelistener () and removelistenertypelistener () methods are always secure. Adding / deleting an addition / deletion operation for the listener list does not have any impact on the events in progress.
Note: The important difference between the RevalIdate () and the old validate () method is that revAlidate () caches the request and combines a validate () call. This is similar to the repaint () cache and combines the draw request. Most initialized GUI work naturally happened in an event distribution thread. Once GUI is visible, most programs are driven by events, such as buttons, or mouse clicks, which always processed in the event dispatching. However, there are always programs that need to perform some non-event-driven GUI work after GUI is visible. such as:
Programs that become a long-term initialization operation need to be used before it is available: This type of program should usually display the GUI during initialization, then update or change the GUI. The initialization process should not be carried out in an event dispatch; otherwise, the redraw assembly and event distribution will stop. Despite this, after initialization, the GUI's update / change should still be carried out in an event dispatch, and the reason is thread security. You must update the GUI program in response to non-AWT events: For example, imagine a server program to get a request from programs that might run on other machines. These requests may arrive at any time and will cause the server to call the server in some possible unknown threads. How do this method call to update the GUI? Execute the GUI update code in the event dispatch.
The Swingutilities class provides two ways to help you execute the code in the event delivery line:
Invokelater (): Requires some code in the event dispatching process. This method will return immediately and will not wait for the code to complete. InvokeAndwait (): Behavior is similar to invokelater (), except for this method to wait for the code to execute. In general, you can replace this method with invokelater (). Here are some examples of using these APIs. Please refer to "Bingo Example" in "The Java Tutorial", especially the following classes: CardWindow, ControlPane, Player, and OveralllStatusPane. Using the invokelater () method
You can call the InvokeLater () method from any thread to request the event dispatch running a specific code. You must put the code you want to run into a Run () method of a runnable object and set this RunNable object to the parameter of InvokeLater (). The invokelater () method will return immediately, and the event is sent to send the specified code. This is an example of using an invokelater () method: runnable demorkrunnable = new runnable () {public void run () {dowork ();}}; swingutilities.invokelater (DOWORKRUNNABLE);
Using invokeAndwait () method
The InvokeAther () method and the invokelater () method are very similar, in addition to the incident dispatched process for the invokeAit () method to return to the specified code. In the case of possible, you should try to use Invokelater () to replace InvokeAndWait (). If you really want to use INVOKEANDWAIT (), make sure the thread calling the invokeAndWait () does not hold the lock that may be needed during the call. This is a use of the invokeAndWait () example: void showHelloThereDialog () throws Exception {Runnable showModalDialog = new Runnable () {public void run () {JOptionPane.showMessageDialog (myMainFrame, "Hello There");}}; SwingUtilities.invokeAndWait ( SHOWMODALDIALOG); ; Runnable getTextFieldText = new Runnable () {public void run () {myStrings [0] = textField0.getText (); myStrings [1] = textField1.getText ();}}; SwingUtilities.invokeAndWait (getTextFieldText); System.out .println (MyStrings [0] " MyStrings [1]);} If you can avoid using threads, it is best to do this. Threads may be difficult to use and make the program's Debug more difficult. In general, the thread is unnecessary to work in strict sense, such as updates to component properties. Anyway, sometimes the thread is necessary. The following is some typical situation using threads: performing a fee-time task without having to send events to lock. Examples include the case where a large amount of calculations will result in a large number of cases (such as initialization), and is blocked for the network or disk I / O. An operation is repeatedly performed, usually a predetermined time period between two operation intervals. Wait a message from the customer.
You can use two classes to help you implement threads:
SwingWorker: Create a background thread to perform a fee. Timer: Create a thread to perform some code multiple times, execute the delay in inter-interval user definitions.
Use SwingWorker class
SwingWorker class
SwingWorker.java
Implementation, this class is not included in any release of Java, so you must download it separately. The SwingWorker class made all the dirty work required to implement a background thread. Although many programs do not need the background thread, the background thread is still very useful when the operation is performed, it can improve the performance of the program. SwingWorker's get () method. Here's an example of useing swingworker: To use the SwingWorker class, you first want to implement one of its subclasses. In the subclass, you must implement the construct () method also contains your long operation. When you instantiate SwingWorker's subclasses, SwingWorker creates a thread but does not start it. You want to call your SwingWorker object's start () method to start the thread, then the start () method calls your construct () method. When you need the object returned by the construct () method, you can call the Get () method of the SwingWorker class. This is an example of using the SwingWorker class: ... // In the main method: final swingworker worker = new swingWorker () {public object construct () {return new expensivedialogcomponent ();}}; worker.start () ;. ..// In the action event processing method:
JOPTIONPANE.SHOWMESSAGEDIALOG (F, Worker.get ()); When the program's main () method calls the start () method, SwingWorker launches a new thread to instantiate the expensivedialogcomponent. The main () method also constructs a GUI consisting of a window and a button. When the user clicks the button, the program will block, if necessary, block the ExpensiveDialogComponent creation completion. Then the program displays a mode dialog containing the ExpensiveDialogComponent. You can
MyApplication.java
Find the entire program.
Use the Timer class
The Timer class performs or performs an action multiple times by an ActionListener. When you create a timer, you can specify the frequency execution execution, and you can specify the listener of the timer's action event. When the timer is started, the action listener's actionPerformed () method is called (multiple) to perform the operation. The ActionPerformed () method defined by the timer action listener will call in the event dispatch. This means you don't have to use the InvokeLater () method. This is an example of using the TIMER class to realize an animation cycle: public class AnimatorApplicationTINDS JFRAME IMPLEments ActionListener {... // Defines instance variables here
Timer Timer; Public AnimatorApplicationTimer (...) {... // Create a timer to // to call this object Action Handler.
Timer = New Timer (DELAY, THIS); Timer.setInitialDelay (0); Timer.Setcoalesce (TRUE); ...} public void startanimation () {if (frozen) {// all don't do anything. Apply noble request // stop transform images. } Else {// Start (or restart) animation!
Timer.start ();}} public void stopanimation () {// Stop moving thread.
Timer.stop ();} public void actionperformed (ActionEvent E) {// Go to the next frame animation.
Framenumber ; // shows.
Repaint ();} ...} Doing all user interface code in a thread has some advantages:
Components Developers don't have to understand thread programming: All components in the toolkit in ViewPoint and TRestle must fully support multi-thread access, making it very difficult to expand, especially for developers who are not proficient in thread programming. Recently, some of the toolkits such as SubARCTIC and IFC use and Swing a similar design. The event is distributed in a predictable order: InvokeLater () queued RunNable object sent from the mouse and keyboard event, timer event, and drawing the same queue. In some of the tool packs that completely support multi-thread access, the change in components is changed by incomplete thread scheduling programs to the event processing. This makes comprehensive testing difficulties or even impossible. Lower price: Try to be careful to lock the toolkit of the critical area to spend the feet time and space in the locked management. Whenever a method in which a method implemented in a customer code (such as any public and protected methods in the public class), the kit must save its status and release all locks so that the customer code can be Get the lock. When the control is retracted to the toolkit, the toolkit must restrained its lock and restore the status. All applications have to afford this price, even if most applications do not need to access concurrent access to GUI.