2013年2月28日 星期四

在 eclipse swt 的介面上放 tool tip

實作 tool tip 時,其實就是在介面上面放一個滑鼠停留的事件
當事件發生時,要求程式畫出一個文字欄位,把 tool tip 要顯示的東西放在欄位上。
範例的滑鼠停留事件可以參考 [1]。

以下先節錄 [1] 定義的 tool tip 事件的 class。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.HelpEvent;
import org.eclipse.swt.events.HelpListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.Widget;
 
/**
 * Emulated tooltip handler Notice that we could display anything in a tooltip
 * besides text and images. For instance, it might make sense to embed large
 * tables of data or buttons linking data under inspection to material
 * elsewhere, or perform dynamic lookup for creating tooltip text on the fly.
 */
public class ToolTipHandler {
  
  private Shell parentShell;
 
  private Shell tipShell;
 
  private Label tipLabelImage, tipLabelText;
 
  private Widget tipWidget; // widget this tooltip is hovering over
 
  private Point tipPosition; // the position being hovered over
 
  /**
   * Creates a new tooltip handler
   * @param parent
   *            the parent Shell
   */
  public ToolTipHandler(Shell parent) {
    final Display display = parent.getDisplay();
    this.parentShell = parent;
 
    tipShell = new Shell(parent, SWT.ON_TOP | SWT.TOOL);
    GridLayout gridLayout = new GridLayout();
    gridLayout.numColumns = 2;
    gridLayout.marginWidth = 2;
    gridLayout.marginHeight = 2;
    tipShell.setLayout(gridLayout);
 
    tipShell.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
 
    tipLabelImage = new Label(tipShell, SWT.NONE);
    tipLabelImage.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
    tipLabelImage.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
    tipLabelImage.setLayoutData(
        new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER));
 
    tipLabelText = new Label(tipShell, SWT.NONE);
    tipLabelText.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
    tipLabelText.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
    tipLabelText.setLayoutData(
        new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER));
  }
 
  /**
   * Enables customized hover help for a specified control
   *
   * @control the control on which to enable hoverhelp
   */
  public void activateHoverHelp(final Control control) {
    // Get out of the way if we attempt to activate the control underneath the tooltip
    control.addMouseListener(new MouseAdapter() {
      public void mouseDown(MouseEvent e) {
        if (tipShell.isVisible())
          tipShell.setVisible(false);
      }
    });
 
    // Trap hover events to pop-up tooltip
    control.addMouseTrackListener(new MouseTrackAdapter() {
      public void mouseExit(MouseEvent e) {
        if (tipShell.isVisible())
          tipShell.setVisible(false);
        tipWidget = null;
      }
 
      public void mouseHover(MouseEvent event) {
        Point pt = new Point(event.x, event.y);
        Widget widget = event.widget;
        if (widget instanceof ToolBar) {
          ToolBar w = (ToolBar) widget;
          widget = w.getItem(pt);
        }
        if (widget instanceof Table) {
          Table w = (Table) widget;
          widget = w.getItem(pt);
        }
        if (widget instanceof Tree) {
          Tree w = (Tree) widget;
          widget = w.getItem(pt);
        }
        if (widget == null) {
          tipShell.setVisible(false);
          tipWidget = null;
          return;
        }
        if (widget == tipWidget)
          return;
        tipWidget = widget;
        tipPosition = control.toDisplay(pt);
        String text = (String) widget.getData("TIP_TEXT");
        Image image = (Image) widget.getData("TIP_IMAGE");
        tipLabelText.setText(text != null ? text : "");
        tipLabelImage.setImage(image); // accepts null
        tipShell.pack();
        setHoverLocation(tipShell, tipPosition);
        tipShell.setVisible(true);
      }
    });
 
    // Trap F1 Help to pop up a custom help box
    control.addHelpListener(new HelpListener() {
      public void helpRequested(HelpEvent event) {
        if (tipWidget == null)
          return;
        ToolTipHelpTextHandler handler = (ToolTipHelpTextHandler) tipWidget
            .getData("TIP_HELPTEXTHANDLER");
        if (handler == null)
          return;
        String text = handler.getHelpText(tipWidget);
        if (text == null)
          return;
 
        if (tipShell.isVisible()) {
          tipShell.setVisible(false);
          Shell helpShell = new Shell(parentShell, SWT.SHELL_TRIM);
          helpShell.setLayout(new FillLayout());
          Label label = new Label(helpShell, SWT.NONE);
          label.setText(text);
          helpShell.pack();
          setHoverLocation(helpShell, tipPosition);
          helpShell.open();
        }
      }
    });
  }
 
  /**
   * Sets the location for a hovering shell
   *
   * @param shell
   *            the object that is to hover
   * @param position
   *            the position of a widget to hover over
   * @return the top-left location for a hovering box
   */
  private void setHoverLocation(Shell shell, Point position) {
    Rectangle displayBounds = shell.getDisplay().getBounds();
    Rectangle shellBounds = shell.getBounds();
    shellBounds.x = Math.max(
        Math.min(position.x, displayBounds.width - shellBounds.width),
        0);
    shellBounds.y = Math.max(
        Math.min(position.y + 16, displayBounds.height
            - shellBounds.height), 0);
    shell.setBounds(shellBounds);
  }
 
  /**
   * ToolTip help handler
   */
  public interface ToolTipHelpTextHandler {
    /**
     * Get help text
     * @param widget
     *            the widget that is under help
     * @return a help text string
     */
    public String getHelpText(Widget widget);
  }
}

接著當需要放 tool tip 時,可以加入以下的程式碼。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Shell shell = new Shell();
ToolTipHandler tooltipHandler = new ToolTipHandler(shell.getShell());
 
// Initial table and table item.
Table table = new Table(shell, SWT.BORDER);
TableItem item = new TableItem(table, SWT.PUSH);
 
// Set properties about tool tip.
item.setData("TIP_TEXT", "tool tip");
item.setData("TIP_HELPTEXTHANDLER", new ToolTipHelpTextHandler() {
  public String getHelpText(Widget widget) {
    Item item = (Item) widget;
    return "tool tip"
  }
});
 
// Activate the tool tip on the table. (Bind events for the Control object)
tooltipHandler.activateHoverHelp(table);

不過詳細的原理我還沒仔細看,所以暫時先不加註語法的解釋了。
需要其他的範例的話,可以直接參考 [1] 的原始碼,上面有好幾種介面的使用範例
並且在 [1] 的範例中,都是有在 tool tip 上放圖的。

PS. 不過要直接執行 [1] 的範例程式碼時,記得自己放 notification.gif 和 warning.gif 兩個圖檔!

參考資料:
1、How to implement hover help feedback using the MouseTrackListener

沒有留言: