Java Swing 重绘延迟

Java Swing Repaint Latency

我有一个简单的绘画程序:

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

public class CanvasPanel extends JFrame implements MouseMotionListener
{
    private int x1, y1, x2, y2;
    public CanvasPanel()
    {
        addMouseMotionListener(this);
        setBounds(50,50,400,250);
        setVisible(true);
    }

    public static void main(String[] argv)
    {
        new CanvasPanel();
    }

    public void update(Graphics g)
    {
        paint(g);
    }

    public void paint(Graphics g)
    {
        g.setColor(Color.black);
        g.drawLine(x1, y1, x2, y2);
    }

    public void mouseDragged(MouseEvent mouseEvent)
    {
        mouseEvent.consume();
        int x = mouseEvent.getX();
        int y = mouseEvent.getY();

        if ( x1 == 0 )
        {
            x1 = x;
        }

        if ( y1 == 0 )
        {
            y1 = y;
        }

        x2 = x;
        y2 = y;
        repaint();
        x1 = x2;
        y1 = y2;
    }

    public void mouseMoved(MouseEvent me)
    {

    }
}

如果你 运行 它,你会发现用鼠标绘图时会有延迟,你画得越快,绘图就会分解成点。我该如何解决?我在想如果重绘速度超快,那么点应该形成直线和曲线。

画画要学的东西还是挺多的。我已经做了相当多的图形,所以我修改了你的程序来说明。

  1. 不要扩展 JFrame 除非您打算覆盖某些内容。很少需要。
  2. 在覆盖 paintComponent()JPanel 中绘画。
  3. 每次通过 arraylist 到 运行 收集您的积分。这是因为调用 super.paintComponent() 会清除屏幕(但必须这样做)。
  4. 不需要,但我发现在私有 class 中使用 MouseAdapter(或任何 *-Adapter)来处理事件很方便。
  5. 由于 Swing 不是线程安全的,因此最好在 EDT 中启动它。只需确保在 EDT 期间没有进行长时间处理,否则您的程序将锁定并变得无响应。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class CanvasPanel extends JPanel {
   List<Point> points = new ArrayList<>();
   // Use compositon over inheritance.
   // Don't extend JFrame unless you plan to override something.
   JFrame      frame  = new JFrame();

   public static void main(String[] args) {
      SwingUtilities.invokeLater(() -> new CanvasPanel());
   }
   public CanvasPanel() {
      MyMouseListener ml = new MyMouseListener();
      addMouseMotionListener(ml);
      addMouseListener(ml);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setPreferredSize(new Dimension(500, 500));
      frame.add(this);
      frame.pack();
      frame.setLocationRelativeTo(null); // center on screen
      frame.setVisible(true);
   }

   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.setColor(Color.black);
      if (points.size() >= 2) {
         Iterator<Point> it = points.iterator();
         Point p1 = it.next();
         while (it.hasNext()) {
            Point p2 = it.next();
            g.drawLine(p1.x, p1.y, p2.x, p2.y);
            p1 = p2;
         }
      }
   }

   // MouseAdapter provides dummy implementations
   private class MyMouseListener extends MouseAdapter {
      public void mouseDragged(MouseEvent me) {
         points.add(me.getPoint());
         repaint();

      }
      public void mousePressed(MouseEvent me) {
         // initialize first point in list.
         points.add(me.getPoint());
      }
   }
}

这个例子还有问题。例如松开鼠标按键,定位到新的位置再点击,就会从最后一点继续。可能有很多方法可以解决这个问题,但最简单的方法是拥有一个列表列表,其中每个列表都是一组独立的点,具有分离的起源。