2012-03-06 72 views
4

我想創建一個「選擇區域」工具。 這個工具應該允許用鼠標在屏幕上繪製一個矩形區域。SWT在外殼上繪製一個「透明」矩形

我使用全屏,半透明,變暗的swt Shell作爲我的背景,在該背景上繪製了一個白色矩形來表示所選區域。

我的問題是,我沒有找到一個有效的方式刷新矩形區域。 到現在爲止我用過的redraw方法,但視覺效果相當難看,甚至以爲我試圖重新繪製僅他所需要的面積:

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(e.x, e.y)); 
      // 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(r.x, r.y, r.width, r.height); 

      gc.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK)); 
      gc.fillRectangle(0, 0, r.x, r.y); 
      gc.fillRectangle(0, 1080 - r.y, r.x, 1080 - r.y); 
      gc.dispose(); 

      lastX = e.x; 
      lastY = e.y; 
     } 
    } 

    @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(e.x, e.y); 
      lastX = e.x; 
      lastY = e.y; 
      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(e.x, e.y)); 
      shell.dispose(); 
     } 
    } 

所以我想知道,如果一個更有效的解決方案,存在於SWT,而不必使用重繪方法。

actual result


EDIT 我使用3個圖像來進行選擇工作:

  • 首先是畫面的圖像(屏幕截圖)
  • 第二個是屏幕+ alpha混合深色矩形的圖像
  • 第三個是我在其上繪製alpha混合圖像的緩衝區+從截圖圖像複製的矩形。

由於只有一個alpha混合操作(對於第二個圖像),性能是可以接受的。

只有一個問題仍然存在,當我第一次使用外殼的圖形控件繪製外殼時,第一次將alpha混合圖像用作外殼背景時,在發送鼠標事件時其他所有內容都正常工作:

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(
       e.x, e.y)); 
     // 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

試試這個辦法:

  • 相反shell.redraw();的,叫shell.print(gc)一次,GC附加到圖像緩衝區。這給你一個shell的圖像。

  • 獲取SWT或jogl的OpenGL擴展。將圖像放在背景中併爲選擇創建一個3D矩形。使用OpenGL進行alpha操作和組合。

推理是在SWT中alpha操作很慢,通常需要使用CPU來完成它。您的圖形卡每秒可以執行相同的操作數百次,而不會出汗。

+0

我更喜歡使用print()方法,而不是OpenGl擴展或jogl。我會嘗試shell.print(gc)。 – zeropouet 2012-03-06 15:53:28

+0

您可以嘗試使用該圖像來加速重繪,但我的直覺是SWT alpha實現對於全屏操作而言太慢。 – 2012-03-06 16:44:45