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都会持续显示半小时。
软件版本: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都会持续显示半小时。
相关文章推荐
- 如何方便的控制css3动画开始时间点与持续时间
- DataGridView单元格字符超长,ToolTip冒泡提醒功能,可控制宽度和持续显示时间
- C#如何控制方法的执行时间,超时则强制退出方法执行
- php 如何设置一个严格控制过期时间的session
- Linux 技巧: 控制预定作业的持续时间
- 如何将曲谱的各音符转换成频率数组和持续时间
- 如何控制层在某个时间显示或者隐藏
- Win8系统如何让家长更放心孩子使用电脑(合理控制时间)
- 如何在apache中设置session的持续时间
- 时间管理:如何高效的控制会议
- 如何运用按钮控制时间轴上帧的移动与跳转
- 如何:控制文本框文本更新源的时间
- 持续讨论 javascript 如何控制优化页面 js 加载顺序
- C#如何控制方法的执行时间,超时则强制退出方法执行
- 同时用两个定时器控制蜂鸣器发声,定时器0控制频率,定时器1控制同个频率持续的时间,间隔300ms依次输出1,10,50,100,200,400,800,1K的方波
- 如何减少服务器迁移中宕机时间及控制风险
- php 如何设置一个严格控制过期时间的session
- 如何控制一个函数的执行时间
- linux中如何查看进程启动时间,持续时长
- 读《如何控制自己的时间与生活》