java - java减少mouseMotionListener间隔之间的时间
问题描述
我想在 java 中创建一个简单的绘图程序,目前只使用Graphics.fillOval()
和 a绘制一条线mouseMotionListener()
。问题是,如果您快速移动鼠标,线条会变得不那么精确,并且椭圆(在这种情况下为圆形)会散开。
这是代码:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Drawing
{
private JFrame window;
private Graphics g;
public Drawing()
{
window=new JFrame();
window.setTitle("Paint_window");
window.setSize(1000,700);
window.setVisible(true);
window.setDefaultCloseOperation(window.EXIT_ON_CLOSE);
g=window.getGraphics();
window.addMouseMotionListener(new MouseMotionAdapter()
{
public void mouseDragged(MouseEvent e)
{
if(SwingUtilities.isLeftMouseButton(e)
{
g.fillOval((int)e.getX(),(int)e.getY(),10,10);
}
}
});
}
}
有没有办法改进这个或更好的方法?
解决方案
g=window.getGraphics();
首先,您不应该使用组件的 getGraphics() 。您所做的任何绘制都只是暂时的,并且会在 Swing 第一次确定组件需要重新绘制时被删除。在上面的示例中,只需尝试调整框架的大小即可看到这一点。
进行自定义绘画的正确方法是覆盖paintComponent(...)
JPanel 的方法并将面板添加到框架中。有关详细信息,请参阅自定义绘画。
问题是,如果您快速移动鼠标,则线条会变得不那么精确,并且椭圆(在这种情况下为圆形)会散开
您将无法为鼠标移动的每个像素生成一个事件。
相反,您需要能够在拖动鼠标时生成的连续点之间“画一条线”。
因此,您需要将每个点存储在 ArrayList 中,并在自定义绘画代码中遍历所有点并绘制一条线。
一个让您入门的基本示例:
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
class DrawingPanel extends JPanel
{
private ArrayList<ArrayList<Point>> previous = new ArrayList<ArrayList<Point>>();
private ArrayList<Point> current = new ArrayList<Point>();
private BasicStroke basicStroke;
public DrawingPanel(int strokeSize)
{
basicStroke = new BasicStroke(strokeSize, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
MouseAdapter ma = new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
current.add( new Point(e.getX(), e.getY()) );
}
@Override
public void mouseDragged(MouseEvent e)
{
current.add( new Point(e.getX(), e.getY()) );
repaint();
}
@Override
public void mouseReleased(MouseEvent e)
{
if (current.size() > 1)
{
previous.add( current );
}
current = new ArrayList<Point>();
}
};
addMouseMotionListener( ma );
addMouseListener( ma );
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke( basicStroke );
// Paint lines from previous drags
for (int i = 0; i < previous.size(); i++)
{
drawLines(g, previous.get(i));
}
// Paint line from current drag
drawLines(g, current);
}
private void drawLines(Graphics g, ArrayList<Point> points)
{
for (int i = 0; i < points.size() - 1; i++)
{
int x = (int) points.get(i).getX();
int y = (int) points.get(i).getY();
int x2 = (int) points.get(i + 1).getX();
int y2 = (int) points.get(i + 1).getY();
g.drawLine(x, y, x2, y2);
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Drawing Panel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawingPanel(15));
frame.setSize(400, 400);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
使用上述方法,您将在每次重新绘制组件时重新绘制线条。
另一种方法是绘制到 aBufferedImage
然后BufferedImage
在面板上绘制。您可以查看自定义绘画方法以获取此方法的示例。
推荐阅读
- docker - 一台主机上有多个 GitLab Runner Docker 实例?
- android - react-native 中使用 AsyncStorage.setItem() 持久化的数据可以从本机代码中获取吗?
- cmake - 使用 Clion 编译 .o 文件
- java - MapStruct:BeanMapping 和 Mapping 的区别
- node.js - 如何使用 Angular 应用程序作为 Node.js 的视图引擎
- postgresql - PostgreSQL:更新大表
- sql - 如何从具有相似列名的不同不相关表中获取列?
- c# - 如何检查字符串是否包含一定数量的字母和数字C#
- python - groupby 后保留形状
- xml - 有没有办法使用 XSLT 解决返回的数据数组中的 XML 命名空间冲突