SWT Draw a transparent rectangle on the shell

I would like to create a selection area tool. This tool should allow you to draw a rectangular area on the screen with the mouse.

I use full-screen, translucent, darkened swt Shell as the background against which I draw a white rectangle to represent the selected area.

My problem is that I did not find an effective way to update the rectangle area. So far I have used the redraw method, but the visual effect was pretty ugly, even I thought I was trying to redraw only the desired area:

  public ManualScreenAreaSelector(final Display display) { shell = new Shell(display, SWT.NO_TRIM | SWT.ON_TOP); shell.setBounds(display.getClientArea()); // shell.setFullScreen(true); shell.setAlpha(180); shell.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); shell.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); } @Override public void mouseMove(final MouseEvent e) { if (editionMode) { // retrieve the rectangular area corresponding to mouse selection final Rectangle r = makeRectangleFromSelection(clickCoordinates, new Point(ex, ey)); // make the ugly 'tint' effect shell.redraw(); GC gc = new GC(shell); gc.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_WHITE)); gc.setAlpha(150); gc.fillRectangle(rx, ry, r.width, r.height); gc.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK)); gc.fillRectangle(0, 0, rx, ry); gc.fillRectangle(0, 1080 - ry, rx, 1080 - ry); gc.dispose(); lastX = ex; lastY = ey; } } @Override public void mouseDown(final MouseEvent e) { // Right click = reset selection if (e.button == 3) { shell.redraw(); selectedArea = null; if (editionMode) { editionMode = false; shell.removeMouseMoveListener(ManualScreenAreaSelector.this); } } else if (e.button == 1) { // left-click enter edition mode // Reset previous selection selectedArea = null; editionMode = true; clickCoordinates = new Point(ex, ey); lastX = ex; lastY = ey; shell.addMouseMoveListener(ManualScreenAreaSelector.this); } } @Override public void mouseUp(final MouseEvent e) { // left click, only if edition was set if ((e.button == 1) && editionMode) { editionMode = false; shell.removeMouseMoveListener(ManualScreenAreaSelector.this); selectedArea = makeRectangleFromSelection(clickCoordinates, new Point(ex, ey)); shell.dispose(); } } 

Therefore, I would like to know if there is a more efficient solution in SWT without using the redraw method.

actual result


EDIT I used 3 images to make a choice:

  • The first is a screen image (screenshot)
  • Secondly, the screen image + alpha mixed dark rectangle
  • The third is a buffer on which I draw an alpha-mixed image + rectangle copied from a screenshot.

Performance is acceptable as there is only one alpha blending operation (for the second image).

There is only one problem left when I used the graphical control of the shell to draw the shell when I used the alpha mixed image for the first time as a background shell, everything else works when sending mouse events:

 public ManualScreenAreaSelector(final Display display) { screenWidth = display.getClientArea().width; screenHeight = display.getClientArea().height; // create a new Image of the screen backGround = new Image(display, display.getBounds()); GC gc = new GC(display); gc.copyArea(backGround, 0, 0); gc.dispose(); // Copy background image and add alpha blended effect aplhaBackGround = new Image(backGround.getDevice(), backGround.getImageData()); GC alphaGC = new GC(aplhaBackGround); alphaGC.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); alphaGC.setAlpha(200); alphaGC.fillRectangle(0, 0, screenWidth, screenHeight); alphaGC.dispose(); // create the shell shell = new Shell(display, SWT.NO_TRIM | SWT.ON_TOP | SWT.NO_BACKGROUND); shell.setBounds(display.getClientArea()); // get shell graphics control shellGraphics = new GC(shell); // set the shell image to screen image <-- does nothing shellGraphics.drawImage(aplhaBackGround, 0, 0); // Image for the shell bufferImage = new Image(shell.getDisplay(), shell.getBounds()); shell.print(shellGraphics); } public void mouseMove(final MouseEvent e) { if (editionMode) { // Get selected area final Rectangle selectedArea = makeRectangleFromSelection(clickCoordinates, new Point( ex, ey)); // Copy alpha blended background into the buffer GC gc1 = new GC(aplhaBackGround); gc1.copyArea(bufferImage, 0, 0); gc1.dispose(); // Paint "normal" background over selected area GC gc2 = new GC(bufferImage); gc2.drawImage(backGround, selectedArea.x, selectedArea.y, selectedArea.width, selectedArea.height, selectedArea.x, selectedArea.y, selectedArea.width, selectedArea.height); // draw the painted image on the shell shellGraphics.drawImage(bufferImage, 0, 0); gc2.dispose(); } } 
+4
source share
1 answer

Try this approach:

  • Instead of shell.redraw(); call shell.print(gc) once and attach the GC to the image buffer. This gives you a shell image.

  • Get OpenGL extensions for SWT or jogl . Place the image in the background and create a 3D rectangle to highlight. Use OpenGL for alpha operations and composition.

Alpha operations are believed to be slow in SWTs, which often must use the CPU for this. Your video card can perform the same operation hundreds of times per second without breaking a sweat.

+4
source

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


All Articles