【问题标题】:java decrease time between mouseMotionListener intervalsjava减少mouseMotionListener间隔之间的时间
【发布时间】:2019-03-23 03:06:24
【问题描述】:

我想在java中创建一个简单的绘图程序,目前只使用Graphics.fillOval()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);
                    }
                }
            });
    }
}

有没有改进的方法或更好的方法?

【问题讨论】:

  • “减少 mouseMotionListener 间隔之间的时间” 我认为没有原生(即 Java)代码是无法做到的。为什么不保留报告的最后鼠标位置,然后如果到新位置的距离大于定义的量,则沿线绘制椭圆分隔两点?
  • 您所问的问题称为 XY 问题。您要求 X 的解决方案,而实际问题是 Y,修复 Y 也修复 X。在您的情况下,您想问如何“连接点”。

标签: java swing mousemotionlistener


【解决方案1】:
g=window.getGraphics();

首先,您不应该使用组件的 getGraphics()。您所做的任何绘制都只是暂时的,并且会在 Swing 第一次确定组件需要重新绘制时被删除。在上面的示例中,只需尝试调整框架的大小即可看到这一点。

进行自定义绘画的正确方法是覆盖 JPanel 的 paintComponent(...) 方法并将面板添加到框架中。请参阅Custom Painting 了解更多信息。

问题是,如果您快速移动鼠标,线条会变得不那么精确,并且椭圆(在这种情况下为圆形)会散开

您将无法为鼠标移动的每个像素生成一个事件。

相反,您需要能够在拖动鼠标时生成的连续点之间“画一条线”。

因此您需要将每个点存储在一个 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();
            }
        });
*/
    }
}

使用上述方法,您将在每次重新绘制组件时重新绘制线条。

另一种方法是绘制到BufferedImage,然后在面板上绘制BufferedImage。您可以查看Custom Painting Approaches 以获取此方法的示例。

【讨论】:

  • 谢谢。我是 Gui 编程新手,清理了很多。根据代码,我还有两个问题:1.super.paintComomponent(g) 用于基本擦除绘制的线条并将背景再次设置为白色对吗? 2.如果我想在鼠标点击时能够绘制形状,我需要修改repaint()method(并添加一个mouseListener)rigth?
  • 我不明白你的问题。我只能说你永远不会改变 repaint() 方法。我给了你一个“自定义绘画方法”的链接。阅读链接。它展示了如何跟踪要绘制的不同形状。
猜你喜欢
  • 2013-09-15
  • 1970-01-01
  • 1970-01-01
  • 2013-08-23
  • 2023-03-08
  • 2015-04-14
  • 2018-09-20
  • 1970-01-01
  • 2011-02-18
相关资源
最近更新 更多