该Java教程适用于JDK 8。本页面中描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
有关Java SE 9及以后版本中更新的语言功能的摘要,请参阅Java语言更改。
有关所有JDK版本的新功能、增强功能以及已删除或弃用选项的信息,请参阅JDK发行说明。
要使用户能够与显示的图形交互,您需要能够确定用户何时点击其中之一。 Graphics2D
类的 hit
方法提供了一种简单确定鼠标点击是否发生在特定 Shape
对象上的方法。或者您可以获取鼠标点击的位置并在 Shape
上调用 contains
来确定点击是否在 Shape
的边界内。
如果您使用的是基本文本,您可以通过获取与文本对应的轮廓 Shape
,然后使用该 Shape
调用 hit
或 contains
进行简单的命中测试。支持文本编辑需要更复杂的命中测试。如果您希望允许用户编辑文本,通常应使用 Swing 可编辑文本组件之一。如果您正在使用基本文本并使用 TextLayout
类来管理文本的形状和定位,则还可以使用 TextLayout
执行文本编辑的命中测试。有关更多信息,请参阅 Java 2D 程序员指南中的文本和字体章节或查看下面的 HitTestSample 示例,该示例使用 TextLayout
执行简单的命中测试。
此 applet 允许用户在 applet 窗口内拖动一个 Shape
。在用户拖动时,Shape
在每个鼠标位置上重新绘制以提供反馈。
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
。
此应用程序通过在用户单击TextLayout
时绘制默认的插入符号来演示命中测试,如下图所示。
包含了这个小程序的完整代码。HitTestSample.java
mouseClicked
方法使用TextLayout.hitTestChar
返回一个包含鼠标点击位置(插入索引)的java.awt.font.TextHitInfo
对象。
TextLayout
的getAscent
、getDescent
和getAdvance
方法返回的信息用于计算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(); }