该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();
}