MarginWidth = "0" marginheight = "0" src = "/ ad / Topbanner.htm" frameborder = "0" width = "468" scrolling = "no" height = "60" valign = "bottom">
July 21, 2004 Login / Register
[Java original community, current online: 206, this peak: 780] Home | JAVA News | Research Collection | Forum | Open Source Software | JR Works | Boutique Download | About Us
Home? Research Collection? Topic: UI Published Review
Revie of SWING thread (below) SRX81 translation (Participate: 240, expert points: 1990) Published: 2003-11-6 9:10 am Version: 1.0 Read: 1738 times
By Jonathan Simon10 / 24/2003 Original: http://today.java.net/pub/a/today.java.net/pub/A/TODAY/2003/10/24/swing.html? Page = 2 Previous: Reflections on Swing Threads (on Solution: Event Drive Programming All of these solutions have a common fatal defect - attempt to represent a task's function set while continuously changing threads. However, changing the thread requires an asynchronous model, while the thread processes Runnable asynchronously. Part of the problem is that we have a synchronized model at an attempt to achieve a synchronous model above an asynchronous thread model. This is the root of all runnails and dependence, execution order and internal SCoPing issues. If we can build a real asynchronous, we can solve our problems and greatly simplify the Swing thread. Before this, let's list the questions we have to solve: 1. Execute code in the appropriate thread 2. Use swingutilities.invokelater () asynchronously. Asynchronous execution results in the following problem: 1. Mutual coupling Component 2. Difficulties in variables 3. The order of execution allows us to consider messaging-based systems like Java Message Services (JMS) because they provide loose coupling between functional components in asynchronous environments. The message system triggers an asynchronous event, as described in Enterprise Integration Patterns. Interested participants listen to the event and respond to the event - usually by executing some of their own code. The result is a group of modular, loosely coupled components, and components can be added or removed from the system without affecting other components. More importantly, the dependence between components is minimized, and each component is a good definition and package - each of them is only responsible for their work. They simply trigger the message, and other components will respond to this message and respond to messages triggered by other components. Now, we first ignore the thread problem and decouple the components and transplanted into the asynchronous environment. After we solve the asynchronous problem, we will go back to see thread problems. As we have to see, it will be very easy to solve this problem. Let us take the examples introduced in front and transplant it to an event-based model. First, we call the lookup to a class called lookupManager. This will allow us to remove database logic in all UI classes and ultimately allow us to completely disengage the two. Below is the code of the LookupManager class: class lookupmanager {private string [] lookup (string text) {string [] results = ... // database lookup code return results} Now we start to convert to the asynchronous model. In order to call this call asynchronously, we need to return to the abstract call. In other words, the method cannot return any value. We will have something you want to know in terms of distinctive action. The most obvious event in our example is the search end event. So let's create a listener interface to respond to these events. This interface contains a single method lookupCompleted (). Below is the definition of the interface: Interface looklistener {public void lookCompleted (Iterator Results); This will allow us to pass other information without changing the LookUplistener interface. For example, we can include the strings and results that are found in the Lookupevent.
The following is LookupEvent class: public class LookupEvent {String searchText; String [] results; public LookupEvent (String searchText) {this.searchText = searchText;} public LookupEvent (String searchText, String [] results) {this.searchText = searchText; this .results = results;} public string getsearchText () {return searchtext;} public string [] getResults () {return results;}} Note that the Lookupevent class is not variable. This is very important because we don't know who will deal with these events during the pass. Unless we created an event's protection copy to each listener, we need to make events unstrenomed. If not, a listener may unintentionally or maliciously revisit the event object and destroy the system. Now we need to call the LookUpComplete () event on lookupManager. We start by adding a set of LookupListener on LookupManager: List listeners = new ArrayList (); and a method LookupListener added and removed on the LookupManager: public void addLookupListener (LookupListener listener) {listeners.add (listener);} public void RemoveluggUplistener (LookUplistener Listener) {listener.Remove (Listener);} We need to call the listener's code when the action occurs. In our example, we will trigger a lookupCompleted () event while looking back. This means it iterations on the listener collection and uses a lookupCompleted () method using a lookupevent event object. I like to extract these code to a separate method Fire [event-method-name], which constructs an event object, iterations on the listener collection, and calls the appropriate method on each listener. This helps isolating the code of the primary logic code and calling the listener. Here is our fireLookupCompleted method: private void fireLookupCompleted (String searchText, String [] results) {LookupEvent event = new LookupEvent (searchText, results); Iterator iter = new ArrayList (listeners) .iterator (); while (iter.hasNext ( )) {Lookuplistener Listener = (lookuplistener) iter.next (); listener.lookUpCompleted (Event);}} The second line of code creates a new collection that is incorporated into the original audio collection. This decides on the LookupManager after the listener response event.
If we are not a secure copy collection, a bored error occurred while some listeners should be called without being called. Below, we will call the FirelookUpCompleted auxiliary method when the action is completed. This is the end of the LOOKUP method's return query results. So we can change the Lookup method to trigger an event rather than return a string array itself. Below is a new lookup method: public void lookup (string text) {// mimic the server call delay ... try {thread.sleep (5000);} catch (exception e) {E.PrintStackTrace ();} // Imagine We got this from a server string [] results = new string [] {"book one", "book two", "book three"}; firelookupCompleted (text, result);} Now let us add a listener to lookupManager . We want to update the text area when you look back. In the past, we just call the setText () method directly. Because the text area is executed in the UI together with the database call. Since we have abstracted from the UI, we will use the UI class as a listener to the LookusManager, listen to the Lookup event and update yourself accordingly. First, we will achieve the listener interface class definition: public class FixedFrame implements LookupListener Then we implement interface methods: public void lookupCompleted (final LookupEvent e) {outputTA.setText ( ""); String [] results = e.getResults () ; For (int i = 0; i In order to demonstrate how to add new events, let's add an event starting with a lookup. We can add an event called lookupstarted () to lookuplistener, and we will trigger it before the lookup starts execution. We also create a FirelookupStarted () event call all lookuplistener's lookstarted (). The LOOKUP method is now as follows: Public void lookup (String text) {FirelookupStarted (text); // mimic the server call delay ... try {thread.sleep (5000);} catch (exception e) {E.PrintStackTrace (); } // imagine we got this from a server string [] results = new string [] {"book one", "book two", "book three"}; firelookupCompleted (text, result);} We also add new triggers Method FirelookupStarted (). This method is equivalent to the FirelookUpCompleted () method, except that we call the lookupstarted () method on the listener, and the event does not contain result sets. Here is the code: private void fireLookupStarted (String searchText) {LookupEvent event = new LookupEvent (searchText); Iterator iter = new ArrayList (listeners) .iterator (); while (iter.hasNext ()) {LookupListener listener = (LookupListener) iter .next (); listener.lookupstarted (Event);}} Last, we implements a lookstarted () method on the UI class, setting the text area prompt the current search. Public Void LookupStarted (Final Lookupevent E) {Outputta.Settext ("Searching for:" E.GetSearchText ());} This example shows how easy it is to add new events. Now let's take a look at the flexibility of displaying event-driven decoupling. We will demonstrate by creating a log class while outputting information in the command line when a search start and end. We call this class as Logger. The following is its code: public class Logger implements LookupListener {public void lookupStarted (LookupEvent e) {System.out.println ( "Lookup started:" e.getSearchText ());} public void lookupCompleted (LookupEvent e) {System. Out.println ("Lookup Completed:" " " E.GETRESULTS ());}} Now we add Logger as a listener for the LookusManager in the FixedFrame constructor. public FixedFrame () {lookupManager = new LookupManager (); lookupManager.addListener (this); lookupManager.addListener (new Logger ()); initComponents (); layoutComponents ();} Now that you've seen to add new events, create new Listener - show you the flexibility and scalability of the event driver. You will find that as you have more developed a program, you will be more skilled in your application to create a universal action. Like all other things, this requires only time and experience. It seems that many studies have been made on the event model, but you still need to compare it with other alternatives. Consider development time costs; the most important, this is a one-time cost. Once you have created a listener model and their actions, add a listener to your app in your app. Threads to now, we have solved the above asynchronous problems; through the listener to deliver the components, pass the variables through the event object, the order of execution by the event generation and the synonym registration. Let us return to thread problems, because it is brought here. It is actually very easy: Because we already have an asynchronous listener, we can simply let the listener decide which thread should be executed in. Consider the separation of the UI class and the LookUpManager. The UI class is based on an event and decides what processing needs. And, this class is also swing, and the log class is not. So let the UI class be responsible for determining what it should perform in what thread will make more meaningful. So let's take a look at the UI class again. Below is a LOOKUPCOMPLETED () method without a thread: public lookuote e) {outputta.setText (""); string [] results = E.GETRESULTS (); for (int i = 0; i Also, for the WOKUPMANAGER incubation to incubation in a non-Swing thread environment is completely unnecessary, such as a non-drawing user interface, in our example, is Logger. An unnecessary new thread will damage the performance of your application, not to improve performance. LookupManager is performing very well, no matter whether Swing thread is - so I like to concentrate the code there. Now we need to perform the JButton's ActionListener to play the LOOKUP code in a non-Swing thread. We created an anonymous Thread, using an anonymous runnable to execute this lookup. Private void search button_actionperformed () {new thread () {public void run () {lookupManager.lookup (searchTf.getText ();}} .start ();} This completed our Swing thread. Simply add a thread to the actionPerformed () method, make sure the listener performs the entire thread problem in the new thread. Note that we don't have to handle any problems like the first example. By spending time in defining an event-driven system, we save more time on the switching thread related processing. Conclusion If you need to perform a lot of Swing code and non-Swing code in the same method, it is easy to place some code. The way the event drive will force you to place the code in what it should be there - it should only be there. If you execute a database call and update the UI component in the same method, you will write too much logic in a class. Analyze the events in your system, create the underlying event model will force you to put the code in the right place. Calling the time-tired database is placed in a non-UI class, or you do not update the UI component in the non-UI component. Using an event-driven system, the UI is responsible for the UI update, the database management class is responsible for the database call. At this point, each package is used only to care about your thread, don't worry about how the system is movable. Of course, the design, building an event-driven client is also useful, but it takes time to expect the flexibility and maintainability of the result system. Copyright Notice Is this article helpful? Vote: Yes No Vote: 10 0 Discussant: Hodex Participation: 123 Experts: 0 Posted: 2004-3-13 11:17 PM Very Good This article has 1 reviews, a total of 1 page Previous article Return [Topic: UI] Next article Word Advertising Link Several giant reports: Integrated Web Reporting System, full graphical design, comprehensive Struts architecture support Jamuchuang Network Report: Support Applet, DHTML, PDF output format, can be closely integrated with any J2EE server into Huardan Charisma report platform: Based on J2EE, MVC Speed Development Platform Custom WEB Report Engine About JR | Copyright Notice | Contact Us? 2002-2003 Java Research Organization Copyright