java - 绘画应用程序 : Drag free-form lines (paths) with AffineTransform

标签 java swing graphics2d translate affinetransform

如何使用 AffineTransform 拖动自由形式的线条(路径)?

我正在用 Java 制作一个类似 Paint 的应用程序,其中一个要求是能够将绘制的自由形状拖到用于绘图的 JPanel 上的新位置。我一直在尝试让 AffineTransform 执行此操作一天,目前它所做的是选择所需的行(存储为 Path2D)并拖动它移动。但是,一旦不再选择任何行,该行将返回到其原始位置。此外,当我再次选择它时,它会立即显示在新位置(如果有意义的话);这可能是正在翻译的坐标系,但我不确定...... 任何帮助将不胜感激!也许有一种更简单的方法可以做到这一点。 PS 我还注意到,当移动任何绘制的线条时,除了最后绘制的线条外,所有在移动的线条之前绘制的线条都会随之移动。 这是代码:

public class DrawPanel extends JPanel {
public double translateX=0;
public double translateY=0;
public int lastOffsetX;
public int lastOffsetY;

class Line {
    public Point start;
    public Point end;
    public Color color;
    public Path2D path;
}

ArrayList<Line> lines = new ArrayList<Line>();
ArrayList<Path2D> paths = new ArrayList<Path2D>();
    boolean moveMode = false;

    Path2D selectedLine;
    int xDistance;
    int yDistance;


    public DrawPanel() {
            setBackground(Color.WHITE);
            setFocusable(true);
            requestFocusInWindow();

            this.addMouseMotionListener(new MouseMotionAdapter() {
                @Override
                public void mouseDragged(MouseEvent e) {
                    //System.out.println(resizeMode);
                        if (moveMode) {
                            if (selectedLine!=null) {
                                int newX = e.getX() - lastOffsetX;
                            int newY = e.getY() - lastOffsetY;
                            lastOffsetX += newX;
                            lastOffsetY += newY;
                            translateX += newX;
                        translateY += newY;
                                    repaint();
                            }
                        } else {

                                Path2D p = paths.get(paths.size() - 1);
                                p.lineTo(e.getX(), e.getY());
                                    repaint();
                        }
                }

                @Override
                public void mouseMoved(MouseEvent e) {
                        super.mouseMoved(e);
                        if (resizeMode) {
                                selectedLine = null;
                                for (Path2D l : paths) {
                                    if (l.contains(e.getPoint())) {
                                        selectedLine = l;
                                    } 
                                    }

                                repaint();
                        }
                }
        });

        this.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                        super.mousePressed(e);
                        if (!moveMode) {
                                Line l = new Line(e.getPoint());
                                l.path = new Path2D.Double();
                                l.path.moveTo(e.getX(), e.getY());
                                lines.add(l);
                                paths.add(l.path);
                        } else {
                                lastOffsetX = e.getX();
                            lastOffsetY = e.getY();
                        }
                        }

                }

                @Override
                public void mouseReleased(MouseEvent e) {
                        super.mouseReleased(e);
                        if (!resizeMode) {
                            if (selectedLine == null) {
                                Line l = lines.get(lines.size() - 1);
                                l.end = e.getPoint();
                                l.path.lineTo(e.getX(), e.getY());
                                Path2D p = paths.get(paths.size() - 1);
                                p.lineTo(e.getX(), e.getY());
                                repaint();
                            } 
                        } else {

                            for (int j=0; j<paths.size();j++) {
                             if (selectedLine!=null && selectedLine.equals(paths.get(j))) {
                                 paths.set(j, selectedLine);
                             }
                            }

                            repaint();
                        }
                }

                });
    }

        private void setKeyBindings() {
            ActionMap actionMap = getActionMap();
            int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
            InputMap inputMap = getInputMap(condition );
            String ctrl = "VK_CONTROL";
            String ctrl_rel = "control_released";
            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL, KeyEvent.CTRL_DOWN_MASK, false), ctrl);
            inputMap.put(KeyStroke.getKeyStroke(("released CONTROL")), ctrl_rel);

            actionMap.put(ctrl, new KeyAction(ctrl));
            actionMap.put(ctrl_rel, new KeyAction(ctrl_rel));
    }
        private class KeyAction extends AbstractAction {
            public KeyAction(String actionCommand) {
               putValue(ACTION_COMMAND_KEY, actionCommand);
            }

            @Override
            public void actionPerformed(ActionEvent actionEvt) {
               if(actionEvt.getActionCommand() == "VK_CONTROL") {
                   moveMode = true;
               }
               else if(actionEvt.getActionCommand() == "control_released") {
                   moveMode = false;
                   repaint();
               }

            }
         }

    @Override
    protected void paintComponent(Graphics g) {
         super.paintComponent(g);
         Graphics2D g2d = (Graphics2D)g;
         g2d.setColor(Color.BLACK);
         g2d.setStroke(new BasicStroke(10.0f));
         g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );

         if (moveMode) {
                    for (int j=0; j<paths.size();j++) {
                         Path2D path = paths.get(j);
                         if (selectedLine!=null && selectedLine.equals(path)) {
                             AffineTransform at = new AffineTransform();
                             at.translate(translateX, translateY);
                             g2d.transform(at);
                             g2d.setColor(Color.RED);
                             g2d.draw(path);
                             g2d.setColor(Color.BLACK);
                             continue;

                         }  
                             g2d.draw(path);
                             g2d.setColor(Color.BLACK);

                     }
         } else {
                for (int i =0; i < paths.size();i++) {
                Path2D path = paths.get(i);
                 g2d.draw(path); // outline
                 }
         }
    }

编辑以包含分辨率:所以最后我所做的是将所有路径的坐标(我从 PathIterator 获得)保存到 ArrayList,创建一个新的空路径,添加之前的路径的坐标从 ArrayList 到新路径(通过 moveTo、lineTo)并将新路径附加到所有绘制路径的 ArrayList。

最佳答案

如您所料,您的AffineTransform 改变了所有 后续绘图的图形上下文坐标系。

例子中引用了here ,每个形状都是 Node 类的一个实例。每个 Node 都包含一个 selected 属性,允许独立选择形状。当从 mouseDragged() 调用时,该值确定 updatePosition() 的效果。 updatePosition() 的实现只是更新每个选定节点的坐标,但您也可以使用 AffineTransformcreateTransformedShape()

关于java - 绘画应用程序 : Drag free-form lines (paths) with AffineTransform,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20029395/

相关文章:

java - Graphics2D 和 GraphicsContext 之间的互操作性

java - 强制完全重绘 Jpanel Java2D

java - 使用 Graphics2D 多次处理图像

java - 如何从android studio中的库模块调用 Activity

java - 重构一个简单填充的长方法

java - 排序后获取数组的索引?

java - 如何在单独的方法中使用不同的颜色重新绘制?

java - 为 Spring Security 设置 LDAP 查询超时

java - 根据用户输入显示多个对话框提示

java - 如何绘制双阿基米德螺线?