Java SWT: icon notifications

I have a desktop based application written in Java SWT running on Windows.

I want to add a button on the user interface screen whose behavior should be similar to the icons on the iphone or facebook notifications, as shown in the figures below.

The number on the icon will be dynamic and will increase or decrease depending on the number of pending notifications.

How can I implement something like this in SWT / AWT?

IOS Icon:

enter image description here

Facebook Notification:

enter image description here

+5
source share
2 answers

I recently applied something similar. You can simply draw your own image using the GC and overlay on the desired icon.

I include my assistant class. This is not the cleanest code (a lot of material is hard coded), but you will understand the essence. The notification bank is resized depending on the number of notifications (max. 999).

How to use (remember about caching and / or deleting images!):

 Image decoratedIcon = new ImageOverlayer() .baseImage(baseImage) // You icon/badget .overlayImage(ImageOverlayer.createNotifImage(5)) // 5 notifications .overlayImagePosition(OverlayedImagePosition.TOP_RIGHT) .createImage(); 


 /** * <pre> * The difference between this and the ImageBuilder is * that ImageOverlayer does not chain the images, rather * just overlays them one onto another. * * * Rules: * * 1.) Images are not disposed. Resource handing must be done externally. * 2.) Only two images allowed, for now. * 3.) The size of the composite image should normally be the size of the * base image, BUT: if the overlaying image is larger, then larger * parameters are grabbed, and the base image is still underneath. * 4.) Use the builder APIs to set the base and overlaying images. The * position of the overlaying image is optional, and CENTER by default. * When you've set these, simply call createImage() * * Further improvements: * * - Combine this with ImageBuilder. These two composers should be welded. * * </pre> * * @author grec.georgian@gmail.com * */ public class ImageOverlayer extends CompositeImageDescriptor { // ==================== 1. Static Fields ======================== public enum OverlayedImagePosition { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, CENTER; } // ====================== 2. Instance Fields ============================= private ImageData baseImageData; private ImageData overlayedImageData; private OverlayedImagePosition overlayedImagePosition = OverlayedImagePosition.CENTER; // ==================== 3. Static Methods ==================== /** * Creates a red circle with a white bold number inside it. * Does not cache the final image. */ public static final Image createNotifImage(final int numberOfNotifications) { // Initial width and height - hardcoded for now final int width = 14; int height = 14; // Initial font size int fontSize = 100; int decorationWidth = width; String textToDraw = String.valueOf(numberOfNotifications); final int numberLength = Integer.toString(numberOfNotifications).length(); if(numberLength > 3) { // spetrila, 2014.12.17: - set a width that fits the text // - smaller height since we will have a rounded rectangle and not a circle // - smaller font size so the new text will fit(set to 999+) if we have // a number of notifications with more than 3 digits decorationWidth += numberLength * 2; height -= 4; fontSize = 80; textToDraw = "999+"; //$NON-NLS-1$ } else if (numberLength > 2) { // spetrila, 2014.12.17: - set a width that fits the text // - smaller height since we will have a rounded rectangle and not a circle decorationWidth += numberLength * 1.5; height -= 4; } final Font font = new Font(Display.getDefault(), "Arial", width / 2, SWT.BOLD); //$NON-NLS-1$ final Image canvas = new Image(null, decorationWidth, height); final GC gc = new GC(canvas); gc.setAntialias(SWT.ON); gc.setAlpha(0); gc.fillRectangle(0, 0, decorationWidth, height); gc.setAlpha(255); gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_RED)); // spetrila, 2014.12.17: In case we have more than two digits in the number of notifications, // we will change the decoration to a rounded rectangle so it can contain // all of the digits in the notification number if(decorationWidth == width) gc.fillOval(0, 0, decorationWidth - 1, height - 1); else gc.fillRoundRectangle(0, 0, decorationWidth, height, 10, 10); final FontData fontData = font.getFontData()[0]; fontData.setHeight((int) (fontData.getHeight() * fontSize / 100.0 + 0.5)); fontData.setStyle(SWT.BOLD); final Font newFont = new Font(Display.getCurrent(), fontData); // gc.setFont(AEFUIActivator.getDefault().getCustomizedFont(font, fontSize, SWT.BOLD)); gc.setFont(newFont); gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); final Point textSize = gc.stringExtent(textToDraw); final int xPos = (decorationWidth - textSize.x) / 2; final int yPos = (height - textSize.y) / 2; gc.drawText(textToDraw, xPos + 1, yPos, true); gc.dispose(); final ImageData imgData = canvas.getImageData(); // Remove white transparent pixels final int whitePixel = imgData.palette.getPixel(new RGB(255,255,255)); imgData.transparentPixel = whitePixel; final Image finalImage = new Image(null, imgData); canvas.dispose(); font.dispose(); newFont.dispose(); return finalImage; } // ==================== 5. Creators ==================== @Override public Image createImage() { if (baseImageData == null || overlayedImageData == null) throw new IllegalArgumentException("Please check the ImageOverlayer. One of the overlaying images is NULL."); //$NON-NLS-1$ return super.createImage(); } // ==================== 6. Action Methods ==================== @Override protected void drawCompositeImage(final int width, final int height) { /* * These two determine where the overlayed image top left * corner should go, relative to the base image behind it. */ int xPos = 0; int yPos = 0; switch (overlayedImagePosition) { case TOP_LEFT: break; case TOP_RIGHT: xPos = baseImageData.width - overlayedImageData.width; break; case BOTTOM_LEFT: yPos = baseImageData.height - overlayedImageData.height; break; case BOTTOM_RIGHT: xPos = baseImageData.width - overlayedImageData.width; yPos = baseImageData.height - overlayedImageData.height; break; case CENTER: xPos = (baseImageData.width - overlayedImageData.width) / 2; yPos = (baseImageData.height - overlayedImageData.height) / 2; break; default: break; } drawImage(baseImageData, 0, 0); drawImage(overlayedImageData, xPos, yPos); } // ==================== 7. Getters & Setters ==================== final public ImageOverlayer overlayImagePosition(final OverlayedImagePosition overlayImagePosition) { this.overlayedImagePosition = overlayImagePosition; return this; } final public ImageOverlayer baseImage(final ImageData baseImageData) { this.baseImageData = baseImageData; return this; } final public ImageOverlayer baseImage(final Image baseImage) { this.baseImageData = baseImage.getImageData(); return this; } final public ImageOverlayer baseImage(final ImageDescriptor baseImageDescriptor) { this.baseImageData = baseImageDescriptor.getImageData(); return this; } final public ImageOverlayer overlayImage(final ImageData overlayImageData) { this.overlayedImageData = overlayImageData; return this; } final public ImageOverlayer overlayImage(final Image overlayImage) { this.overlayedImageData = overlayImage.getImageData(); return this; } final public ImageOverlayer overlayImage(final ImageDescriptor overlayImageDescriptor) { this.overlayedImageData = overlayImageDescriptor.getImageData(); return this; } @Override protected Point getSize() { // The size of the composite image is determined by the maximum size between the two building images, // although keep in mind that the base image always comes underneath the overlaying one. return new Point( max(baseImageData.width, overlayedImageData.width), max(baseImageData.height, overlayedImageData.height) ); } } 
+6
source

In addition, you can use control jewelry for this. The advantage is that you can easily hide / show the notification using the hide() and show() methods and add the text of the prompt and listeners to it.

Check out the blog how to use the control. Use Button widget instead of Text for your case.

Create a notification image as shown below and set a ControlDecoration object for it.

  Image image = new Image(display, 20, 25); GC gc = new GC(image); gc.setBackground(display.getSystemColor(SWT.COLOR_RED)); gc.fillRectangle(0, 0, 20, 25); gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); int notif = 5; gc.drawText(new Integer(notif).toString(), 5, 5); gc.dispose(); 
+2
source

Source: https://habr.com/ru/post/1214792/


All Articles