如何在不改变[EDITED]的情况下使用AffineTransform缩放JScrollPane

时间:2014-04-13 11:03:04

标签: java swing input zoom graphics2d

我正在尝试为我的游戏编辑器实现缩放工具。我正在使用Color []来存储所有“Colors / tiles”,我希望能够在我的JPanel中放大以查看所有关闭或远离的图块,即放大或缩小。这些是我想要的一些要求(任何例子都受到赞赏,它们不需要包括所有或任何要求。它们可以帮助您理解我的目标):

  • 缩放应由可动态更改的缩放变量确定(最好是mouseWheel)
  • 当放大(进或出)时,您应该能够尽可能少地撕裂或其他图形故障(使用示例中的JScrollBar)进行无人驾驶和垂直导航。
  • 缩放应基于鼠标光标的位置并向该点缩放
  • 缩放可以使用普通Java中的任何内容,这意味着没有外部库。

这是我编辑器的一个非常简单的版本。我添加了一些缩放测试代码,但它不起作用。我给你这个代码,所以你有必要从一开始就有必要。请参阅PaintComponent方法和mouseWheel侦听器。

已编辑:感谢@trashgod,您现在可以将颜色放置在正确的位置。请参阅MouseTest类! 撕裂了。

package stuff;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Scrollable;
import javax.swing.SwingUtilities;

public class ZoomPane extends JPanel implements MouseWheelListener, Scrollable {

private int width, height, screenWidth, screenHeight, tileSize;
private Color[] colorMap;
private double scale = 1.0;

// Zooming
AffineTransform at;

class MouseTest extends MouseAdapter {
    public void mousePressed(MouseEvent e) {
        try {
            int newX = (int) at.inverseTransform(e.getPoint(), null).getX();
            int newY = (int) at.inverseTransform(e.getPoint(), null).getY();
            colorMap[(newX / tileSize) + ((newY / tileSize) * width)] = getRandomColor();

        } catch (NoninvertibleTransformException e1) {
            e1.printStackTrace();
        }
        repaint();
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        super.mouseDragged(e);
        try {
            System.out.println("Dragging");
            int newX = (int) at.inverseTransform(e.getPoint(), null).getX();
            int newY = (int) at.inverseTransform(e.getPoint(), null).getY();
            colorMap[(newX / tileSize) + ((newY / tileSize) * width)] = getRandomColor();

        } catch (NoninvertibleTransformException e1) {
            e1.printStackTrace();
        }
        repaint();
    }
}

public ZoomPane(int width, int height, int tileSize) {
    super();
    this.width = width;
    this.height = height;
    this.screenWidth = width * tileSize;
    this.screenHeight = height * tileSize;
    this.tileSize = tileSize;
    this.colorMap = new Color[width * height];
    addMouseWheelListener(this);
    addMouseListener(new MouseTest());
    addMouseMotionListener(new MouseTest());
}

public void paintComponent(Graphics g) {
    super.paintComponents(g);
    final Graphics2D g2d = (Graphics2D) g.create();

    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    // Scale
    at = null;
    at = g2d.getTransform();
    // Translate code here?

    at.scale(scale, scale);

    g2d.setTransform(at);
    final Rectangle clip = g2d.getClipBounds();

    g2d.setColor(Color.DARK_GRAY);
    g2d.fill(clip);

    int topX = clip.x / tileSize;
    int topY = clip.y / tileSize;
    int bottomX = clip.x + clip.width / tileSize + 1 + (int) (tileSize * scale);
    int bottomY = clip.y + clip.height / tileSize + 1;

    // Draw colors
    for (int y = topY; y < bottomY; y++) {
        for (int x = topX; x < bottomX; x++) {
            Rectangle r = new Rectangle(width, height);
            if (r.contains(x, y) && colorMap[x + y * width] != null) {
                g2d.setColor(colorMap[x + y * width]);
                g2d.fillRect(x * tileSize, y * tileSize, tileSize, tileSize);
            }
        }
    }
    g2d.dispose();
}

private Color getRandomColor() {
    Random rand = new Random();
    return new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255));
}

@Override
public Dimension getPreferredSize() {
    return new Dimension((int) (screenWidth), (int) (screenHeight));
}

@Override
public void mouseWheelMoved(MouseWheelEvent e) {
    double delta = 0.05 * e.getPreciseWheelRotation();
    if (scale + delta > 0)
        scale += delta;
    revalidate();
    repaint();
}

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            JFrame frame = new JFrame("Zoom test");
            // Frame settings
            frame.setVisible(true);
            frame.setPreferredSize(new Dimension(800, 600));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JScrollPane pane = new JScrollPane(new ZoomPane(50, 50, 32));
            frame.add(pane);
            frame.pack();
        }
    });

}

@Override
public Dimension getPreferredScrollableViewportSize() {
    repaint();
    return null;
}

@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
    repaint();
    return 0;
}

@Override
public boolean getScrollableTracksViewportHeight() {
    repaint();
    return false;
}

@Override
public boolean getScrollableTracksViewportWidth() {
    repaint();
    return false;
}

@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
    repaint();
    return 0;
}

}

如果您尝试运行该程序,您将看到以下问题:

  • 当您移动JScrollBars时,它会在您尝试放置颜色时接触到鼠标位置获得偏移。
  • 如果你缩放/滚动鼠标,那么一切都会向上/向下和向左/向右移动。我想放大鼠标光标/点或至少不要将所有东西都移到一边。

这是目前有效的方法:

  • 现在可以正确放置颜色。
  • 移动verticaly或horizo​​ntaly不再撕裂。

正如你所看到的那样,我在顶部提到的大多数要求都可以在SO上的文章中找到,其中大多数都非常好并且描述得很好但是我不知道/不能实现它们以便我可以解决上面的问题。

我使用此缩放的目标就像here中的示例,除了绘制我的“Colors / tiles”而不是他绘制的矩形以及我正在使用AffineTransform。否则那个例子就是我的目标。

它不必使用他使用的任何代码。我会更喜欢使用AffineTransform。如果你们中的任何一个人知道如何以另一种方式实现我正在寻找的东西,那我就是全部的耳朵。我认为这个例子可能会让你们更容易理解我的目标。

我接受有关代码或实现的任何更改或评论,我会尽快回复并更改帖子。

非常感谢, Towni0

0 个答案:

没有答案