Dispose of SWT shell when cursor moves out of it
I'm implementing a custom preview/tooltip for an Ec开发者_如何学Pythonlipse plug-in. It did it using a Shell in SWT, removing all its trimmings and placing a text box inside it. It looks great. However now I need to dispose of the shell when the cursor moves out of the shell window and I ran into some issues:
Does it make sense to attach a mousemoveListener to the shell? First I was doing this but then I realized that this listener only captures mouse move Events which occur inside the shell. How will I capture the mouse going out of the shell so as I could dispose of it?
Thanks and regards, Krt_Malta
Attach a MouseTrackListener with MouseTrackAdapter as a listener and override mouseExit() method.
As another options, you can use AbstractHoverInformationControlManager
from org.eclipse.jface.text
, which handles all the nasty details (e.g. when you Alt+Tab out of the application, does your tooltip disappear?). The event handling is taken care of and you can focus on the interesting things. An example:
import org.eclipse.jface.text.AbstractHoverInformationControlManager;
import org.eclipse.jface.text.AbstractReusableInformationControlCreator;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class Example {
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
shell.setSize(200, 200);
final ExampleHoverInformationControlManager controlManager = new ExampleHoverInformationControlManager();
// This must be done for the control for which you want the mouse
// tracking to be enabled and you possibly want to show hovers.
controlManager.install(shell);
shell.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
controlManager.dispose();
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
private static class ExampleHoverInformationControlCreator extends
AbstractReusableInformationControlCreator {
@Override
protected IInformationControl doCreateInformationControl(Shell parent) {
return new DefaultInformationControl(parent);
}
}
private static class ExampleHoverInformationControlManager extends
AbstractHoverInformationControlManager {
protected ExampleHoverInformationControlManager() {
super(new ExampleHoverInformationControlCreator());
}
@Override
protected void computeInformation() {
MouseEvent e = getHoverEvent();
// Just a static example area for simplicity
if (e.x >= 0 && e.x < 100 && e.y >= 0 && e.y < 20) {
Rectangle area = new Rectangle(0, 0, 100, 20);
setInformation(
"This can be a string or something else, you control it", area); //$NON-NLS-1$
return;
}
// computeInformation must setInformation in all cases
setInformation(null, null);
}
}
}
I just discovered a much better solution. It runs like this.
Shell coverup = new Shell(SWT.NO_TRIM) ;
coverup.setBounds(parentComposite.getShell().getBounds());
coverup.moveAbove( Display.getCurrent().getActiveShell() );
coverup.setAlpha( 13 );
coverup.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
popupShell = new Shell( coverup, SWT.NO_TRIM );
coverup.addMouseMoveListener(new MouseMoveListener() {
@Override
public void mouseMove( MouseEvent mouseEvent )
{
System.out.println( "coverup - mouse moves" );
coverup.close() ;
}
});
Which in English is:
Create an invisible shell the same size as the application/parent shell.
Cover the parent shell with the invisible shell.
Attach a mouse Enter listener to the covering shell.
Create the actual popup as a child of, and on top of, the covering shell When the mouse enters the popup, activate the coverup.
This means that no matter where the mouse goes after being in the popup, it enters the coverup shell - and the coverup mouse enter event disposes everything.
We are not detecting when we the mouse exits the popup - we are detecting when the mouse enters the surroundings.
Added bonus: setting the background of the coverup to a light gray, and a low Alpha, makes hte whole application subtly 'grayed-out' - so the user is aware is is disabled.
Small gotcha: if the popup shell is not wholly contained in the appwindow, where the popup shell goes outside the appwindow the mouse can escape without triggering the coverup shell.
Other than that - this works really well!
精彩评论