Buoy is a free User Interface (UI) toolkit above Swing, which provides convenient and simplicity for UI developers. In this paper, the author uses a simple Fractal user interface program to introduce what you can do, why do you do this. When I first tried to build a simple user interface with a Java language, I was surprised by the complexity of the SWING interface. Honestly, I want to fight back. Recently, a friend mentioned me that the rendering program he used (see Resources) Based on a different kit: Buoy. One of the reasons recommended is that it is more friendly. When he first mentioned it, I thought he was talking about "Bui", and it is similar to the name of GUI. Here B represents Better, but the name buoy is not an abbreviation. Buoy is free. In fact, it is a public thing. It does not release it under a permission of an open level, and it is actually not controlled at all. This means that you can use Buoy in any project written in Java language, without considering licensing issues. This toolkit is easy to modify and expand because of a complete source code. This article is based on the Buoy 1.3 release, requiring readers to have basic understanding of Swing, although it is not understandable. The sample program I have tried to finalize the first application built with Swing ended. In order to see the contrast between the toolkit, I decided to use Buoy to build this same program. The code example in the article is all of the Buoy version of the program. The program generated some fractals, specifically, it is an iterative fractal. Basic ideas are very simple: define a range of line sections on a plane, from (0, 0) to (1, 0), position around any one unit line. After drawing these sections, draw the same set of deformed lines, use this section as the unit vector. It is easier to say that it is as seen in Figure 1.
Figure 1. Fractal in the fractal editor
The interface of this program is quite simple. It has some interface widgets, with a canvas, draws a beautiful picture on the canvas, but also supports the mouse manipulation picture. In fact, all the work that must be done is to manipulate the point of the original curve, and the original curve will be iteratively drawn. There is also a minimized menu; it can turn the file, close the window, or save the current image as a file in the PNG format. Although it is simple, this interface briefly provides a reasonable example of a Buoy widget, as well as a considerable number of experiences for the event processing system. The actual core code of the program - Fractal generator - has been written, which turns this example into a good test program. Of course, in the process of updating it, I also found and patch some bugs. The release package contains the source code for the sample program, as well as compiled class files and buoy's JAR files (click the Code icon at the top of this article or the bottom icon, download factal.tar). The package also includes a directory called FRAC, which contains some sample fractals. If you use a UNIX style machine, there is a Java compiler in the path, then you can run it as soon as you run make. Otherwise, you need to set the classpath containing the directory where the current path and the JAR file of Buoy are set, and then run the FractalViewer class. On the Windows system, the correct command line should be java -classpath.; Buoy.jar FractalViewer. Sed-E S / J / B / G may form an impression in the first in-depth study of the code: Convert Swing code to the buoy code, simply simply as simple as the letter J in the UI element name. For example, the FractalViewer class no longer expands JFrame; it is now extended by bframe. The main small part name can also be speculated as this. Spinner and Slider have the same name as before, just changed a letter. MenuBar is still constructed by Menus, and the menu is accommodated for MenuItems. Some naming conversions are slightly different. In the place of Swing quote BorderLayout, Buoy has BorderContainer. In general, Buoy's naming conversion is quite unified, although not always named Swing. A obvious difference is that Buoy almost combines the concept of containers and layout managers; each container type knows how to lay out. This greatly simplifies the design. For example, the labelwidget class used in the fractal generator is a bordercontainer; in swing, this may be a JPanel with the BorderLayout Layout Manager. However, there are still many similarities between the two. This has a great help to adapt to new things. More importantly, Buoy builds above Swing. This means that, in general, if you need to do it, you can pass the Buoy object to the SWING object that it is packaged. For this case, if you want to access some Swing objects without Buoy counter, you can simply put it in the AWTWIDGET object. This object provides very thin wrapper, through it, not only Buoy's own widget, but also all Widgets can access the widget API of Buoy. For example, if you find that GridbagLayout is required, you may need this. For example, the FractalPanel class is an AWTWIDGET. In early design, it is a subclass of JPanel, but in fact I don't need JPanel code.
Instead, I built the class Fractalcanvas that packaged custom class, it itself is a subclass of ordinary Canvas classes. Turn it into an AWTWIDGET, you can use the Buoy's efficient event handling mechanism on it. Event processing code is very simple. When pressing the mouse button, BUOY sends a new mousepressed () function to the mousepressed () function via the Magic, Buoy, busepressed (). I ignored which button is pressed, just consider holding down the Shift click or ordinary click. Ordinary Click to select the closest point, and press and hold the Shift clicking, re-display the display. Then, if the mouse moves, each time buoy pays attention to the move, you will start sending a mousedraggedEvent event. FractalPanel generates your own event when processing these events. Jearly PointChangeDevent In order to make some discussion more specific, please come and see PointChangeDevent. This is a testic class. If you don't like it, it can only blame the old days. The idea of this class is to let a class indicate changes in the status point. The editor tracks "current" point - that is, the editor widget is currently being edited. You can use these widgets or click Select a new point in the fractal panel to select the closest point. I conclude that in the code, there are about three types involved in the point to send from a class to another class. One is the feature that changes a point: Point event type. If the editor is sent, it is to tell the fractal to change the point on the prototype line and ask the line. If the fractal is sent, it is to tell the editor's characteristics of the points just selected. The next is to choose a point. You can choose according to the index or position. So, if you only provide an index or location, the constructor will consider the intention to populate other values. There is a little special place, point index -1 is used to indicate that there is no selected point, so it is necessary to use -2 to indicate that the editor is looking for points in the specified location. This may not be beautiful, but effective. It is a bit means that the Fractal class responds to the way. If you have successfully selected a point, you will send back a new PointChangeDevent event, as shown in Listing 1. Listing 1. Answer event with an event
case PointChangedEvent.SELECT:if (e.getIndex ()> = -1) selectPoint (e.getIndex ()); elseselectPoint (e.getPoint ()); // just in case they do not knowevent (new FractalChangedEvent (FractalChangedEvent .SIZE, size)); if (selectedPoint> = 0 && selectedPoint this.addEventLink (MousePressedEvent.class, this, "mousePressed"); this.addEventLink (MouseReleasedEvent.class, this, "mouseReleased"); this.addEventLink (MouseDraggedEvent.class, this, "mouseDragged"); [...] Public void mouseeleased (widgetMouseEvent EV) {LastCenter = NULL; DispatChevent (new fractalchangedevent (fractalchangedevent.slow); setantialiasing (true);} mouseeleased () function is only available. It just cleans up after the mousepressed () function, telling the Fractal object to the time when it is fully renovated. Buoy's event handling has another interesting feature. If you prefer, you can create a new event type. An event type is a class. That's it. It doesn't even need to inherit any class or what is achieved. It is a class. If this class object is sent to DispatchEvent (), then it or its parent class listener will be called. You can also create new event types in Swing, but you must do your own; you must design the Listener interface, but also write your own code generation events and listen for events. In the sample program, the Fractal class is designed to demonstrate that the event processing function can be added to any original class relatively easily. Just declare a FractalViewer class to add a listener event source eventsource. The FractalViewer class sets the event link from the event source (such as fractaleditor) to their listeners, as shown in Listing 3. Listing 3. Binding private void tieEvents () {// Set up event handling relations.addEventLink (WindowResizedEvent.class, this, "layoutChildren"); addEventLink (WindowResizedEvent.class, panel, "repaint"); tieControlEvents (); tieFractalEvents (); TIEPANELEVENTS ();} The custom event class is generally to represent user behavior. In Buoy, it is generally only used by user behavior, not the system interface generation event - unless you want to explicitly call the dispatch generated by yourself. When the fractal object changes in a manner that can be updated in a field, all components will be notified. In this way, we invent a new class parameterchangedevent, use it to indicate that the parameters have changed. Alternatively, if the change is the location of the selected point or an index, a new PointChangedeevent is sent. If the behavior is sufficiently obvious, the event processor does not even need to accept parameters. As an example of event processing, please see Listing 4, which demonstrates the beginning of the parameterchanged () method of Fractaleditor. Listing 4. Changes in parameters void parameterChanged (ParameterChangedEvent ev) {FractalParameters p = ev.getParams (); int v = ev.getValue (); switch (ev.getType ()) {case ParameterChangedEvent.ALL: maxSlider.setValue (p.getMaxIterations ()); Minslider.setMaximum (p.getmaxiterations ()); minslider.setValue (p.getminiterations ()); MaxSlider.SetMinimum (p.Getminity); zoomslider.setValue (p.Getzoom ()); break; [... ] In this example, the event processing system passes the various information before and after. In previous versions, each class has references to other each class, and the messy GET method is sorted by day. In the current version, Buoy's event processing system is used to handle various notifications. For example, the FractalchangeDevent class can be used to let the other parts of the code know the modification of the fractal, which may be the number of points (the number of editor points is the point selector to define the correct spinnerNumbermodel), or the notification that needs to be redrawn, such as a list 5 shown. Listing 5. Obviously, when you redeemed Public void fractalchanged (fractalchangedevent e) {switch (E.GETTYPE ()) {case fractalchangedevent.redraw: repaint (); break;}} Buoy's documentation discussed in detail the difference between Swing event model and Buoy event model, and these differences the reason. There is a good reason, and the model of Buoy usually results in smaller, clearer code. Of course, you can still do extra or stupid things, just like it can be done in any system, but at least have a clean and beautiful interface when doing these things. I used to use a GUI tool for an afternoon. It is not long enough for one afternoon. For Buoy, I have a 6 hour or almost a whole day. I really got a great help from more experienced Buoy users. The experience of learning Swing before, but in fact, I don't think Swing experience is necessary. Buoy's document is quite good, and its simplicity is indeed helpful. For basic UI things, there is not much thing to learn. Buoy's documentation is not as complete as Swing documents, but overrides many details and very good. In addition, the source code is there, so answering some simple questions about the interface is very easy. It is of course a good thing with a more complete document. However, since this project is placed on the SourceForge, if you like, you can write more things to contribute to it. Buoy's learning curve is a big advantage than Swing. With a fairly simple interface, you can make most interface widgets correctly. To use an example in the Buoy document: In Swing, Jlist requires the use of a static list or build a new class that implements the ListModel interface. In Buoy, simply add a project to the list; in most common situations, the arduous work has been made by Buoy. Buoy is quite small. The complete release package contains source code, JAR files, and documents, with a total of less than 1 MB. The organization is well organized, which can easily find any particular code segment, and it is not difficult to adjust the design. BUG Although Buoy is a stable, useful system, it is not an absolutely perfect thing. Occasionally, it will have a very reasonable place, which will also have a strange manifestation, which has a surprising behavior. If you consider using Buoy to complete an actual project, you need to understand the bug: their universal, severity, and difficulty overcoming them. In the process of developing this app, I met something, at the time, it looked like a bug. But not all. Some may be bugs in the document - In these cases, the behavior of the code is not expected, but it is very reasonable. In fact, I can be very sure, from essentially, not Buoy bug, but they do have something that may encounter when debuging the Buoy application. After debugging a few days of code, I can be very sure, every obvious bug I have encountered is either my mistake, or I don't like the design decision in the underlying Swing. It is possible to say that these problems cannot be avoided in swing. The rolling bar scorpion I most often encountered a bug is when the scale tag in the ruler. Initially, I couldn't get the label displayed above. Listing 6. Make people depressed scroll code Minslider.setshowlabels (true); minslider.setmajortspacing (2); the code in Listing 6 does not work. It can be seen that the tag is only displayed after setting the scale pitch. If the scale spacing is not set before telling the scroll bar to display the label, it does not show any scales. More subtle is that the scale spacing can then be changed; the attempt to change the scale spacing has no effect. However, this is actually a bug bug, but a Swing work. Since the BSLIder class is just passing the request to JSLIDER, it is not fair. A more subtle, and the bug related to the underlying JSLider's problem occurs in aligning behavior. The construction function of the BSLider sets the secondary scale to 5, and the main scale is 20 - these two values are reasonable relative to the default size 100. However, when the scroll bar is created with 1-10, it does not see the secondary scale, so it can only be set to 1 main scales. As a result, a scroll bar having a scale value of 1-10, and only stays at 1 and 6; aligned behavior hinders the use of other values, because the alignment is the secondary scale rather than the main scale. Although this problem derived from JSLider, it happened in Buoy's default behavior, which will fix it in the upcoming version 1.4 release. Note that this is the only reason for me because the sample program is constantly updating some of the rolling bars. For example, if there is a line segment, only 50 iterations are allowed, then there is a bit more power to mark each number on the scroll bar. On the other hand, if only a few iterations are allowed, then some numbers don't look good. It is still very convenient to update the interface in a scroll bar. Menu Shortcut Key Buoy provides constructor for menu shortcuts with a character or keyboard event (KeyEvent). When I first test it, I can't let it work. It seems that you must use your lowercase; but you must replace 'W' with 'W' when you call the constructor, as shown in Listing 7. Listing 7. Add a CLOSE menu item Mi = New Bmenuitem ("Close", New Shortcut ('W')); Mi.SetActionCommand ("Close"); Mi.AddeventLink (CommandEvent.class, this, "Menuevent"); FileMenu.Add (MI); It may be necessary to handle the Java 5.0 SDK and 1.42 accidentally fuzzy. As a surface, if the uppercase letter is passed to the constructor, what is done is as expected. Light level problem - which set or modifier is to express Ctrl-? - A small free library can also be completely solved. The file selection is for some unaptimistic reasons, and when the new file selector is started on the Mac system, the Buoy defaults to the root directory. I made a detailed bug report, about how it looks like to miss a lot of files, but then I will recognize that I have moved my home directory from / users / seebs to / volumes / home / seebs, and the file The selector does display something on the disk. Score: Buoy 1, Seebs 0. I still want to know why it begins with the root of the file system. This may be a problem with JVM's Mac. Conclusion Buoy follows the famous ancient UNIX philosophy: 100% work to solve the problem of 90%. Buoy does not want to solve all the problems for everyone, but it can complete most of the work that interface users or designers need. It has the best license terms, and is still growing. Best, if you find it can't let you do something you do, you can study it, modify it, modify it, or modify the source code of Buoy, either call getComponent () and write your own Swing code. If you feel that a large UI tool is too terrible, then Buoy is a good choice. It allows simple UI to continue simply, and then leave complex code to need. In practice, a few code can be processed in a program that is more advantageous than buoy is more advantageous than buoy. This is a toolkit that let me spend time with Java for UI programming. this.addEventLink (MousePressedEvent.class, this, "mousePressed"); this.addEventLink (MouseReleasedEvent.class, this, "mouseReleased"); this.addEventLink (MouseDraggedEvent.class, this, "mouseDragged"); [...] Public void mousereleased (widgetMouseEvent EV) {LastCenter = NULL; DispatChevent (new fractalchangedevent (fractalchangedevent.slow); setantialiaSing (true);} The mouseeleased () function has only the least work to do. It just cleans up after the mousepressed () function, telling the Fractal object to the time when it is fully renovated. Buoy's event handling has another interesting feature. If you prefer, you can create a new event type. An event type is a class. That's it. It doesn't even need to inherit any class or what is achieved. It is a class. If this class object is sent to DispatchEvent (), then it or its parent class listener will be called. You can also create new event types in Swing, but you must do your own; you must design the Listener interface, but also write your own code generation events and listen for events. In the sample program, the Fractal class is designed to demonstrate that the event processing function can be added to any original class relatively easily. Just declare a FractalViewer class to add a listener event source eventsource. The FractalViewer class sets the event link from the event source (such as fractaleditor) to their listeners, as shown in Listing 3. Listing 3. Binding private void tieEvents () {// Set up event handling relations.addEventLink (WindowResizedEvent.class, this, "layoutChildren"); addEventLink (WindowResizedEvent.class, panel, "repaint"); tieControlEvents (); tieFractalEvents (); TIEPANELEVENTS (); Custom event classes are generally to represent user behavior. In Buoy, it is generally only used by user behavior, not the system interface generation event - unless you want to explicitly call the dispatch generated by yourself. When the fractal object changes in a manner that can be updated in a field, all components will be notified. In this way, we invent a new class parameterchangedevent, use it to indicate that the parameters have changed. Alternatively, if the change is the location of the selected point or an index, a new PointChangedeevent is sent. If the behavior is sufficiently obvious, the event processor does not even need to accept parameters. As an example of event processing, please see Listing 4, which demonstrates the beginning of the parameterchanged () method of Fractaleditor. Listing 4. Changes in parameters void parameterChanged (ParameterChangedEvent ev) {FractalParameters p = ev.getParams (); int v = ev.getValue (); switch (ev.getType ()) {case ParameterChangedEvent.ALL: maxSlider.setValue (p.getMaxIterations ()); Minslider.setMaximum (p.getmaxiterations ()); minslider.setValue (p.getminiterations ()); MaxSlider.SetMinimum (p.Getminity); zoomslider.setValue (p.Getzoom ()); break; [... ] In this example, the event processing system is used to pass the various information before and after. In previous versions, each class has references to other each class, and the messy GET method is sorted by day. In the current version, Buoy's event processing system is used to handle various notifications. For example, the FractalchangeDevent class can be used to let the other parts of the code know the modification of the fractal, which may be the number of points (the number of editor points is the point selector to define the correct spinnerNumbermodel), or the notification that needs to be redrawn, such as a list 5 shown. Listing 5. Obviously, public void fractalchanged (fractalchangedevent e) {switch (E.GETTYPE ()) {case (); break;}} Buoy's documentation discusses the difference between the Swing event model and the Buoy event model, and these differences. There is a good reason, and the model of Buoy usually results in smaller, clearer code. Of course, you can still do extra or stupid things, just like it can be done in any system, but at least have a clean and beautiful interface when doing these things. I used to use a GUI tool for an afternoon. It is not long enough for one afternoon. For Buoy, I have a 6 hour or almost a whole day. I really got a great help from more experienced Buoy users. The experience of learning Swing before, but in fact, I don't think Swing experience is necessary. Buoy's document is quite good, and its simplicity is indeed helpful. For basic UI things, there is not much thing to learn. Buoy's documentation is not as complete as Swing documents, but overrides many details and very good. In addition, the source code is there, so answering some simple questions about the interface is very easy. It is of course a good thing with a more complete document. However, since this project is placed on the SourceForge, if you like, you can write more things to contribute to it. Buoy's learning curve is a big advantage than Swing. With a fairly simple interface, you can make most interface widgets correctly. To use an example in the Buoy document: In Swing, Jlist requires the use of a static list or build a new class that implements the ListModel interface. In Buoy, simply add a project to the list; in most common situations, the arduous work has been made by Buoy. Buoy is quite small. The complete release package contains source code, JAR files, and documents, with a total of less than 1 MB. The organization is well organized, which can easily find any particular code segment, and it is not difficult to adjust the design. BUG Although Buoy is a stable, useful system, it is not an absolutely perfect thing. Occasionally, it will have a very reasonable place, which will also have a strange manifestation, which has a surprising behavior. If you consider using Buoy to complete an actual project, you need to understand the bug: their universal, severity, and difficulty overcoming them. In the process of developing this app, I met something, at the time, it looked like a bug. But not all. Some may be bugs in the document - In these cases, the behavior of the code is not expected, but it is very reasonable. In fact, I can be very sure, from essentially, not Buoy bug, but they do have something that may encounter when debuging the Buoy application. After debugging a few days of code, I can be very sure, every obvious bug I have encountered is either my mistake, or I don't like the design decision in the underlying Swing. It is possible to say that these problems cannot be avoided in swing. The rolling bar scorpion I most often encountered a bug is when the scale tag in the ruler. Initially, I couldn't get the label displayed above. Listing 6. Make people depressed scroll code Minslider.setshowlabels (true); minslider.setmajortickspacing (2); The code in Listing 6 does not work. It can be seen that the tag is only displayed after setting the scale pitch. If the scale spacing is not set before telling the scroll bar to display the label, it does not show any scales. More subtle is that the scale spacing can then be changed; the attempt to change the scale spacing has no effect. However, this is actually a bug bug, but a Swing work. Since the BSLIder class is just passing the request to JSLIDER, it is not fair. A more subtle, and the bug related to the underlying JSLider's problem occurs in aligning behavior. The construction function of the BSLider sets the secondary scale to 5, and the main scale is 20 - these two values are reasonable relative to the default size 100. However, when the scroll bar is created with 1-10, it does not see the secondary scale, so it can only be set to 1 main scales. As a result, a scroll bar having a scale value of 1-10, and only stays at 1 and 6; aligned behavior hinders the use of other values, because the alignment is the secondary scale rather than the main scale. Although this problem derived from JSLider, it happened in Buoy's default behavior, which will fix it in the upcoming version 1.4 release. Note that this is the only reason for me because the sample program is constantly updating some of the rolling bars. For example, if there is a line segment, only 50 iterations are allowed, then there is a bit more power to mark each number on the scroll bar. On the other hand, if only a few iterations are allowed, then some numbers don't look good. It is still very convenient to update the interface in a scroll bar. Menu Shortcut Key Buoy provides constructor for menu shortcuts with a character or keyboard event (KeyEvent). When I first test it, I can't let it work. It seems that you must use your lowercase; but you must replace 'W' with 'W' when you call the constructor, as shown in Listing 7. Listing 7. Add a Close menu item Mi = New Bmenuitem ("Close", New Shortcut ('W')); Mi.SetActionCommand ("Close"); Mi.AddeventLink (CommandEvent.class, this, "Menuevent"); FileMenu .add (mi);