Java JComponent相对于JPanel的坐标系

Java JComponent相对于JPanel的坐标系,java,swing,jcomponent,Java,Swing,Jcomponent,paintComponent中的println打印出497971。在杰帕内尔看来,根据这对数字,红线的左上点应该在杰帕内尔的中间附近,但事实上不是。它是由坐标系转换引起的吗 提前谢谢 代码如下: import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; im

paintComponent中的println打印出497971。在杰帕内尔看来,根据这对数字,红线的左上点应该在杰帕内尔的中间附近,但事实上不是。它是由坐标系转换引起的吗

提前谢谢

代码如下:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;

import javax.imageio.ImageIO;
import javax.swing.*;

public class ClockFrame extends JFrame {
JPanel panel;
public ClockFrame(){
    panel = new JPanel();
   setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   add(panel);
    setSize(1000, 1000);
    panel.setSize(getWidth(), getHeight());
    //panel.setLayout(null);//!important
    panel.setLayout(new GridLayout());
    setVisible(true);
    setResizable(false);
    panel.setBackground(Color.BLACK);
    Hand sHand=new Hand(panel);
    panel.add(sHand);

}
class Hand extends JComponent{
private Timer timer;
public Hand(Object o){
    setLocation(500,500);
    ((JPanel)o).add(this);

    timer = new Timer(800, new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            repaint();
        }
    });
    timer.start();

}
protected void paintComponent(Graphics g) {
    super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(Color.RED);System.out.println(panel.getWidth()/2 +"    "+panel.getHeight());
        g2d.drawLine(panel.getWidth()/2, panel.getHeight()/2, 30, 30);
        g2d.dispose();
}
public Dimension getPreferredSize() {
    return new Dimension(600, 600);
}
}   
public static void main(String[] a) {
  ClockFrame c=new ClockFrame();
  }
}
应该是:

        g2d.setColor(Color.WHITE); // correct
        g2d.drawLine(0, 0, 100, 50);
