简体   繁体   English

Java Swing重绘延迟

[英]Java Swing Repaint Latency

I have a simple paint program: 我有一个简单的绘画程序:

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

    }
}

If you run it, you will see that there is a lag when painting with your mouse and the drawing will disintegrate into dots the faster you go. 如果运行它,您将看到用鼠标绘画时会有滞后,并且绘制得越快,分解成的点就越少。 How do I fix this? 我该如何解决? I was thinking if the repaint is super fast, then the dots should form into lines and curves. 我在想,如果重新绘制速度非常快,那么点应该形成直线和曲线。

There are quite a few things to learn when painting. 绘画时要学习很多东西。 I have done a fair amount of graphics so I modified your program to illustrate. 我已经做了大量的图形工作,所以我修改了程序以进行说明。

  1. Don't extend JFrame unless you plan to override something. 除非您打算覆盖某些内容,否则不要扩展JFrame It is seldom necessary. 几乎没有必要。
  2. Do your painting in a JPanel that overrides paintComponent() . 在覆盖paintComponent()JPanel中进行绘画。
  3. Collect your points in an array or list to run thru them each time. 将您的点收集在一个arraylist ,以便每次都可以遍历它们。 This is because the call to super.paintComponent() will clear the screen (but it is necessary to do so). 这是因为对super.paintComponent()的调用将清除屏幕(但有必要这样做)。
  4. Not required but I find it convenient to use MouseAdapter (or any *-Adapter) in a private class to handle events. 不需要,但是我发现在私有类中使用MouseAdapter (或任何* -Adapter)来处理事件很方便。
  5. Since Swing is not thread safe it is a good idea to start it in the EDT. 由于Swing不是线程安全的,因此最好在EDT中启动它。 Just make certain that no long processing is done while in the EDT or your program will lock up and become unresponsive. 只需确保在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());
      }
   }
}

This example still has problems. 这个例子仍然有问题。 For example, if you release the mouse button and position to a new location and then click, it will continue from the last point. 例如,如果释放鼠标按钮并将其定位到新位置,然后单击,它将从最后一点继续。 There are probably many ways to fix this but the simplest would be to have a list of lists, where each list is a separate set of points with detached origins. 可能有很多方法可以解决此问题,但是最简单的方法是拥有一个列表列表,其中每个列表都是一个单独的点集,这些点具有不同的起点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM