过度绘制Eclipse RCP应用程序的主shell

时间:2018-05-03 10:24:10

标签: java eclipse eclipse-rcp

我一直试图"透支"我的Eclipse RCP应用程序的主窗口,以显示红色"录制"应用程序启用了屏幕录制功能时的边框。

private boolean isActive;

private final ProgressMonitorDialog monitor;

private PaintListener paintListener;
private final int recordingFrameThickness = 5;  

public boolean toggle() {
  isActive = !isActive;

  try {
    // New state
    if (isActive) {
      monitor.run(true, false, new BackupExecutionBeginRecording(Display.getCurrent()));
      addRecordingFrame(Display.getCurrent().getActiveShell());
    }
    else {
      monitor.run(true, false, new BackupExecutionAfterRecording());
      removeRecoringFrame(Display.getCurrent().getActiveShell());
    }
  }
  catch (InvocationTargetException e) {
    System.err.println("Couldn't start backup task. Error: " + e.getMessage());
  }
  catch (InterruptedException e) {
    System.err.println("Backup thread was interrupted. Error: " + e.getMessage());
  }

  return isActive;
}

private void addRecordingFrame(Shell shell) {
  paintListener = new PaintListener() {

    @Override
    public void paintControl(PaintEvent e) {
      Rectangle clientArea = shell.getClientArea();
      e.gc.setLineWidth(recordingFrameThickness);
      e.gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
      e.gc.drawRectangle(clientArea);
    }
  };

  shell.addPaintListener(paintListener);
}

private void removeRecoringFrame(Shell shell) {
  shell.removePaintListener(paintListener);
}

正如您所看到的,我遵循的方法是等待应用程序主窗口被绘制并随后添加一个矩形。理论上,在每次改变窗口大小或位置后,应重新渲染重叠的红框。但似乎应用程序的主shell不会调用PaintEvent。

是否有其他方法可以将某些内容绘制到应用程序的现有布局上,而不会阻止与下面控件的交互?

2 个答案:

答案 0 :(得分:1)

Eclipse Platform通过在 overlay shell上创建和绘制来实现这一点,该shell小心地位于基本shell的顶部。叠加层是使用SWT.NO_TRIM | SWT.ON_TOP创建的,其位置跟踪底层基础shell。有关示例,请参阅e4 Overlay

答案 1 :(得分:0)

通过下面的解决方案,我能够在我的主壳周围绘制一个红色边框,"跟随" shell的任何重新定位和调整大小的活动。一个很大的缺点仍然存在:红色边框似乎有一个外边框(由区域创建?),它与用于调整外壳大小的手柄重叠。因此,只有在没有显示红色边框时才能调整外壳的大小(等于外壳没有焦点)。

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Region;
import org.eclipse.swt.widgets.Shell;

public class RecordingFrame {

    private Shell baseShell;
    private Shell overlayShell;

    private ControlListener controlListener;
    private ShellListener shellListener;
    private PaintListener paintListener;

    private Rectangle outerRect;
    private Rectangle innerRect;
    private Region region;

    private int lineWidth = 10;
    private Color color;

    public RecordingFrame(Shell baseShell) {
        this.baseShell = baseShell;

        // Set up new shell
        overlayShell = new Shell(baseShell, SWT.BORDER | SWT.NO_TRIM | SWT.ON_TOP);
        overlayShell.setVisible(true);

        // Initialize objects
        outerRect = new Rectangle(0, 0, 0, 0);
        innerRect = new Rectangle(0, 0, 0, 0);
        region = new Region();

        color = new Color(baseShell.getDisplay(), 255, 0, 0);

        // First drawing of frame
        redraw();

        // Configure listeners
        initListeners();

        // Add listeners to shells
        baseShell.addControlListener(controlListener);
        baseShell.addShellListener(shellListener);
        overlayShell.addPaintListener(paintListener);
    }

    public void dispose() {
      // Remove all listeners
      overlayShell.removePaintListener(paintListener);
        baseShell.removeControlListener(controlListener);
        baseShell.removeShellListener(shellListener);

        if (!overlayShell.isDisposed())
            overlayShell.dispose();
    }

    private void redraw() {

      // Get bounds of base shell
        overlayShell.setBounds(baseShell.getBounds());

        // Calculate outer rectangle
        outerRect.height = overlayShell.getBounds().height;
        outerRect.width = overlayShell.getBounds().width;
        outerRect.x = 0;
        outerRect.y = 0;

        // Calculate inner rectangle
        innerRect.height = outerRect.height - 2 * lineWidth;
        innerRect.width = outerRect.width - 2 * lineWidth;
        innerRect.x = 0 + lineWidth;
        innerRect.y = 0 + lineWidth;

        // Create a new region which is the outer shell minus the inner shell
        region = new Region();
        region.add(outerRect);
        region.subtract(innerRect);

        overlayShell.setRegion(region);
        region.dispose();

        // Draw rectangle with new GC
        GC gc = new GC(overlayShell);
        gc.setLineWidth(lineWidth);
        gc.setForeground(color);
        gc.drawRectangle(innerRect);
        gc.dispose();
    }

    private void initListeners() {
       controlListener = new ControlListener() {

          @Override
          public void controlResized(ControlEvent e) {
            redraw();
          }

          @Override
          public void controlMoved(ControlEvent e) {
            redraw();
          }
        };

        shellListener = new ShellListener() {

          @Override
          public void shellIconified(ShellEvent e) {
            overlayShell.setVisible(false);        
          }

          @Override
          public void shellDeiconified(ShellEvent e) {
            overlayShell.setVisible(true);                
          }

          @Override
          public void shellDeactivated(ShellEvent e) {
            overlayShell.setVisible(false);         
          }

          @Override
          public void shellClosed(ShellEvent e) {
            dispose();        
          }

          @Override
          public void shellActivated(ShellEvent e) {
            overlayShell.setVisible(true);          
          }
        };

        paintListener = new PaintListener() {

          @Override
          public void paintControl(PaintEvent e) {
            redraw();
          }
        };
    }
}