其他提示:
  • 最好在添加所有组件后对框架进行
    pack()
    。然后它将是显示它们的精确正确大小。设置顶级容器可见应该是构造函数中的最后一件事(在绝大多数情况下)

  • 组件的位置最好由布局管理器、填充和边框确定

    public Hand(Object o){
        setLocation(500,500);
    
  • 如果组件需要添加到容器中,最好将其作为容器传递。话虽如此,最好不要在构造函数中传递容器,而是在实例化后立即在代码中添加(…)它

    public Hand(Object o){
        // ..
        ((JPanel)o).add(this);
    
  • 其中一些概念在下面的代码中实现。一定要运行它以查看效果

    特别注意:

                /* Note that this is translating further drawing operations
                to the middle of the Hand container based on its preferred size,
                which is (layout manager not withstanding) also its actual size. 
                All co-ordinates in custom painting are relative to the component 
                being painted. */
                g2d.translate(middle, middle); 
    
    代码 编辑:包括分针和时针
    我发现在秒针之后,如果我加上分针,我的面板将是原来的两倍宽-我想这是因为图形不能叠加…-我得到的结果是,两个图形彼此分离得很远,然后重新喷漆..有什么好办法解决这个问题吗

    因为我很无聊,我又多玩了一会儿代码。我发现角度是错的,所以放一个偏移量来修正它。然后,我将分针和时针添加到该相同的自定义组件中。我认为后者是您描述的问题的原因(如果不是,则显示您的最新代码-尽管可能是在一个新问题中)

    尝试此版本(请注意,秒、分针和时针都被量化为各自的时间单位):


    我已经在下面指出了一些问题,但我只想指出这个问题/代码在很多方面都是正确的。1) 我们可以使用可编译/可运行的代码。使问题调查变得轻而易举。2) 自定义组件设置背景颜色,并在重写方法中调用
    super.paintComponent(..)
    ,以绘制该颜色并删除以前的图形。3) 重写
    getPreferredSize()
    方法作为对布局管理器的提示。4) 使用基于Swing的
    计时器
    进行GUI动画。-总而言之,这是一个很好的问题和代码。:)安德鲁,非常感谢!但这并不是我想问的。我对问题稍加修改;你能再看一遍吗?嗯,坐标系从自定义组件左上角的0,0开始。X向右增加,Y向下增加。我们可以将组件的首选大小的一半添加到
    二手
    行中的所有参数中,以将它们移到中间,或者更简单地说,只需翻译
    Graphics2D
    实例并将偏移量(用于中间)添加到其中。在调用
    translate(…)
    后,尝试在0,0处绘制一个字符串,看看它从哪里开始。看起来java只维护一个全局坐标系,所以java中没有像Qt的mapToGlobal这样的东西存在?我不知道Qt,但有一些方法可以将坐标从组件转换到屏幕,反之亦然。我真的看不出将合作词从组件转换到顶级容器(例如
    JFrame
    )有什么意义,尽管有很多方法可以做到。谢谢,我明白了这一点。在相关的帖子中,我发现如果我加上分针,我的面板会有两倍宽-我想这是因为图形不能叠加…-我得到的是,两个图形彼此分开很远,然后重新喷漆..有什么好办法解决这个问题吗?:'(
    public Hand(Object o){
        // ..
        ((JPanel)o).add(this);
    
                /* Note that this is translating further drawing operations
                to the middle of the Hand container based on its preferred size,
                which is (layout manager not withstanding) also its actual size. 
                All co-ordinates in custom painting are relative to the component 
                being painted. */
                g2d.translate(middle, middle); 
    
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.geom.Line2D;
    import java.util.Calendar;
    import java.util.Date;
    import javax.swing.*;
    
    public class ClockFrame extends JFrame {
    
        public ClockFrame() {
            JPanel panel = new JPanel();
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            add(panel);
            panel.setSize(getWidth(), getHeight());
            //panel.setLayout(null);//!important
            panel.setLayout(new GridLayout());
            setResizable(false);
            panel.setBackground(Color.BLACK);
            Hand sHand = new Hand(panel);
            panel.add(sHand);
    
            pack();
            setVisible(true);
        }
    
        class Hand extends JComponent {
    
            private Timer timer;
            private Dimension preferredSize = new Dimension(600, 600);
            private Calendar currentTime;
    
            public Hand(Object o) {
                setLocation(500, 500);
                ((JPanel) o).add(this);
                currentTime = Calendar.getInstance();
    
                timer = new Timer(50, new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        currentTime.setTime(new Date(System.currentTimeMillis()));
                        repaint();
                    }
                });
                timer.start();
            }
    
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                System.out.println("x: " + this.getX() + " y: " + this.getY() + " w: " + this.getWidth() + " h: " + this.getHeight());
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setColor(Color.WHITE);
                double angle = (currentTime.get(Calendar.SECOND)*2*Math.PI)/60d;
                double middle = preferredSize.getWidth() / 2d;
                /* Note that this is translating further drawing operations
                to the middle of the Hand container based on its preferred size,
                which is (layout manager not withstanding) also its actual size. 
                All co-ordinates in custom painting are relative to the component 
                being painted. */
                g2d.translate(middle, middle); 
                Line2D.Double secondHand = new Line2D.Double(0, 0, 
                        middle*.9*Math.cos(angle), 
                        middle*.9*Math.sin(angle));
                g2d.draw(secondHand);
                g2d.dispose();
            }
    
            public Dimension getPreferredSize() {
                return preferredSize;
            }
        }
    
        public static void main(String[] a) {
            ClockFrame c = new ClockFrame();
        }
    }
    
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.geom.Line2D;
    import java.io.IOException;
    import java.net.URL;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.imageio.ImageIO;
    import javax.swing.*;
    
    public class ClockFrame extends JFrame {
    
        public ClockFrame() {
            JPanel panel = new JPanel();
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            add(panel);
            panel.setSize(getWidth(), getHeight());
            panel.setLayout(new GridLayout());
            setResizable(false);
            panel.setBackground(Color.MAGENTA.darker().darker());
            Hand sHand = new Hand(panel);
            panel.add(sHand);
    
            pack();
            setVisible(true);
        }
    
        class Hand extends JComponent {
    
            private Timer timer;
            private Dimension preferredSize = new Dimension(600, 600);
            private Calendar currentTime;
            private Image clockFace;
    
            public Hand(Object o) {
                setLocation(500, 500);
                ((JPanel) o).add(this);
                currentTime = Calendar.getInstance();
                try {
                    clockFace = ImageIO.read(new URL(
                            "http://www.clipartbest.com/cliparts/LTK/kBp/LTKkBpRGc.png"));
                } catch (IOException ex) {
                    Logger.getLogger(ClockFrame.class.getName()).log(Level.SEVERE, null, ex);
                }
    
                timer = new Timer(50, new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        currentTime.setTime(new Date(System.currentTimeMillis()));
                        repaint();
                    }
                });
                timer.start();
            }
    
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(
                        RenderingHints.KEY_ANTIALIASING, 
                        RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setRenderingHint(
                        RenderingHints.KEY_DITHERING, 
                        RenderingHints.VALUE_DITHER_ENABLE);
                g2d.setColor(Color.LIGHT_GRAY);
                int size = preferredSize.width;
                g2d.fillOval((int)(size*.01), (int)(size*.01), (int)(size*.98), (int)(size*.98));
                if (clockFace!=null) {
                    g2d.drawImage(clockFace, 0, 0, this);
                }
                double middle = size / 2d;
                /* Note that this is translating further drawing operations
                to the middle of the Hand container based on its preferred size,
                which is (layout manager not withstanding) also its actual size. 
                All co-ordinates in custom painting are relative to the component 
                being painted. */
                g2d.translate(middle, middle); 
    
                g2d.setColor(Color.CYAN.darker().darker());
                double angleHour = ((currentTime.get(Calendar.HOUR)*2*Math.PI)/12d)-(Math.PI/2);
                g2d.setStroke(new BasicStroke(6.5f));
                Line2D.Double hourHand = new Line2D.Double(0, 0, 
                        middle*.83*Math.cos(angleHour), 
                        middle*.83*Math.sin(angleHour));
                g2d.draw(hourHand);
    
                g2d.setColor(Color.CYAN.darker());
                double angleMin = ((currentTime.get(Calendar.MINUTE)*2*Math.PI)/60d)-(Math.PI/2);
                g2d.setStroke(new BasicStroke(4.5f));
                Line2D.Double minuteHand = new Line2D.Double(0, 0, 
                        middle*.85*Math.cos(angleMin), 
                        middle*.85*Math.sin(angleMin));
                g2d.draw(minuteHand);
    
                g2d.setColor(Color.CYAN);
                double angleSec = ((currentTime.get(Calendar.SECOND)*2*Math.PI)/60d)-(Math.PI/2);
                g2d.setStroke(new BasicStroke(2.5f));
                Line2D.Double secondHand = new Line2D.Double(0, 0, 
                        middle*.87*Math.cos(angleSec), 
                        middle*.87*Math.sin(angleSec));
                g2d.draw(secondHand);
    
                g2d.dispose();
            }
    
            public Dimension getPreferredSize() {
                return preferredSize;
            }
        }
    
        public static void main(String[] a) {
            ClockFrame c = new ClockFrame();
        }
    }