JComponent相对于JPanel的坐标系

时间:2017-02-16 06:42:21

标签: java swing jcomponent

paintComponent中的

println打印出497 971.在JPanel的视图中,根据该数字对,红线的左上角应该位于JPanel中间附近,但事实上它& #39;不是。enter image description here是否由坐标系转换引起?

提前致谢。

代码如下所示:

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();
  }
}

1 个答案:

答案 0 :(得分:3)

        g2d.drawLine(0, 0, 100, 50);
        g2d.setColor(Color.WHITE); // no good setting the color now!

应该是:

        g2d.setColor(Color.WHITE); // correct
        g2d.drawLine(0, 0, 100, 50);

其他提示:

  1. 添加所有组件后,最好到pack()帧。然后显示它们将是完全正确的大小。设置顶级容器应该是构造函数中的 last 事物(在绝大多数情况下)。

    setSize(1000, 1000);
    
  2. 组件的位置最好由布局管理器,填充和边框决定。

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

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

    特别注意:

                /* 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();
        }
    }
    

    编辑:包括分针和时针

      

    我发现如果我添加分针后的秒针,我的面板将是两倍宽 - 我认为这是因为图形不能叠加...... - 而我得到的是两个graphics2D分开远远离彼此并重新粉刷自己......有什么好主意可以解决这个问题?

    因为我很无聊,所以我更多地使用了代码。我发现角度没有了,所以放一个偏移来纠正它。然后我将分钟和时针添加到相同的自定义组件。我认为后者是您描述的问题的原因(如果没有,请显示您的最新代码 - 尽管可能是在一个新问题中)。

    试试这个版本(注意第二,分钟和时针是全部量化为各自的时间单位):

    enter image description here

    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();
        }
    }