java - 如何删除 Java Swing 中的行?

标签 java swing

我希望通过让用户能够删除他已经在 JPanel 上绘制的线条来为我的绘图应用程序提供一个额外的选项。

上面的代码是在JPanel上画线

谁能给我一个删除特定行的方法?

例如,一个方法使用户能够单击窗口中的按钮,然后选择特定行并删除。

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class DrawLine extends JPanel {

    private MouseHandler mouseHandler = new MouseHandler();
    private Point p1 = new Point(0, 0);
    private Point p2 = new Point(0, 0);
    private boolean drawing;

    //Store lines in an arraylist
    private ArrayList<Line> lines = new ArrayList<>();

    public DrawLine() {
        setBackground(Color.white);
        this.setPreferredSize(new Dimension(1200, 600));
        this.addMouseListener(mouseHandler);
        this.addMouseMotionListener(mouseHandler);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        //Grid start
        g.setColor(Color.lightGray);
        int sideLength = 20;
        int nRowCount = getHeight() / sideLength;
        int currentX = sideLength;
        for (int i = 0; i < nRowCount; i++) {
            g.drawLine(0, currentX, getWidth(), currentX);
            currentX = currentX + sideLength;
        }

        int nColumnCount = getWidth() / sideLength;
        int currentY = sideLength;
        for (int i = 0; i < nColumnCount; i++) {
            g.drawLine(currentY, 0, currentY, getHeight());
            currentY = currentY + sideLength;
        }
        //Grid end

        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.black);
        g2d.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setStroke(new BasicStroke(8,
            BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
        g.drawLine(p1.x, p1.y, p2.x, p2.y);

        //draw all previous lines
        for (int i = 0; i < lines.size(); i++) { 
            g.drawLine(lines.get(i).p1.x, lines.get(i).p1.y, lines.get(i).p2.x, lines.get(i).p2.y);
        }
    }

    private class MouseHandler extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            drawing = true;
            p1 = e.getPoint();
            p2 = p1;
            repaint();
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            drawing = false;
            p2 = e.getPoint();
            repaint();
            lines.add(new Line(p1, p2));
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (drawing) {
                p2 = e.getPoint();
                repaint();
            }
        }
    }

    private void display() {
        JFrame f = new JFrame("LinePanel");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new DrawLine().display();
            }
        });
    }

    public class Line {
        Point p1;
        Point p2;

        public Line(Point p1, Point p2) {
            this.p1 = p1;
            this.p2 = p2;
        }
    }
} 

删除一条线意味着从ArrayList中删除线坐标,但我的问题是如何在单击删除按钮时处理新的鼠标操作以及如何关闭旧的鼠标操作(那个让用户画线)

最佳答案

首先对于找到点击的线可以使用Line2D.Double(point1, point2).ptSegDist()方法。此方法返回线与给定点之间的距离。如果距离小于 4(因为您的笔画宽度为 8),则表示用户单击了该行。那是最难的部分。

之后,我在 Line 类中添加了一个 boolean 值成员来保留“点击”信息。最后,在删除操作中,我在 lines 列表中循环并删除选定的行。

请注意,我使用 isControlDown() 来确定用户是要选择一条线还是要绘制另一条线。因为我必须以某种方式决定所需的操作是什么。

public class DrawLine extends JPanel {

    private static final int LINE_WIDTH = 8;

    private MouseHandler mouseHandler = new MouseHandler();
    private Point p1 = null;
    private Point p2 = null;
    private boolean drawing;

    private Point draggingPoint = null;

    // Store lines in an arraylist
    private ArrayList<Line> lines = new ArrayList<>();

