Java,鼠标拖动AffineTransform

时间:2017-09-29 17:30:52

标签: java swing affinetransform custom-painting

我正在使用Java Swing。

我需要一个允许用户缩放绘图的应用程序。

图纸是在自定义的JPanel paintComponent方法内完成的。

一张图是一个drawRect方法调用。

在应用程序中,有两种方法(让我称之为"模式")缩放绘图:

  1. 调用方法时,只需增加图形的宽度和高度即可。例如:

    graphics.drawRect(x, y, width + addX, height + addY);
    

    其中addXaddY是用户鼠标拖动手势的偏移量。

  2. 在绘制绘图之前,使用/更改处理绘图缩放的AffineTransform。例如:

    graphics.transform(at);
    graphics.drawRect(x, y, width, height);
    
  3. 两种缩放模式组合在一起!

    用户将鼠标拖动到图形边缘以缩放图形。

    用户每次通过两个按钮选择启用哪种模式:第一种模式的1按钮("绘制比例")和第二种模式的1按钮(" AffineTransform scale" )。

    到目前为止,这是我的代码:

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Cursor;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.geom.AffineTransform;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class Main {
    
        //The panel which handles drawing:
        private static class PaintPanel extends JPanel {
            private final double drawX, drawY;
            private final AffineTransform at;
            private double drawWidth, drawHeight;
    
            public PaintPanel(final double drawX,
                              final double drawY,
                              final double drawWidth,
                              final double drawHeight) {
                at = new AffineTransform();
                this.drawX = drawX;
                this.drawY = drawY;
                this.drawWidth = drawWidth;
                this.drawHeight = drawHeight;
            }
    
            public AffineTransform getAffineTransform() {
                return at;
            }
    
            public double getDrawX() {
                return drawX;
            }
    
            public double getDrawY() {
                return drawY;
            }
    
            public double getDrawWidth() {
                return drawWidth;
            }
    
            public double getDrawHeight() {
                return drawHeight;
            }
    
            public double getTotalWidth() {
                return getDrawWidth() * getAffineTransform().getScaleX();
            }
    
            public double getTotalHeight() {
                return getDrawHeight() * getAffineTransform().getScaleY();
            }
    
            @Override
            public void paintComponent(final Graphics g) {
                super.paintComponent(g);
                final Graphics2D g2d = (Graphics2D) g.create();
    
                //Red rectangle for clarity.
                g.setColor(Color.RED);
                g.drawRect((int)getDrawX(), (int)getDrawY(), (int)getTotalWidth()-1, (int)getTotalHeight()-1);
    
                //The drawing!
                g2d.transform(getAffineTransform());
                g2d.drawRect((int)getDrawX(), (int)getDrawY(), (int)getDrawWidth()-1, (int)getDrawHeight()-1);
                g2d.drawOval((int)getDrawX(), (int)getDrawY(), (int)getDrawWidth()-1, (int)getDrawHeight()-1);
    
                g2d.dispose();
            }
    
            //The scale(...) method scales the drawing.
            //The scale(...) method needs changes.
            public void scale(final boolean drawScale,
                              final double addX,
                              final double addY) {
                if (drawScale) {
                    drawWidth += (addX / getAffineTransform().getScaleX());
                    drawHeight += (addY / getAffineTransform().getScaleY());
                }
                else {
                    final double tmpAddX = addX / getAffineTransform().getScaleX(),
                                 tmpAddY = addY / getAffineTransform().getScaleY();
                    final double sx = (getDrawWidth() + tmpAddX) / getDrawWidth(),
                                 sy = (getDrawHeight() + tmpAddY) / getDrawHeight();
    
                    getAffineTransform().scale(sx, sy);
    
                    final double tmpAddX2 = addX / getAffineTransform().getScaleX(),
                                 tmpAddY2 = addY / getAffineTransform().getScaleY();
                    final double sx2 = (getDrawWidth() + tmpAddX2) / getDrawWidth(),
                                 sy2 = (getDrawHeight() + tmpAddY2) / getDrawHeight();
    
                    getAffineTransform().translate(getDrawX() - getDrawX()*sx2,
                                                   getDrawY() - getDrawY()*sy2);
                }
                repaint();
            }
        }
    
        private static boolean drawScale;
    
        public static void main(final String[] args) {
            final Dimension dim = new Dimension(300, 300);
            final int drawOff = 100;
    
            final PaintPanel paintPanel = new PaintPanel(drawOff/2, drawOff/2, dim.width - 2*drawOff, dim.height - 2*drawOff);
            paintPanel.setPreferredSize(dim);
            final MouseAdapter ma = new MouseAdapter() {
                private Point dragLocation;
                private boolean dragX, dragY;
    
                //Tells if the width is dragged:
                private boolean isDragX(final Point loc) {
                    return (loc.getX() > paintPanel.getTotalWidth()-10+paintPanel.getDrawX()
                            && loc.getX() < paintPanel.getTotalWidth()+10+paintPanel.getDrawX()
                            && loc.getY() < paintPanel.getTotalHeight()+paintPanel.getDrawY()+10
                            && loc.getY() > paintPanel.getDrawY());
                }
    
                //Tells if the height is dragged:
                private boolean isDragY(final Point loc) {
                    return (loc.getY() > paintPanel.getTotalHeight()-10+paintPanel.getDrawY()
                            && loc.getY() < paintPanel.getTotalHeight()+10+paintPanel.getDrawY()
                            && loc.getX() < paintPanel.getTotalWidth()+paintPanel.getDrawX()+10
                            && loc.getX() > paintPanel.getDrawX());
                }
    
                //Only used to set the cursor:
                @Override
                public void mouseMoved(final MouseEvent mevt) {
                    final Point loc = mevt.getPoint();
                    if (isDragX(loc) && isDragY(loc))
                        paintPanel.setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
                    else if (isDragX(loc))
                        paintPanel.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
                    else if (isDragY(loc))
                        paintPanel.setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
                    else if (paintPanel.getCursor() != Cursor.getDefaultCursor())
                        paintPanel.setCursor(Cursor.getDefaultCursor());
                }
    
                //Determines (on mouse click) which sides are dragged:
                @Override
                public void mousePressed(final MouseEvent mevt) {
                    final Point loc = mevt.getPoint();
                    dragX = isDragX(loc);
                    dragY = isDragY(loc);
                    dragLocation = loc;
                }
    
                //Scales while dragging:
                @Override
                public void mouseDragged(final MouseEvent mevt) {
                    final Point loc = mevt.getPoint();
                    if (dragX && dragY)
                        paintPanel.scale(drawScale, loc.getX()-dragLocation.getX(), loc.getY()-dragLocation.getY());
                    else if (dragX)
                        paintPanel.scale(drawScale, loc.getX()-dragLocation.getX(), 0);
                    else if (dragY)
                        paintPanel.scale(drawScale, 0, loc.getY()-dragLocation.getY());
                    dragLocation = loc;
                }
            };
            paintPanel.addMouseListener(ma);
            paintPanel.addMouseMotionListener(ma);
    
            final JButton drawScaleButton = new JButton("Draw scale"),
                          affineTransformScaleButton = new JButton("AffineTransform scale");
            drawScaleButton.addActionListener(e -> {
                drawScale = true;
                drawScaleButton.setEnabled(false);
                affineTransformScaleButton.setEnabled(true);
            });
            affineTransformScaleButton.addActionListener(e -> {
                drawScale = false;
                drawScaleButton.setEnabled(true);
                affineTransformScaleButton.setEnabled(false);
            });
            drawScale = false;
            drawScaleButton.setEnabled(true);
            affineTransformScaleButton.setEnabled(false);
    
            final JPanel buttons = new JPanel(/*FlowLayout*/);
            buttons.add(affineTransformScaleButton);
            buttons.add(drawScaleButton);
    
            final JPanel contents = new JPanel(new BorderLayout());
            contents.add(buttons, BorderLayout.PAGE_START);
            contents.add(paintPanel, BorderLayout.CENTER);
    
            final JFrame frame = new JFrame("Scaling shape test");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(contents);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    }
    

    问题是我无法正确组合这两种模式。我需要AffineTransform对象相应地改变用户的拖动手势,这样当变换应用于绘图时,绘图将缩放用户鼠标所在的位置。

    为清晰起见,代码将绘图绘制在红色矩形内。缩放模式后的绘图大小必须仍然在红色矩形内,但它不是,这就是问题。

    以下是演示此问题的屏幕截图:

    problemDemoImage

    要重新创建问题,您可以执行以下步骤:

    1. 拖动图纸将其放大,直至到达框架的两侧。
    2. 选择&#34;绘制比例&#34;。
    3. 拖动绘图尽可能小(但也可见)。
    4. 选择&#34; AffineTransform scale&#34;。
    5. 重复上述步骤一次或两次,问题应该是可见的。

0 个答案:

没有答案