透支 Eclipse RCP 应用程序的主要 shell
Overdraw Eclipse RCP application's main shell
我一直在尝试 "overdraw" 我的 Eclipse RCP 应用程序的主要 window 以便在应用程序启用屏幕录制功能时显示红色 "recording" 边框。
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);
}
如您所见,我采用的方法是等到应用程序 main window 绘制完成后添加一个矩形。理论上,每次 window 大小或位置发生变化后,覆盖的红框应该重新渲染。但似乎应用程序的主要 shell.
没有调用 PaintEvent
是否有其他方法可以在应用程序的现有布局上绘制内容,而不会阻止与下方控件的交互?
Eclipse 平台通过在 overlay shell 上创建和绘制来做到这一点,该 shell 小心地放置在基础 shell 之上。覆盖层是用 SWT.NO_TRIM | SWT.ON_TOP
创建的,其位置跟踪基础 shell。有关示例,请参见 e4 Overlay。
使用下面的解决方案,我能够在 shell 的主要 shell 周围绘制一个红色边框,"follows" shell 的任何重新定位和调整大小 activity。一个很大的缺点仍然存在:红色边框似乎有一个外边框(由区域创建?),它与用于调整 shell 大小的手柄重叠。因此,只有在不显示红色边框时才能调整 shell 的大小(等于 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();
}
};
}
}
我一直在尝试 "overdraw" 我的 Eclipse RCP 应用程序的主要 window 以便在应用程序启用屏幕录制功能时显示红色 "recording" 边框。
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);
}
如您所见,我采用的方法是等到应用程序 main window 绘制完成后添加一个矩形。理论上,每次 window 大小或位置发生变化后,覆盖的红框应该重新渲染。但似乎应用程序的主要 shell.
没有调用 PaintEvent是否有其他方法可以在应用程序的现有布局上绘制内容,而不会阻止与下方控件的交互?
Eclipse 平台通过在 overlay shell 上创建和绘制来做到这一点,该 shell 小心地放置在基础 shell 之上。覆盖层是用 SWT.NO_TRIM | SWT.ON_TOP
创建的,其位置跟踪基础 shell。有关示例,请参见 e4 Overlay。
使用下面的解决方案,我能够在 shell 的主要 shell 周围绘制一个红色边框,"follows" shell 的任何重新定位和调整大小 activity。一个很大的缺点仍然存在:红色边框似乎有一个外边框(由区域创建?),它与用于调整 shell 大小的手柄重叠。因此,只有在不显示红色边框时才能调整 shell 的大小(等于 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();
}
};
}
}