支持用户互动

为了使用户能够与您显示的图形进行交互,您需要能够确定用户何时单击其中的一个。 Graphics2D类的hit方法提供了一种轻松确定在特定Shape对象上是否发生鼠标单击的方法。或者,您可以获取鼠标单击的位置,然后在Shape上调用contains以确定单击是否在Shape的范围内。

如果您正在使用原始文本,则可以通过获取与文本对应的轮廓Shape,然后使用Shape调用hitcontains来执行简单的点击测试。支持文本编辑需要更复杂的命中测试。如果要允许用户编辑文本,通常应使用 Swing 可编辑文本组件之一。如果您正在使用原始文本并使用TextLayout类来 管理 文本的形状和位置,则还可以使用TextLayout进行命中测试以进行文本编辑。有关更多信息,请参见Java 2D 程序员指南中的文本和字体一章,或参见下面的 HitTestSample 示例,该示例使用TextLayout执行简单的点击测试。

Example: ShapeMover

此 Servlets 允许用户在 Servlets 窗口中拖动Shape。在每个鼠标位置重新绘制Shape,以在用户拖动鼠标时提供反馈。

Note:

如果看不到 Servlets 正在运行,则需要至少安装Java SE 开发套件(JDK)7版本。

ShapeMover.java包含此 Servlets 的完整代码。

调用contains方法可确定按下鼠标时光标是否在矩形的边界内。如果是,则矩形的位置将更新。

public void mousePressed(MouseEvent e){
    last_x = rect.x - e.getX();
    last_y = rect.y - e.getY();
    if(rect.contains(e.getX(),
        e.getY())) updateLocation(e);
    ...

public void updateLocation(MouseEvent e){
    rect.setLocation(last_x + e.getX(),
        last_y + e.getY());
    ...
    repaint();

您可能会注意到在每个鼠标位置重绘Shape的速度很慢,因为填充的矩形每次移动都会重新渲染。使用 Double 缓冲可以消除此问题。如果使用 Swing,则图形将自动被 Double 缓冲;您根本不需要更改渲染代码。该程序的 Swing 版本的代码是SwingShapeMover.java

Example: HitTestSample

该应用程序通过在用户单击TextLayout的任何位置绘制默认插入记号来说明命中测试,如下图所示。

Note:

如果看不到 Servlets 正在运行,则需要至少安装Java SE 开发套件(JDK)7版本。

HitTestSample.java包含此 Servlets 的完整代码。

mouseClicked方法使用TextLayout.hitTestChar返回一个java.awt.font.TextHitInfo对象,该对象包含TextLayout对象中的鼠标单击位置(插入索引)。

TextLayout getAscentgetDescentgetAdvance方法返回的信息用于计算TextLayout对象的原点位置,因此它在水平和垂直方向上居中。

...

private Point2D computeLayoutOrigin() {
  Dimension size = getPreferredSize();
  Point2D.Float origin = new Point2D.Float();
     
  origin.x = (float) (size.width -
             textLayout.getAdvance()) / 2;   
  origin.y = 
    (float) (size.height -
             textLayout.getDescent() +
             textLayout.getAscent())/2;
  return origin;
}

...

public void paintComponent(Graphics g) {
  super.paintComponent(g);
  setBackground(Color.white);
  Graphics2D graphics2D = (Graphics2D) g;                
  Point2D origin = computeLayoutOrigin();
  graphics2D.translate(origin.getX(),
                       origin.getY());
                
  // Draw textLayout.
  textLayout.draw(graphics2D, 0, 0);
     
  // Retrieve caret Shapes for insertionIndex.
  Shape[] carets =
      textLayout.getCaretShapes(insertionIndex);
       
  // Draw the carets.  carets[0] is the strong
  // caret and carets[1] is the weak caret.   
  graphics2D.setColor(STRONG_CARET_COLOR);
  graphics2D.draw(carets[0]);                
  if (carets[1] != null) {
    graphics2D.setColor(WEAK_CARET_COLOR);
    graphics2D.draw(carets[1]);
  }       
}

...

private class HitTestMouseListener
              extends MouseAdapter {
                
    /**
     * Compute the character position of the
     * mouse click.
     */     
    public void mouseClicked(MouseEvent e) {
                
      Point2D origin = computeLayoutOrigin();
                
      // Compute the mouse click location
      // relative to textLayout's origin.
      float clickX =
          (float) (e.getX() - origin.getX());
      float clickY =
          (float) (e.getY() - origin.getY());
         
      // Get the character position of the
      // mouse click.
      TextHitInfo currentHit =
          textLayout.hitTestChar(clickX, clickY);
      insertionIndex =
          currentHit.getInsertionIndex();
            
      // Repaint the Component so the new
      // caret(s) will be displayed.
      hitPane.repaint();
    }