Java教程是针对JDK 8编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,并可能使用不再可用的技术。
请查看Java语言更改,了解Java SE 9及其后续版本中更新的语言功能的概述。
请查看JDK发布说明,了解有关所有JDK版本的新功能、增强功能以及已删除或已弃用选项的信息。
最后,我们将添加事件处理代码,以在用户单击或拖动鼠标时以编程方式重绘组件。为了使我们的自定义绘制尽可能高效,我们将跟踪鼠标坐标,并仅重绘屏幕上已更改的区域。这是一种推荐的最佳实践,将使您的应用程序尽可能高效地运行。
已完成的应用程序
点击“启动”按钮使用Java™ Web Start(下载JDK 7或更高版本)来运行SwingPaintDemo3。或者,要自己编译和运行示例,请参考示例索引。
package painting; import javax.swing.SwingUtilities; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.BorderFactory; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseMotionListener; import java.awt.event.MouseMotionAdapter; public class SwingPaintDemo3 { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } private static void createAndShowGUI() { System.out.println("在EDT上创建GUI?"+ SwingUtilities.isEventDispatchThread()); JFrame f = new JFrame("Swing绘制演示"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(new MyPanel()); f.pack(); f.setVisible(true); } } class MyPanel extends JPanel { private int squareX = 50; private int squareY = 50; private int squareW = 20; private int squareH = 20; public MyPanel() { setBorder(BorderFactory.createLineBorder(Color.black)); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { moveSquare(e.getX(),e.getY()); } }); addMouseMotionListener(new MouseAdapter() { public void mouseDragged(MouseEvent e) { moveSquare(e.getX(),e.getY()); } }); } private void moveSquare(int x, int y) { int OFFSET = 1; if ((squareX!=x) || (squareY!=y)) { repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET); squareX=x; squareY=y; repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET); } } public Dimension getPreferredSize() { return new Dimension(250,200); } protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawString("这是我的自定义面板!",10,20); g.setColor(Color.RED); g.fillRect(squareX,squareY,squareW,squareH); g.setColor(Color.BLACK); g.drawRect(squareX,squareY,squareW,squareH); } }
这个改变首先从java.awt.event
包中导入各种鼠标类,使应用程序能够响应用户的鼠标活动。构造函数已经更新为注册鼠标按下和拖动的事件监听器。每当接收到MouseEvent
时,它会被转发到moveSquare
方法,该方法会更新正方形的坐标并以智能的方式重新绘制组件。请注意,默认情况下,放置在这些事件处理程序中的任何代码都将在事件分派线程上执行。
但最重要的变化是调用repaint
方法。该方法由java.awt.Component
定义,是允许您以编程方式重新绘制任何给定组件的表面的机制。它有一个无参版本(重新绘制整个组件)和一个多参数版本(仅重新绘制指定区域)。这个区域也被称为剪辑。调用repaint
的多参数版本需要额外的努力,但可以确保您的绘图代码不会浪费时间重新绘制未更改的屏幕区域。
由于我们手动设置了剪辑,我们的moveSquare
方法不止一次地调用了repaint方法,而是两次。第一次调用告诉Swing重新绘制组件中以前的正方形所在的区域(继承的行为使用UI Delegate将该区域填充为当前的背景颜色)。第二次调用绘制组件中正方形当前所在的区域。值得注意的一点是,虽然我们在同一个事件处理程序中连续两次调用repaint,但Swing足够智能,可以将这些信息作为一个单一的绘制操作一次性地重新绘制屏幕的那些部分。换句话说,即使代码看起来是连续两次重新绘制组件,Swing也不会连续两次重新绘制组件。
练习: