您的位置:首页 > 其它

Draw2d中如何控制ToolTip的持续时间

2007-03-26 14:26 393 查看
Draw2d中如何控制ToolTip的持续时间

软件版本:Eclipse3.2, draw2d_3.2.0.v20060626

在Draw2d中,Figure都支持ToolTip(通过调用setToolTip方法),当鼠标停留在其上面时,显示一个标签,以便提供有用的信息给使用者。这个显示的持续时间为5秒。那么对于ToolTip内容比较长的情况,5秒时间不够用,怎么办?这是一个典型的中国式需求 :-P
话说从头。相传SWT与Draw2d连接的桥梁叫做LightweightSystem,而在LightweightSystem中,负责分发SWT事件的,叫做SWTEventDispatcher,这个SWTEventDispatcher呢,使用一个ToolTipHelper的对象来控制ToolTip的显示,而在ToolTipHelper中,那个5秒的持续时间竟然是写死的!——必须承认,做eclipse插件开发,很多时候你都是在阅读他们的源码并且不时摇头叹息——那么,我们的解决办法自然就是:将这个ToolTipHelper的行为替换掉。OK,继承一个:

public class ToolTipHelperX extends ToolTipHelper {
private Timer timer;
private IFigure currentTipSource;
private long duration = 5000;

/**
* Constructs a ToolTipHelper to be associated with Control <i>c</i>.
*
* @param c the control
* @since 2.0
*/
public ToolTipHelperX(Control c) {
super(c);
}

/*
* Calculates the location where the tooltip will be painted. Returns this as a Point.
* Tooltip will be painted directly below the cursor if possible, otherwise it will be
* painted directly above cursor.
*/
private Point computeWindowLocation(IFigure tip, int eventX, int eventY) {
org.eclipse.swt.graphics.Rectangle clientArea = control.getDisplay().getClientArea();
Point preferredLocation = new Point(eventX, eventY + 26);

Dimension tipSize = getLightweightSystem()
.getRootFigure()
.getPreferredSize()
.getExpanded(getShellTrimSize());

// Adjust location if tip is going to fall outside display
if (preferredLocation.y + tipSize.height > clientArea.height)
preferredLocation.y = eventY - tipSize.height;

if (preferredLocation.x + tipSize.width > clientArea.width)
preferredLocation.x -= (preferredLocation.x + tipSize.width) - clientArea.width;

return preferredLocation;
}

/**
* Sets the LightWeightSystem's contents to the passed tooltip, and displays the tip. The
* tip will be displayed only if the tip source is different than the previously viewed
* tip source. (i.e. The cursor has moved off of the previous tooltip source figure.)
* <p>
* The tooltip will be painted directly below the cursor if possible, otherwise it will be
* painted directly above cursor.
*
* @param hoverSource the figure over which the hover event was fired
* @param tip the tooltip to be displayed
* @param eventX the x coordinate of the hover event
* @param eventY the y coordinate of the hover event
* @since 2.0
*/
public void displayToolTipNear(IFigure hoverSource, IFigure tip, int eventX, int eventY) {
if (tip != null && hoverSource != currentTipSource) {
getLightweightSystem().setContents(tip);
Point displayPoint = computeWindowLocation(tip, eventX, eventY);
Dimension shellSize = getLightweightSystem().getRootFigure()
.getPreferredSize().getExpanded(getShellTrimSize());
setShellBounds(displayPoint.x, displayPoint.y, shellSize.width, shellSize.height);
show();
currentTipSource = hoverSource;
timer = new Timer(true);
timer.schedule(new TimerTask() {
public void run() {
Display.getDefault().syncExec(new Runnable() {
public void run() {
hide();
timer.cancel();
}
});
}
}, duration);
}
}

/**
* Disposes of the tooltip's shell and kills the timer.
*
* @see PopUpHelper#dispose()
*/
public void dispose() {
if (isShowing()) {
timer.cancel();
hide();
}
getShell().dispose();
}

/**
* @see PopUpHelper#hookShellListeners()
*/
protected void hookShellListeners() {
// Close the tooltip window if the mouse enters the tooltip
getShell().addMouseTrackListener(new MouseTrackAdapter() {
public void mouseEnter(org.eclipse.swt.events.MouseEvent e) {
hide();
currentTipSource = null;
timer.cancel();
}
});
}

/**
* Displays the hover source's tooltip if a tooltip of another source is currently being
* displayed.
*
* @param figureUnderMouse the figure over which the cursor was when called
* @param tip the tooltip to be displayed
* @param eventX the x coordinate of the cursor
* @param eventY the y coordinate of the cursor
* @since 2.0
*/
public void updateToolTip(IFigure figureUnderMouse, IFigure tip, int eventX, int eventY) {
/* If the cursor is not on any Figures, it has been moved
off of the control. Hide the tool tip. */
if (figureUnderMouse == null) {
if (isShowing()) {
hide();
timer.cancel();
}
}
// Makes tooltip appear without a hover event if a tip is currently being displayed
if (isShowing() && figureUnderMouse != currentTipSource) {
hide();
timer.cancel();
displayToolTipNear(figureUnderMouse, tip, eventX, eventY);
} else if (!isShowing() && figureUnderMouse != currentTipSource)
currentTipSource = null;
}

public void setDuration(long duration) {
this.duration = duration;
}

}

这段代码不短,但它其实可以很短,原因是作者没考虑到会有人想要继承它,以致我们无法直接覆盖displayToolTipNear方法了事,于是我干脆就把ToolTipHelper的代码全拷过来贴上。
然后,再来看SWTEventDispatcher,发现,它的这个toolTipHelper成员无法注入(没有setter),用的时候是直接在getter里new出来的;不过还好,这个getter是protected,也就是说,在设计上考虑了继承的可能性,这样代码就会简单一些了。来来来,再继承一个:

public class SWTEventDispatcherX extends SWTEventDispatcher {

private ToolTipHelperX toolTipHelperX;

private long tooltipDuration;

public SWTEventDispatcherX(long tooltipDuration) {
super();
this.tooltipDuration = tooltipDuration;
}

protected ToolTipHelper getToolTipHelper() {
if (toolTipHelperX == null) {
toolTipHelperX = new ToolTipHelperX(control);
toolTipHelperX.setDuration(tooltipDuration);
}
return toolTipHelperX;
}
}

OK了,还剩下最后一个,传说中的LightweightSystem。这个东西好,他直接提供了SWTEventDispatcher的注入器(就是setter了,说注入器显得唬人一些),就不需要我们再做什么了,小功告成!
譬如说,现在要在一个名叫parent的Composite上放置一个FigureCanvas,做为其它Figure的容器,就可以这样写:

LightweightSystem lws = new LightweightSystem();
lws.setEventDispatcher(new SWTEventDispatcherX(1800000L));//半小时
FigureCanvas canvas = new FigureCanvas(parent, SWT.DOUBLE_BUFFERED, lws);
canvas.setContents(yourTopMostFigure);
...

如此一来,这个FigureCanvas上的Figure的ToolTip都会持续显示半小时。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: