首页 > 解决方案 > Java Swing 重绘延迟

问题描述

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

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)
    {

    }
}

如果你运行它,你会看到用鼠标绘画时会有一个滞后,而且你走得越快,绘图就会分解成点。我该如何解决?我在想如果重绘速度超级快,那么点应该形成线条和曲线。

标签: javaswingrepaint

解决方案


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

  1. JFrame除非您打算覆盖某些内容,否则不要扩展。很少需要。
  2. JPanel覆盖paintComponent().
  3. 收集你的积分arraylist每次都通过它们。这是因为调用super.paintComponent()将清除屏幕(但必须这样做)。
  4. 不是必需的,但我发现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());
      }
   }
}

这个例子还是有问题的。例如,如果您释放鼠标按钮并定位到一个新位置然后单击,它将从最后一个点继续。可能有很多方法可以解决这个问题,但最简单的方法是拥有一个列表列表,其中每个列表是一组具有分离原点的单独点。


推荐阅读