SWT (Standard Widget Toolbox, Standard Widget Toolkit) is a window widget toolbox for use on the Eclipse platform. It can also be used as an important alternative to Swing / AWT to build any type of Java GUI application. As the Eclipse platform has become increasingly popular in the past two years, SWT has entered everyone's line of sight, and it has recently replaced Swing / AWT in some applications. The popularity of SWT originates from the fact that it is a cross-platform toolbox that utilizes the nature of widgets and has a powerful functionality that is equally Swing and other modern kits. With SWT, it is not necessary to make a handle between portability, function, and performance.
In fact, Swing / AWT is only significantly stronger than SWT in one aspect, which is Java 2D. Java 2D is a powerful API that is introduced in JDK 1.2. It allows Java developers to draw complicated two-dimensional transforms (translation, rotation, scaling, error, etc.) when drawing Java developers on AWT components. Unfortunately, Java 2D is designed to use only on the AWT or SWING toolbox, while SWT has not provided this extended two-dimensional ability. Therefore, many developers have found that they must choose to use Java 2D on the Java platform or to abandon its exciting features to use SWT.
However, you will learn how to have these two benefits at the same time. I will show a simple technique that utilizes this technology to draw Java 2D images on SWT components and DRAW2D images. In order to understand this example, the reader should be familiar with Java 2D, AWT, and SWT. It is also helpful with the experience of GEF (graphic editing framework, graphical editing framework) with some Eclipse platform.
Exterior Image Technology This article shows a simple technique that utilizes this technology, you can draw on any SWT window widget or DRAW2D image with Java 2D function. In order to make up for the lack of Java 2D, the Java 2D is received in an Ofscreen AWT image and convert them to the pixel value independent of the toolbox. Use another image of the SWT toolbox to draw these pixel information on any SWT component. Figure 1 shows a process of converting an AWT image converted to a SWT image and plotting on a small part of the SWT widget.
Figure 1. Exterior image technology allows Java 2D to be used on SWT
The external AWT image shown in Figure 1 is initialized to a transparent background. The Java 2D method is then called the graphical context of the image image. Like all AWT images, the graphical context of the external image is automatically supported Java 2D. After completing all Java 2D drawings, extract the pixel values of the AWT image and transmit it to a SWT image. This SWT image is then drawn on the SWT component with the GC.DRAWIMAGE (...) method of the toolbox, just like all normal images.
I will complete every step in this process in the following sections.
Create an image outside the AWT image to the AWT screen, you want to use the java.awt.image.bufferedImage instance. BUFFEREDIMAGE is an image that can access its pixel data through its API. The pixel value of the image is accessed, it can be converted to a SWT image later.
The easiest way to build an AWT buffer image is to use the constructor public bufferedImage (int Width, Int Height, Int iMageType). The first two parameters indicate the size of the image. The third parameter is the constant of the type of image to be created. Image Type - Possible Value is one of the constant type_xxx declared in class bufferedImage - indicating how the pixel value is stored in the image. In color images, the following most important image types are generally used: type_byte_indexed: This image type of image will use an index color model. The index color model means that each color used in the image is indexed in a set of colors. The pixel value only contains the index of this pixel in the color model. This type of image is limited to 256 colors - that is, the size of the color model. In this way, the pixel information can be used very compactly, because each pixel is only coded with one byte. TYPE_INT_RGB: This type constant indicates that the image uses a direct color model. The direct color model means that the value of each pixel contains complete information about its color. TYPE_INT_RGB indicates that each pixel is encoded with an integer (four bytes). The information encoded in each pixel is the red, green and blue (RGB) component of this pixel. Each color component is encoded in one byte. Since the entire pixel value is encoded with four bytes, there is a byte that is not used. The internal representation of such an image is four times that of the image using the index color model, but the number of colors that can be used in such an image increased to 1 million (256 x 256 x 256). TYPE_INT_ARGB: Like Type_INT_RGB, this type of image uses a direct color model and encodes each pixel with four bytes. Different, the fourth byte is not used with Type_INT_RGB, which is also called the alpha component of the color. This type of image can have a transparent background or translucent.
In order to make the exterior image technology work, it is necessary to transfer only pixels that are affected by Java 2D to the surface of the SWT component. In order to ensure this, the initial image must have a transparent background. Therefore, the buffer image type used is type_int_argb for the AWT screen image.
The next step of drawing and extracting an image This process is to draw an image with Java 2D. First get its Graphics2D context. This can be used to do this with method CreateGraphics2D () or call getgraphics (). Drawing the pixel data of the image will be automatically modified on this context. After the drawing is completed, the image is easily and efficiently extracted with the method GETRGB (int Startx, Int Starty, Int Offset, INT Scansize). This method can transfer pixel data in the rectangular area in the image to an integer array. The parameters of the getRGB () method are as follows:
STARTX, Starty is the coordinates of the image of the area to extract. W, H is the width and height of the area to be extracted. Rgbarray is an integer array of receiving pixel values. Offset is an index of the location where the first pixel value is received. ScanSize is an index offset value of pixels having the same row index in the image in the image. If this value is the same as the width of the area to be extracted, the first pixel of a row is stored in the index position behind the last pixel in the array. If this value is greater than the width of the extraction area, there will be some unused indexes between the final and the next row.
Storage pixel data Figure 2 shows how bufferedImage.GetrGB (...) fills the entire buffer after extracting the rectangular area of the AWT image. The part below represents an integer buffer. Each box represents a value including a 4-byte arbg value in the buffer. The numbers in parentheses indicate the coordinates of the pixels in the image.
Figure 2. Extracting pixel values from the AWT image In this case, do not use any OFFSET, which means that the first pixel will be saved in the position of the buffer index 0. Scansize's value takes the width of the area to be extracted, which means that the first pixel in the extracted row will then follow the last pixel buffer position of the previous line. Using these parameters, the buffer of integers will be large enough, which can contain w * h integers.
When the color information of each pixel is stored in an integer's simple buffer, you can transfer this information to the SWT screen image.
Create a SWT image SWT Image is similar to the AWT BufferedImage because its pixel data can be accessed directly or write. This means that any pixel or any set of pixels in the image can be set or acquired by direct reading or modifying data of the image. However, the SWT API is very different from the corresponding API and is more likely to use.
The Image of the SWT provides several constructor that can complete the following tasks:
By passing a file name or an InputStream as a parameter to the constructor load an existing image. The format of the image must be one of the supported formats: BMP, GIF, JPG, PNG, Windows ICO, etc. Constructs an empty image specifying the size. This image can be drawn by modifying its pixel value or copying the content (GC) of a SWT graphic context. A image of an existing buffer using a pixel value is constructed.
You will create a SWT image using the third constructor, which is a copy of the AWT image.
Information about the image of the ImageData class is included in its imageData. ImageData is a class containing image sizes, palettes, color values, and transparency information. You should pay special attention to the following imageData fields:
Width and Height specify the size of the image. DEPTH Specifies the color depth of the image. The possible value is 1, 2, 4, 8, 16, 24 or 32, specifying the number of digits used by the value of each pixel. The Palette contains a Palettedata object that stores information about the color model of the image. Like AWT, the color model of the SWT can be an index or direct. If the color model is index, then the Palettedata contains a color index. If it is direct, it contains the shift information indicating how the color RGB component should be extracted from the integer value of the pixel. DATA contains a byte buffer containing a pixel value. Unlike the AWT buffer, the SWT buffer is not an array of integer arrays that contain a color value of each pixel. Instead, it contains the byte value. The method of byte encoding depends on the colors used. For an 8-bit image, one byte in the array acts represents the value of one pixel in the image. For 16-bit images, each pixel value is encoded as two bytes in the buffer. These two bytes are stored in the minimum valid byte order. For 24 or 32-bit images, each pixel value is encoded in the highest effective bit byte order to three or four bytes in the buffer. BYTESPERLINE indicates how many bytes in the buffer are used to write all pixels in the image in the image. TransParentPixel defines pixel values for transparency in the image.
We will use a 24-bit image with a transparent color channel. Each pixel in the image is encoded as three bytes in the array, and the order is red, green and blue ingredients.
The converted image knows the image data to easily convert the AWT image to the SWT image. The byte buffer used by the integer buffer (by the AWT image returned) integer buffer is converted to the SWT image. Figure 3 shows how these values are stored in the buffer in the SWT image.
Figure 3. Write the pixel value to the SWT image
As in FIG. 2, the following portion below shows the internal representation of the image buffer. The numbers in parentheses are displayed in the coordinates of the pixel representing their color values in the buffer. Although each pixel is encoded in three bytes, for a 24-bit image, the size of a row of pixels in the buffer is not always 3 * width. There may be some indexes between the two lines pixels in the buffer. To know how many bytes of each line of pixels in the image (this can beware of which index position starting from the next row in the buffer), you must use the BYTESPERLINE value of the imagedata field.
SWT to Java 2D Renderer Listing 1 Displays the source code of the general renderer that implements the external image technology. This renderer can use Java 2D routines when drawing on SWT components or DRAW2D images.
Listing 1. SWT / DRAW2D Java 2D Renderer
Package swtgraphics2d;
Import java.awt.graphics2d;
Import java.awt.image.bufferedImage;
Import org.eclipse.swt.graphics.gc;
Import org.eclipse.swt.graphics.image;
Import org.eclipse.swt.graphics.imagedata;
Import org.eclipse.swt.graphics.palettedata;
Import org.eclipse.swt.widgets.display;
/ **
* Helper Class Allowing The Use of Java 2D on Swt or Draw2d Graphical
* context.
* @Author Yannick Saillet
* /
Public class graphics2drenderer {
Private static final palettedata palette_data =
New Palettedata (0xff0000, 0xFF00, 0xFF);
Private bufferedimage.
Private image swtimage;
Private imagedata swTimageData;
Private int [] awtpixels;
/ ** RGB Value To Use as transparent color * /
Private static final int transparent_color = 0x123456;
/ **
* Prepare to Render On A SWT Graphics Context.
* /
Public void preparerendering (GC GC) {
Org.eclipse.swt.graphics.Rectangle Clip = gc.getclipping ();
Preparerendering (Clip.x, Clip.y, Clip.Width, Clip.Height);
}
/ **
* Prepare to Render on a Draw2d Graphics Context.
* /
Public void preplerendering (org.eclipse.draw2d.graphics graphics) {
Org.eclipse.draw2d.geometry.Rectangle Clip =
Graphics.getClip (new org.eclipse.draw2d.geometry.Rectangle ());
Preparerendering (Clip.x, Clip.y, Clip.Width, Clip.Height);
}
/ **
.
* /
Private Void Preparerening (int CLIPX, INT Clipy, int CLIPW, INT CLIPH) {
// Check what the offscreen images area in initized and large enough
CheckoffScreenImages (Clipw, Cliph);
// Fill The Region in The AWT Image with The Transparent Color
Java.awt.graphics awtgraphics = awtimage.getgraphics ();
AWTGRAPHICS.SETCOLOR (New Java.awt.color (Transparent_Color);
AWTGRAPHICS.FILLRECT (CLIPX, Clipy, Clipw, Cliph);
}
/ **
* Returns the graphics2d context to use.
* /
Public graphics2d getgraphics2d () {
IF (AWTIMAGE == Null) Return NULL;
Return (Graphics2D) AWTIMAGE.GETGRAPHICS ();
}
/ **
* Complete the rendering by flushing the 2D renderer on a swt graphhical
* context.
* /
Public void render (GC GC) {
IF (AWTIMAGE == Null) Return;
Org.eclipse.swt.graphics.Rectangle Clip = gc.getclipping ();
Transferpixels (Clip.x, Clip.y, Clip.width, Clip.Height);
GC.DrawImage (Swtimage, Clip.x, Clip.y, Clip.width, Clip.height,
CLIP.X, Clip.y, Clip.Width, Clip.Height;
}
/ **
* Complete the rendering by flushing the 2D renderer ON A Draw2d
* Graphical context.
* /
Public void render (org.eclipse.draw2d.graphics graphics) {
IF (AWTIMAGE == Null) Return;
Org.eclipse.draw2d.geometry.Rectangle Clip =
Graphics.getClip (new org.eclipse.draw2d.geometry.Rectangle ());
Transferpixels (Clip.x, Clip.y, Clip.width, Clip.Height);
Graphics.drawImage (Swtimage, Clip.x, Clip.y, Clip.Width, Clip.height,
CLIP.X, Clip.y, Clip.Width, Clip.Height;
}
/ **
* Transfer A Rectangular Region from the a'...
* /
Private Void Transferpixels (int CLIPX, INT CLIPY, INT CLIPW, INT CLIPH) {
INT Step = SwtimageData.Depth / 8; Byte [] Data = SwtimageData.Data;
AWTIMAGE.GETRGB (Clipx, Clipy, Clipw, Cliph, AWTPIXELS, 0, CLIPW);
For (int i = 0; i INT IDX = (Clipy i) * SwtimageData.Bytesperline Clipx * Step; For (int J = 0; j Int rgb = awtpixels [j i * clipw]; For (int K = SWTIMAGEDATA.DEPTH - 8; K> = 0; k - = 8) { DATA [IDX ] = (Byte) ((RGB >> K) & 0xFF); } } } IF (SWTIMAGE! = null) SWTIMAGE.DISPOSE (); SWTIMAGE = New Image (Display.getDefault (), SWTIMAGEDATA); } / ** * Dispose the resources attached to this 2D renderer. * / Public void dispose () { IF (AWTIMAGE! = NULL) AWTIMAGE.FLUSH (); IF (SWTIMAGE! = null) SWTIMAGE.DISPOSE (); AWTIMAGE = NULL; SWTIMAGEDATA = NULL; AWTPIXELS = NULL; } / ** * Ensure That The Offscreen Images Are Initialized and Area At Least * as large as the size given as parameter. * / Private Void CheckoffScreenImages (int width, int hotht) { INT currentImageWidth = 0; INT currentImageheight = 0; IF (SWTIMAGE! = NULL) { CurrentImageWidth = SWTIMAGE.GETIMAGEDATA (). width; CurrentImageHeight = SWTIMAGE.GETIMAGHTA (). HEIGHT } // if the offscreen images are too small, recreate them IF (Width> CurrentImageWidth || Height> CurrentImageHeight) { Dispose (); Width = Math.max (Width, CurrentImageWidth); Height = Math.max (Height, CurrentImageHeight); AWTIMAGE = New BufferedImage (Width, Height, BufferedImage.Type_INT_ARGB); SWTIMAGEDATA = New ImageData (Width, Height, 24, Palette_Data); SWTIMAGEDATA.TRANSPARETPIXEL = Transparent_color; AWTPIXELS = New Int Int IntTH * Height]; } } This renderer is included in a utility class. This class contains and manages references to the AWT and SWT screens required for the external image technology. Also pay attention to: Fields SWTIMAGEDATA and AWTPIXELS are buffers that contain pixel values of the SWT image when the pixel is transferred, respectively, respectively, respectively, and a buffer for pixel values of the AWT image. Constant TRANSPARENT_COLOR contains an RGB value as a transparent color in an SWT image. Because the color as the transparency channel must be defined to draw a background, you must keep a color value for this. In the code, I used the random value 0x123456. All pixels that use this color value are transparent. If the color represented by this value is likely to be used in the drawing operation, it can be used to represent the transparency with another value. The renderer works the work process of the SWT / DRAW2D Java 2D renderer: Before you can use the renderer, it is necessary to initialize the external image and buffer in the same size as the area to be drawn. This is done by calling method prepererendering (...). According to the SWT or DRAW2D graphics context, this method is used as a SWT GC or a Draw2D Graphics object as a parameter. Next, Preparerendering is extracted from the graphical context - the clip rectangle is the maximum rectangular area of the pixel. Then call the private method prepererendering (int CLIPX, INT CLIPY, INT CLIPW, INT CLIPH), ready to render the exterior image. This method is independent of the type of graphical context used, which can be SWT or DRAW2D. The process of the precherendering () method is as follows: It first checks that the AWT and SWT screens are instantiated and sufficient to include the area to be drawn, which is done by the method CheckoffScreenImages (Clipw, Cliph). If the external image has been instantiated, it is not large enough, it will be discarded and recreate one with the required size. If the external image is greater than the area to be drawn, then it will be reused and only modify the part of the area corresponding to the area to be drawn. After this test is completed, the color transparent_color reserved for the transparency channel is filled with the drawing area. This image can be used to perform Java 2D operation. When the renderer is ready to perform Java 2D drawing operation in the critical area, you can get Java 2D Graphics2D context from BufferedImage AWT. This graphic context will be used for all Java 2D drawing routines. Modify an AWT image outside each time you draw. When all Java 2D drawing operations are completed, the pixels of the drawing area must be converted from AWT to the SWT screen image, and then draw to the SWT or DRAW2D graphics context. This operation is done by method render (GC) or RENDER (Graphics). Both methods are internally calling Private Method Transferpixels (...), which converts pixels from AWT to SWT. If the renderer is no longer required or the resource must be released, the Dispose () method can be called to clear the exterior image and buffer used by the renderer. This will release resources, but take time to recreate buffers when you need renderer again. DISPOSE () should be called based on the frequency of resection of the component and the redrawing zone should be used to determine when it is called. One Example Listing 2 shows how to draw some rotation text on SWT Canvas with a renderer. Listing 2. Examples of use on SWT Canvas Canvas canvas = new canvas (shell, swt.no_backround); Final Graphics2drenderer RENDERER = New Graphics2drenderer (); Canvas.addpainTlistener (New PainTlistener () { Public void PaintControl (Paintevent E) { Point controlsize = ((control) E.GETSOURCE ()). GetSize (); GC GC = E.GC; // Gets The SWT Graphics Context from the Event RENDERER.PREPArerendering (GC); // Prepares The Graphics2D Renderer // Gets the graphics2d context and switch on the antialiasing Graphics2d g2d = renderer.getgraphics2d (); g2d.sethrenderingHint (RenderingHints.Key_Text_antialiaSing, RenderingHints.Value_text_ntialias_on); // Paints The Background with a color gradient G2d.SETPAINT (New GradientPaint (0.0F, 0.0F, Java.awt.color.Yellow, (Float) Controlsize.x, (float) Controlsize.y, java.awt.color.white)); G2D.FillRect (0, 0, Controlsize.x, Controlsize.y); // Draws Rotated Text G2d.SetFont (New Java.awt.Font ("Sansserif", Java.awt.Font.Bold, 16); g2d.setcolor (java.awt.color.blue); G2d.Translate (Controlsize.x / 2, Controlsize.y / 2); INT nbofslices = 18; For (INT i = 0; i g2d.drawstring ("Angle =" (i * 360 / nbofslices) "/ u00b0", 30, 0); g2d.rotate (-2 * math.pi / nbofslices); } // Now That We Are Done with Java 2D, Renders Graphics2D Operation // on the SWT graphics context RENDERER.Render (GC); // Now We can Continue with Pure Swt Paint Operations gc.drawoval (0, 0, Controlsize.x, Controlsize.y); } }); Code description: Create a renderer and reuse it while you need to reagent to Canvas. Instance the drawings and add a PaintListener on it to perform the drawing operation. Get the graphic context GC from Paintevent. The renderer is prepared in the graphical context, which means that the external image can be accepted. In the next step, the Java 2D graphic context G2D is obtained. A set of Java 2D drawings is then implemented to draw background with gradient colors and draw a rotating text every 20 degrees. This process uses the pan and several rotations of the graphic context. Finally, the Render (GC) method is called to transfer the Java 2D to the SWT graphics context. Java 2D and pure SWT plotting can be used in the same drawing routine. The result of the result of the rendering operation is shown in Figure 4. In this example, the renderer is not discarded, and it can be repeatedly used to reuse the external image and internal buffer each time you draw Canvas, which saves the time of instantiation and garbage collection. Remember, if the canvas do not need to be reploth frequently, and the resources occupied by the renderer are very important, then the renderer can be discarded after each drawing. Figure 4. Example: Help draw SWT with Java 2D routine Listing 3 shows how to implement the same example in the DRAW2D image. Here is the method of drawing Figure by covering the method PaintClientarea (Graphics). The use of Graphics2drenderer is exactly the same as the previous example. The only difference is that the method prepererendering and render are called with a Draw2D Graphics instead of a SWT GC as a parameter. Listing 3. Example of using the Draw2D chart Final graphics2drenderer renderer = new graphics2drenderer (); IFigure first = new figure () { Protected void PaintClientarea (org.eclipse.draw2d.graphics graphics) { Dimension Controlsize = getSize (); Renderer.preparerendering (graphics); // Prepares the graphics2d renderer // Gets the graphics2d context Graphics2d g2d = renderer.getgraphics2d (); (...) // does the java 2d painting // Now That We Are Done with Java 2D, Renders Graphics2D Operation // on the drast graphics context RENDERER.RENDER (Graphics); // Now We CAN Continue with Pure Draw2D Paint Operations Graphics.drawoval (0, 0, Controlsize.width, Controlsize.width); } } Conclusion The simple technique of this document is made to integrate the Java 2D function into the SWT and GEF applications and are quite easy. Step step on how to combine the best features of SWT and Java 2D and draw the results on any SWT component or GEF DRAW2D image. The technique shown here is like code examples: only one line of code can be implemented, do not need to rely on any external library, and do not need to start an AWT thread.