java - 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)
{
}
}
如果你运行它,你会看到用鼠标绘画时会有一个滞后,而且你走得越快,绘图就会分解成点。我该如何解决?我在想如果重绘速度超级快,那么点应该形成线条和曲线。
解决方案
画画的时候有很多东西要学。我已经做了相当多的图形,所以我修改了你的程序来说明。
JFrame
除非您打算覆盖某些内容,否则不要扩展。很少需要。- 在
JPanel
覆盖paintComponent()
. - 收集你的积分
array
或list
每次都通过它们。这是因为调用super.paintComponent()
将清除屏幕(但必须这样做)。 - 不是必需的,但我发现
MouseAdapter
在私有类中使用(或任何 *-Adapter)来处理事件很方便。 - 由于 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());
}
}
}
这个例子还是有问题的。例如,如果您释放鼠标按钮并定位到一个新位置然后单击,它将从最后一个点继续。可能有很多方法可以解决这个问题,但最简单的方法是拥有一个列表列表,其中每个列表是一组具有分离原点的单独点。
推荐阅读
- python - “TypeError:只能连接列表(不是“int”)来列出“我该如何处理这个
- d3.js - d3 来自分组数据数组的每个刻度的多个圆圈
- sorting - 有没有证明给定定理的好策略?
- terraform - 如何在本地进行变量定义?
- javascript - 编写我的第一个 HOF 反应组件时出错:如果您返回一个组件而不是返回,则可能会发生这种情况
- web-component - 嵌套的 Web 组件
- cmake - 如何从其他可执行文件中添加一个可执行文件的依赖项?
- c - 你能帮我找出这个基本 C 代码的问题吗
- python - 文件并进入 Jupiter 笔记本,我收到错误 UTF-8
- visual-studio-code - VSCode:“Markdown 预览”SHIFT-COMMAND-P 不起作用