文档

Java™教程
隐藏目录
支持用户交互
路径: 2D图形
教程: Java2D高级主题

支持用户交互

要使用户能够与显示的图形交互,您需要能够确定用户何时点击其中之一。 Graphics2D 类的 hit 方法提供了一种简单确定鼠标点击是否发生在特定 Shape 对象上的方法。或者您可以获取鼠标点击的位置并在 Shape 上调用 contains 来确定点击是否在 Shape 的边界内。

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

示例:ShapeMover

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


注意:  如果您看不到 applet 运行,请安装至少 Java SE Development Kit (JDK) 7 版本。

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

在鼠标按下时,调用 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,这样会导致绘制的矩形每次移动都重新渲染,从而变慢。使用双缓冲可以消除这个问题。如果你使用Swing,绘制将自动进行双缓冲;你不需要改变渲染代码。这个程序的Swing版本的代码是SwingShapeMover.java

示例:HitTestSample

此应用程序通过在用户单击TextLayout时绘制默认的插入符号来演示命中测试,如下图所示。


注意:  如果您看不到运行的小程序,则需要安装至少Java SE Development Kit (JDK) 7版本。

HitTestSample.java包含了这个小程序的完整代码。

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

TextLayoutgetAscentgetDescentgetAdvance方法返回的信息用于计算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());
                
  // 绘制textLayout
  textLayout.draw(graphics2D, 0, 0);
     
  // 获取插入点的插入符形状
  Shape[] carets =
      textLayout.getCaretShapes(insertionIndex);
       
  // 绘制插入符。carets[0]为强插入符,carets[1]为弱插入符
  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 {
                
    /**
     * 计算鼠标点击的字符位置。
     */     
    public void mouseClicked(MouseEvent e) {
                
      Point2D origin = computeLayoutOrigin();
                
      // 计算鼠标点击位置相对于textLayout原点的位置
      float clickX =
          (float) (e.getX() - origin.getX());
      float clickY =
          (float) (e.getY() - origin.getY());
         
      // 获取鼠标点击位置的字符位置
      TextHitInfo currentHit =
          textLayout.hitTestChar(clickX, clickY);
      insertionIndex =
          currentHit.getInsertionIndex();
            
      // 重绘组件,以显示新的插入符
      hitPane.repaint();
    }

上一页: 从几何原始体构建复杂形状
下一页: 尾页