AffineTransform存在的问题

3

你好,我对 Java 中的 affineTransform 还不熟悉。我想用它来扭曲一些 GUI,以便稍后使用。 目前,我只是想测试一段示例代码,但我无法解释它的输出。 下面是代码:

    package main;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.geom.AffineTransform;

    import javax.swing.BorderFactory;
    import javax.swing.JFrame;
    import javax.swing.JPanel;

    public class MainClass{
    public static void main(String[] args) {
    JFrame jf = new JFrame("Demo");

    jf.getContentPane().add(new MyCanvas());

    jf.setSize(600, 600);
    jf.setVisible(true);
  }
}

    class Left extends JPanel {

    Left(){
        setPreferredSize(new Dimension(450,450));
        setBorder(BorderFactory.createLineBorder(Color.green));
        setBackground(Color.gray);

    }


      public void paintComponent(Graphics g) {

            super.paintComponent(g);

            Graphics2D g2 = (Graphics2D) g;

            AffineTransform at = new AffineTransform();

            g2.setTransform(at);

            g2.drawRect(getWidth()/2 - 10, getHeight()/2 - 10, 20, 20);

          }
}

    class MyCanvas extends JPanel {

    MyCanvas()
    {
        setBorder(BorderFactory.createLineBorder(Color.red));
        setLayout(new FlowLayout(FlowLayout.CENTER));
        add(new Left());
    }


}

我想在Left类中绘制的矩形应该出现在中心右边?但它偏向左边...看起来它是相对于外框架取得它的坐标。如果我删除g2.setTransform(at);,它就会正常显示...你能解释一下为什么吗?


你怎么能够执行 g2.getWidth() 呢? - coder
+1 for sscce - trashgod
4个回答

7
setTransform 方法仅用于在渲染后恢复原始的 Graphics2D 变换。话虽如此,你永远不应该在现有变换上叠加新的坐标变换,因为 Graphics2D 可能已经有一个为其他用途(如渲染 Swing 组件)所需的变换。你的代码就体现了这一点。要添加坐标变换,请使用 transformrotatescaleshear 方法。

1
你必须拥有一个庞大的粉丝团,这是最重要的(将所有帖子放在一起)+1。 - mKorbel
如果有人在没有提供有价值的理由的情况下对某篇文章进行了负评,那么为什么要详细解释呢?只是他/她不同意而已,没有其他影响,那么为什么要问这个问题呢?如果他/她想要那样做,那么可能会写出原因 :-) - mKorbel
你一定是个非常热情的人,为什么会有火焰呢?别在意这些,你的地位并不是真实的。专业社区里有很多人都是为了乐趣而来的,就像我一样 :-) - mKorbel
2
@little:我既不是投票人也不是管理员;我在大约11小时前点了赞。看起来所有答案都被系统地下降,包括你的大约30个。您可以审计您的帐户以查看更多信息。如果自动作弊检测机制没有捕捉到它,则可以将其标记为管理员关注。我也受到了双重打击。 - trashgod

3

您可能正在绘制一些轻量级组件。这意味着它没有自己的坐标系,所以它使用最近的重量级父级的坐标系。

因此,您应该将要执行的变换与原始变换相结合(通过乘法)。

在完成绘制后,您(也许)应该恢复原始变换。


我不明白你在说什么轻量级和重量级组件混合的问题。你能解释一下吗? - mre
1
要绘制任何东西,必须有硬件组件。Swing 中的许多元素都是轻量级的。JFrame 是硬件组件,Panel 是轻量级的,并且居中,所以它被移动到侧面,这是通过仿射变换和剪切完成的。 - Alpedar

2
扩展@littel的答案,您可以在使用以下示例调整框架大小时将当前变换与标识进行比较。请注意,只有平移分量会变化:dx = 75.0MyCanvasLeft宽度之差的一半,而dy包括Left的垂直偏移和绿色边框的大小。
身份:仿射变换[[1.0,0.0,0.0],[0.0,1.0,0.0]] 身份:仿射变换[[1.0,0.0,0.0],[0.0,1.0,0.0]] 当前:仿射变换[[1.0,0.0,75.0],[0.0,1.0,201.0]] 当前:仿射变换[[1.0,0.0,75.0],[0.0,1.0,1.0]]

Demo image

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.geom.AffineTransform;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class MainClass {

    public static void main(String[] args) {
        JFrame jf = new JFrame("Demo");
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setLayout(new GridLayout(0, 1));
        jf.add(new MyCanvas());
        jf.add(new MyCanvas());
        jf.pack();
        jf.setLocationRelativeTo(null);
        jf.setVisible(true);
    }
}

class MyCanvas extends JPanel {

    MyCanvas() {
        setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
        setPreferredSize(new Dimension(600, 200));
        setBorder(BorderFactory.createLineBorder(Color.red));
        add(new Left(), BorderLayout.CENTER);
    }
}

class Left extends JPanel {

    Left() {
        setPreferredSize(new Dimension(450, 100));
        setBorder(BorderFactory.createLineBorder(Color.green));
        setBackground(Color.gray);
        System.out.println("Identity: " + new AffineTransform());
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        System.out.println("Current: " + g2.getTransform());
        g2.drawRect(getWidth() / 2 - 10, getHeight() / 2 - 10, 20, 20);
    }
}

-3

我知道你的问题出在哪里了,你在与父组件相同的图形上绘制。 "super.paintComponent(g);"

你应该尝试使用类似于 super.repaint(); 的方法。


3
paintComponent()方法内调用repaint()是不可取的。 - mre
@小兔寶寶,在給出-1之前,請提供有建設性的論據。你這樣做非常粗魯。 - Zemzela
1
简单 - 因为你最终会不断调用 paintComponent() 直到程序终止。以后请不要声称你“知道”问题所在,当你显然不知道时。 - mre
1
我做了,它有效。顺便问一下,你是在查看我所有的答案/问题并给它们投反对票吗? - mre
1
无限循环 - 话不多说 - BAR
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接