    public DrawLine() {
        setBackground(Color.white);
        this.setPreferredSize(new Dimension(400, 200));
        this.addMouseListener(mouseHandler);
        this.addMouseMotionListener(mouseHandler);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        // Grid start
        g.setColor(Color.lightGray);
        int sideLength = 20;
        int nRowCount = getHeight() / sideLength;
        int currentX = sideLength;
        for (int i = 0; i < nRowCount; i++) {
            g.drawLine(0, currentX, getWidth(), currentX);
            currentX = currentX + sideLength;
        }

        int nColumnCount = getWidth() / sideLength;
        int currentY = sideLength;
        for (int i = 0; i < nColumnCount; i++) {
            g.drawLine(currentY, 0, currentY, getHeight());
            currentY = currentY + sideLength;
        }
        // Grid end

        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.red);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setStroke(new BasicStroke(LINE_WIDTH, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));

        if (p1 != null && p2 != null) {
            g.drawLine(p1.x, p1.y, p2.x, p2.y);
        }

        // draw all previous lines
        for (int i = 0; i < lines.size(); i++) {
            Line line = lines.get(i);
            if (line.isSelected) {
                g2d.setColor(Color.red);
            } else {
                g2d.setColor(Color.blue);
            }
            g.drawLine(lines.get(i).p1.x, lines.get(i).p1.y, lines.get(i).p2.x, lines.get(i).p2.y);
        }
    }

    private void deSelectAll() {
        for (Line line : lines) {
            line.isSelected = false;
        }
    }

    private class MouseHandler extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            if (!e.isControlDown()) {
                drawing = true;
                p1 = e.getPoint();
                p2 = p1;
                repaint();
            } else {
                for (Line line : lines) {
                    line.isSelected = false;
                    if (isInside(line, e.getPoint())) {
                        line.isSelected = true;
                    }
                }

                draggingPoint = e.getPoint();

                repaint();
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (!e.isControlDown()) {
                drawing = false;
                p2 = e.getPoint();
                repaint();
                deSelectAll();
                lines.add(new Line(p1, p2));

                p1 = null;
                p2 = null;
            }
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (!e.isControlDown()) {
                if (drawing) {
                    p2 = e.getPoint();
                    repaint();
                }
            } else if (draggingPoint != null) {

                int XDiff = e.getPoint().x - draggingPoint.x;
                int YDiff = e.getPoint().y - draggingPoint.y;

                draggingPoint = e.getPoint();

                for (Line line : lines) {
                    if (line.isSelected) {
                        line.p1.x = line.p1.x + XDiff;
                        line.p1.y = line.p1.y + YDiff;
                        line.p2.x = line.p2.x + XDiff;
                        line.p2.y = line.p2.y + YDiff;
                    }
                }

                repaint();
            }
        }

        /**
         * Returns true if the given point is inside the given line.
         */
        private boolean isInside(Line line, Point p) {
            return new Line2D.Double(line.p1, line.p2).ptSegDist(p) < (LINE_WIDTH / 2);
        }
    }

    private void display() {
        JFrame f = new JFrame("LinePanel");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);

        f.add(new JButton(new DeleteLineAction()), BorderLayout.SOUTH);

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private class DeleteLineAction extends AbstractAction {

        public DeleteLineAction() {
            super("Delete");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            Iterator<Line> iterator = lines.iterator();

            while (iterator.hasNext()) {
                Line line = iterator.next();

                if (line.isSelected) {
                    iterator.remove();
                }
            }

            repaint();
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new DrawLine().display();
            }
        });
    }

    class Line {
        Point p1;
        Point p2;

        boolean isSelected;

        public Line(Point p1, Point p2) {
            this.p1 = p1;
            this.p2 = p2;

            isSelected = true;
        }
    }
}

关于java - 如何删除 Java Swing 中的行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36508760/

相关文章:

java - 通过URL导入图片并添加到面板时出错

java - 如何将主类中的TCP连接变量传递给另一个JFrame类?

java - 具有不同 xml 名称的相同响应对象

java - 如何修复 SwipeRefreshLayout 抖动?

java - ActionListener 内的递归

java - 单击 JFrame 中的 JButton 时如何更改现有图像? ( java )

java - 如何使我的 jframe 可滚动而不删除文本

java - 参数中的Java类型提升

java - 带有 BufferedImage 的 setRGB 提供不正确的着色

java - 如何缓存从 API 提取的数据中的图像和文本