Summary
SWT's Image class can be used to display images in a GUI. The most common source of images is to load from a standard file format such as GIF, JPEG, PNG, or BMP. Some controls, including Buttons and TreeItems, are able to display an Image directly through the setImage(Image) method, but any control's paint event allows images to be drawn through the callback's graphic context. SWT's ImageData class represents the raw data making up an SWT Image and determines the color for each pixel coordinate. This article shows the correct uses of ImageData and Image, shows how to load images from files, and how to achieve graphic effects such as transparency, alpha blending, animation, scaling, and custom cursors.By Joe Winchester, IBM
September 10th, 2003
This first section of this article gives an introduction to colors and showshow an image records the color value of each pixel.
The next section describes image transparency, alpha blending, animation, andhow to scale images.Finally, the article shows how to create cursors from images, by using a sourceimage together with a mask.Image image = new Image(display,
"C:/eclipse/eclipse/plugins/org.eclipse.platform_2.0.2/eclipse_lg.gif");
Instead of hard-coding the location of the image, it's more common to loadthe Image from a folder location relative to a given class. This is done bycreating an InputStream pointing to the file with the method Class.getResourceAsStream(Stringname), and using the result as the argument to the constructor Image(Displaydisplay, InputStream inputStream).
The Eclipse package explorer below shows the class com.foo.ShellWithButtonShowingEclipseLogoand the eclipse_lg.gif in the same folder. To following code wouldload the graphic from its location relative to the class.
Image image = new Image(display,
ShellWithButtonShowingEclipseLogo.class.getResourceAsStream(
"eclipse_lg.gif"));
Once the image has been created it can be used as part of a control such as aButton or Label that is able to render the graphic as part of their setImage(Imageimage) methods.
Button button = new Button(shell,SWT.PUSH);
button.setImage(image);
Images can be drawn onto using a graphics context that is created with theconstructor GC(Drawable drawable) with the Image as the argument.
GC gc = new GC(image);
gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
gc.drawText("I've been drawn on",0,0,true);
gc.dispose();
Using a GC to draw onto an Image permanently alters the graphic. Moreinformation on how to use a GC is covered in the article GraphicsContext - Quick on the draw.
As well as loading an Image directly from a file, you can separately create the ImageData object and then construct the Image using Image(Device device, ImageData imageData). The data for an existing Image can be retrieved using getImageData(), although this will not be the same object that was used to create the image. This is because when preparing an image to be drawn onto a screen, properties such as its color depth might be different from the initial image data.
Instances of Image represent an underlying resource that has been preparedfor a specific device and they must be disposed when they are no longer requiredto free up the allocated resource. There is no finalization of resources in SWTwhen an object is garbage collected. For more information see SWT:The Standard Widget Toolkit: Managing Operating System Resources.
The next section describes how colors are representedby their RGB values, and how PaletteData maps a mappixel value to a particular color.
Color cyanColor = new Color(display,0,255,255);
// ... Code to use the Color
cyanColor.dispose();
The convenience class org.eclipse.swt.graphics.RGB exists in SWTthat combines a color's red, green and blue values into a single object.
RGB cyanRGB = new RGB(0,255,255);
Color cyanColor = new Color(display,cyanRGB);
// ... Code to use the Color
cyanColor.dispose();
The Color instance should be disposed when it is no longer required, whereasthe RGB has no need to be disposed. This is similar to the relationship betweenan Image and its ImageData, where Color and Image are device specific objectsusing underlying native resources, while RGB and ImageData are the underlyingmodel data.
To avoid having to create and manage instances of the commonly used colors,the Display class allow these to be retrieved using the method Display.getSystemColor(intid).
Color cyanColor = display.getSystemColor(SWT.COLOR_CYAN)
When a Color is obtained by an SWT program using the method Display.getSystemColor(intid) method, it must not be disposed. The rule of thumb that works for anySWT resource is "If you created it, you are responsible for disposing it".Because the statement above retrieved the cyan color instance, and didn'texplicitly construct it, it should not be disposed.
How a Color is actually represented on the display depends on factors such as the resolution and depth of the display. For more information on this and the SWT color model see SWT Color Model.
The example below is a 48 by 48 square image created with a depth of 1, and an indexed color palette. The indexed palette assigns
The above example has a depth of 1 so it can store 2 colors, but as the color depth of the ImageData increases then so can the number of colors in the palette. An indexed palette can have a 1, 2, 4, or 8 bit depths, and an 8 bit depth provides 2^8 = 256 possible colors. To have a higher color depth (such as 16, 24, or 32) a direct palette must be used.
The value for each pixel represents a combination of the red, green and bluecomponents into a single 24 bit integer. To construct an indexed palette theconstructor used
Using the same technique as earlier, the code iterates over every pixel coordinate setting it to either
for (int x=0;x<48;x++){
for(int y=0;y<48;y++){
if(y >11 && y < 35 && x > 11 && x < 35){
This creates the result below where the image is red with a green center.
Because you can use color depths of 16, 24 and 32 bits with direct palettes, you can represent more colors than are available with an indexed palette whose maximum depth is 8. A color depth of 24 allows you to represent 16 million colors (2^24). The tradeoff however is size, because an indexed palette with a depth of 8 requires one byte per image coordinate whereas a direct palette with a depth of 24 requires three bytes per image coordinate.
With both direct and indexed palettes you can go from an RGB to a pixel valueand vice-versa using the public methods int getPixel(RGB rgb) and RGB getRGB(intpixelValue).
When Images are used directly on controls such as Button or Label the nativebehavior may be that transparent pixels are ignored and drawn in the pixel colorspecified by the source. Native image transparency however is supported in SWTfor operations involving a GC. To illustrate this the following file Idea.gifhas a color depth of 8, and the white pixel (index 255 in the palette) set to bethe transparent pixel.
The shell below has a Label on the left with a Canvas next to it. TheIdea.gif is used
Image ideaImage = newImageData(getClass().getResourceAsStream("Idea.gif"));
Label label = new Label(shell,SWT.NONE);
For the above example I stacked the deck in my favor, because I didn'tactually use the idea graphic that is included with eclipse articles in theirbanner. The reason is that the original graphic is a JPG file which doesn'tsupport transparency, so I used a graphics tool to convert it to a GIF and setthe value of the white pixel in the palette to be the transparency pixel. Theoriginal Idea.jpg is shown below, and although it looks the same as theIdea.gif, this is because it is on the white background of the HTML browser.
By using the original JPG file this offers a good example of how we toachieve a transparency effect progrmatically by manpulating its ImageData. TheImageData class has a public field transparentPixel to specify whichpixel is transparent that can be set once a persisted image file is loaded intoan ImageData instance, irrespective of whether the persisted file formatsupports transparency.
The code below loads the Idea.jpg file in an ImageData object and
ImageData ideaData = new ImageData(
getClass().getResourceAsStream("Idea.jpg"));
Next a Shell uses the newly created image
Label transparentIdeaLabel = newLabel(shell,SWT.NONE);
As can be seen from the second of the two images (drawn on the Canvas with the white pixel set to transparent), there are still some patches of white. Closer analysis reveals that this is not a bug, but that these regions are not pure white (255,255,255), but are slighly off-white (such as 255,254,254). The transparent pixel of an ImageData can only be used for a single value. This now presents the next problem to be solved - locate all of the off-white pixels in the ImageData and convert them to pure-white. To do this we will iterate over each pixel in the image data and modify those that are close to white to be pure white.
The first step is to load the image and then iterate over each pixelindividually looking at its color. Because Idea.jpg is using a direct palette,the pixel value is an int that contains the red, green and blue component asmasked bit areas. These mask value can be obtained from the palette.
ImageData ideaImageData = new ImageData(
getClass().getResourceAsStream("Idea.jpg"));
int redMask = ideaImageData.palette.redMask;
int blueMask = ideaImageData.palette.blueMask;
int greenMask = ideaImageData.palette.greenMask;
For any pixel value we can bitwise AND it with the mask to see what the colorcomponent is. The red component is the low order bits so this will be the actualvalue (from 0 to 255), however the green and blue values need adjusting as theyare the high order bits in the pixel value. To make this adjustment the colorcomponent can be bit shifted to the right using the >> operator. If youare writing generic code to do this kind of manipulating, take care that directpalettes for color depths of 24 or 32 store their color components with redbeing the low order bits, however for color depth of 16 the colors are reversedand red is high order with blue being low order. The reason for this is to bethe same as how Windows stores images internally so there is less conversionwhen creating the image.
Two for loops will iterate over the imageData. The first is traversing theimage from top to bottom a line at a time, and
Having manipulated the raw bytes making up the ImageData we have nowsuccessfully changed the off-white values to pure white.
ImageLoader imageLoader = new ImageLoader();
imageLoader.data = new ImageData[] {ideaImageData};
imageLoader.save("C:/temp/Idea_PureWhite.jpg",SWT.IMAGE_JPEG);
The finished result is shown below.
It doesn't look much different to the original Idea.jpg because it is drawnon a white background, but when it is drawn on a Canvas with the white pixel setto be the transparent pixel the background shows through achieving the desiredeffect.
ImageData pureWhiteIdeaImageData =
new ImageData("C:/temp/Idea_PureWhite.jpg");
We have shown how an ImageData is an array of int values representing eachpixel coordinate, and how each pixel value is mapped to a color through thepalette. This allowed us to iterate over the image data for the Idea.jpg, querypixel values that were close to white, and convert these to a pure white RGBvalue. The end result of this was that we were able to create theIdea_PureWhite.jpg file that can be used as a transparent JPG by setting thewhite pixel to be transparent. Transparency works by having a source pixel value(the image being drawn), a destination pixel value (the image being drawn onto)and a rule by which the resulting destination pixel value is determined. Fortransparency the rule is that the source pixel value is used unless it'stransparent in which case the destination pixel is used. Another technique is touse alpha values that specify the weight applied to the source relative to thedestination to create the final pixel value. This allows the blending betweenthe source image and the existing background it is being drawn onto.
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
ImageData imageData = newImageData("C:/temp/Idea_PureWhite.jpg");
Canvas canvas = newCanvas(shell,SWT.NO_REDRAW_RESIZE);
canvas.addPaintListener(new PaintListener() {
public voidpaintControl(PaintEvent e) {
e.gc.drawImage(fullImage,0,0);
e.gc.drawImage(halfImage,140,0);
e.gc.drawImage(quarterImage,280,0);
}
});
The following code creates
ImageData fullImageData = newImageData("C:/temp/Idea_PureWhite.jpg");
int width = fullImageData.width;
int height = fullImageData.height;
The resulting image is shown below, and the alphaData byte[] makesthe top of the image transparent and the bottom opaque, with a gradual fadingbetween the two.
To create an effect based on an existing image and a style flag use theconstructor Image(Display display, Image image, int flag). The flagargument is a static constant of either SWT.IMAGE_COPY, SWT.IMAGE_DISABLE orSWT.IMAGE_GRAY. Copy creates a new image based on the original but with a copyof its imageData, whereas Disable and Gray create a new image applying platformspecific effects. The following code shows the Idea.jpg, together with threemore images that we created using the style bits
Image ideaImage = new Image(display,
getClass().getResourceAsStream("/icons/Idea.jpg");
While the web browser you're using to read this article should show the Idea_SWT_Animation.gif file as a sequence with the moving pen, this is not true of native SWT controls displaying the graphic. The animation must be done programmatically, and the class org.eclipse.swt.examples.ImageAnalyzer shows how this can be achieved. The ImageAnalyzer class can be obtained from the SWT examples project in the Eclipse CVS repository.
When an animated GIF is loaded by the ImageLoader class, each individualframe is a separate element in the data field array typed to ImageData[]. In the animation sequence each ImageData records how many milliseconds it shouldbe displayed for in the int field delayTime. The number of times the sequenceshould repeat can be retrieved from the field loader.repeatCount, a value of -1indicates that the animation should repeat indefinitely andIdea_SWT_Animation.gif has this value. When switching from one frame to the nextthere are three ways that the new frame can replace the previous one, specifiedby the int field ImageData.disposalMethod. This can take the following valuesdefined in the constant class org.eclipse.swt.SWT.
DM_FILL_NONE | Leave the previous image in place and just draw the image on top. Each frame adds to the previous one. |
DM_FILL_BACKGROUND | Fill with the background color before painting each frame. The pixel value for this is defined in the field loader.backgroundPixel |
DM_FILL_PREVIOUS | Restore the previous picture |
DM_FILL_UNSPECIFIED | No disposal method has been defined |
To conserve on space, animated GIFs are generally optimized to just store thedelta that needs to be applied to the previous image. In theIdea_SWT_Animation.gif above the 15 frames are shown below. Each frame stores adelta against the previous image, and this was automatically generated by thetool I create the animated GIF with. The disposal method for each frame isDM_NONE so the each image should be drawn on top of the previous one. Eachindividual ImageData element has the x and y for its top left corner, as well asits width and height. The overall size to use can be obtained from the fieldsloader.logicalScreenWidth and loader.logicalScreenHeight.
To illustrate how to display an animated GIF in SWT we'll create an
ImageLoader loader = new ImageLoader();
loader.load(getClass().getResourceAsStream("Idea_SWT_Animation.gif"));
Canvas canvas = new Canvas(shell,SWT.NONE);
The body of the example will create a thread that iterates through eachframe, waiting until the
Thread thread = new Thread(){
public void run(){
long currentTime =System.currentTimeMillis();
int delayTime =loader.data[imageNumber].delayTime;
The following code loads the Idea.jpg image
The end result is shown below, and both techniquesproduce almost identical results.
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
When to use GC scaling, and when to use ImageData.scaledTo(...), depends on the particular scenario. The GC scaling is faster because it is native, however it does assume that you have a GC and an Image to work with. Using just the ImageData means that you don't need to have prepared an Image (that requires a native resource and requires disposing), and an ImageData can be loaded directly from a graphic file (using the constructor ImageData(String fileName) or ImageData(InputStream stream)). By using raw ImageData you are delaying the point at which you will need native display resources, however you will eventually need to create an Image from the scaled ImageData before it can be rendered onto a device.
Cursors can be created in two ways, either from a pre-defined style or usingsource and mask images.
CURSOR_APPSTARTING | ![]() | CURSOR_IBEAM | ![]() | CURSOR_SIZENE | ![]() |
CURSOR_ARROW | ![]() | CURSOR_NO | ![]() | CURSOR_SIZENESW | ![]() |
CURSOR_CROSS | ![]() | CURSOR_SIZEALL | ![]() | CURSOR_SIZENS | ![]() |
CURSOR_HAND | ![]() | CURSOR_SIZEE | ![]() | CURSOR_SIZENW | ![]() |
CURSOR_HELP | ![]() | CURSOR_SIZEN | ![]() | CURSOR_SIZESNWSE | ![]() |
CURSOR_SIZES | ![]() | CURSOR_SIZESE | ![]() | CURSOR_SIZESW | ![]() |
CURSOR_SIZEWE | ![]() | CURSOR_UPARROW | ![]() | CURSOR_WAIT | ![]() |
Every Control can have a cursor associated with it, and when the mousepointer moves over the control it changes to the specified cursor. Changing a cursor also affects any child controls, so if you update the cursoron a Shell this affects the mouse pointer for anywhere on the shell, although ifthe child control itself has an explicit cursor, or uses its own cursor such asan I bean for Text or Combo, this takes precedence over the parent's definedcursor. The following code illustrates this, by changing the shell's cursor tobe hand cursor, and the list's cursor to a cross. When the mouse is over theshell (or its childButton that has no explicit cursor) it is a hand, and when itis over the list it is a cross.
List list = new List(shell,SWT.BORDER);
Button button = new Button(shell,SWT.NONE);
button.setText("Button");
Cursor handCursor = new Cursor(display,SWT.CURSOR_HAND);
shell.setCursor(handCursor);
Cursor crossCursor = new Cursor(display,SWT.CURSOR_CROSS);
list.setCursor(crossCursor);
Cursors use underlying native resources and should be disposed when they areno longer required. In the above code this would be when the shell has beendisposed and there are no remaining controls using either the handCursor orcrossCursor fields.
The source and mask image data pixels are combined to determine whether thecursor pixel should be white, black or transparent.
Image | Mask | Cursor color |
1 | 0 | Transparent |
0 | 0 | Black |
1 | 1 | Black |
0 | 1 | White |
The ImageData can be loaded from files, and Eclipse itself does this for someof its drag and drop cursors defined in org.eclipse.ui/icons/full/dnd. Youcan also directly create and manipulate the image data within your program. Thecode sample below creates an indexed palette with two colors. The source andmask ImageData are 32 by 32 with a color depth of 1. The int[] for the sourceand mask define an up arrow, the 0s for the source and 1s for the mask are shownin bold to show how the arrow is defined with the arrays. 0 and 1 makes whitewhich is the center of the arrow, 1 and 1 is black for the edge of the arrow,and 1 and 0 transparent for the remainder. The tip of the arrow is 16,3 so thisis made the cursor hotspot when it is created.
PaletteData paletteData = new PaletteData(new RGB[] {
new RGB(0,0,0) , new RGB(255,255,255)
});
ImageData sourceData = new ImageData(32,32,1,paletteData);
ImageData maskData = new ImageData(32,32,1,paletteData);
int[] cursorSource = new int[] {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 };
int[] cursorMask = new int[] {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, };
sourceData.setPixels(0,0,1024,cursorSource,0);
maskData.setPixels(0,0,1024,cursorMask,0);
Cursor cursor = new Cursor(display,sourceData,maskData,16,3);
shell.setCursor(cursor);
To keep the code listings narrow the above sample used an int[]
to define the source and mask imageData. A byte uses less memory than anunsigned int, so when creating custom cursors it is more efficient to use abyte[] instead, such as:
byte[] cursorSource = new byte[] {
(byte)0x00, (byte)0x00, (byte)0x01, (byte)0x01,(byte)0x00, // etc...
Custom cursors need to be disposed in just the same way as pre-defined systemcursors, so when there is no remaining control using the cursor is must be sendthe method dispose() to free up the underlying native resource.
Although the above example is for a monochrome cursor, Eclipse 3.0 supports color cursors on platforms that allow it (such as Windows). Two SWT code snippets showing how to do this are here: snippet 1, snippet 2.
Java and all Java-based trademarks and logos are trademarksor registered trademarks of Sun Microsystems, Inc. in the United States, othercountries, or both.
Windows is a trademark of Microsoft corporation in the UnitedStates, other countries, or both.
Other company, product, and service names may be trademarks orservice marks of others.
联系客服