0

I implement a clock where second hand and minute hand extends the same Component, JClockHand. I have the execution like this,enter image description here But it's not what I want. I am wondering if there are any possible ways to set the Graphics z index to overlap different graphics? thanks in advance.

sechand.png, https://app.box.com/s/pwwxxl9g0mparsg5fxghxwvtjjd58b25

minhand.png, https://app.box.com/s/mgwgx4odjexgt7qhyxr1tbcp68lkpy6x

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

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);
        setSize(1000, 1000);
        panel.setSize(getWidth(), getHeight());     
        panel.setLayout(new GridLayout());
        setVisible(true);
        setResizable(false);
        panel.setBackground(Color.BLACK);
        SecondHand sHand=new SecondHand("./res/icon/sechand.png");
        panel.add(sHand);
        MinuteHand mHand=new MinuteHand("./res/icon/minhand.png");
        panel.add(mHand);
        pack();
        setVisible(true);

    }
//start here
public class JClockHand extends JComponent{

    protected Dimension preferredSize=new Dimension(1000,1000);
    protected BufferedImage secImage;
    public void setIconPath(String iconPath){
        try {
            secImage = ImageIO.read(new File(iconPath));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
    public void rotate(Graphics2D g2d,BufferedImage img,double angleRad){
        double middle = preferredSize.getWidth() / 2d;

        g2d.translate(middle, middle); 
        AffineTransform at = AffineTransform.getTranslateInstance(middle, middle);
        at.rotate(angleRad);
        g2d.setTransform(at);        
        g2d.drawImage(img, 0, 0, this);         
    }    
    public Dimension getPreferredSize() {
        return preferredSize;
    }

}
class SecondHand extends JClockHand{

    private Timer timer;
    private Calendar currentTime;


    public SecondHand(String iconPath){
        currentTime = Calendar.getInstance();

        setIconPath(iconPath);
        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();
        double angle = (currentTime.get(Calendar.SECOND)*2*Math.PI)/60d;
        rotate(g2d,secImage,angle);  
        g2d.dispose();
    }

}

public class MinuteHand extends JClockHand{

    private Timer timer;
    private Calendar currentTime;

    public MinuteHand(String iconPath) {

        currentTime = Calendar.getInstance();

        setIconPath(iconPath);
        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();
        double angle = (currentTime.get(Calendar.MINUTE)*2*Math.PI)/60d;
        rotate(g2d,secImage,angle);  
        g2d.dispose();
    }


}
public static void main(String[] a) {
    ClockFrame c = new ClockFrame();
}   

}
Yu Fang
  • 520
  • 5
  • 17
  • Some approaches are cited [here](http://stackoverflow.com/a/14677267/230513). – trashgod Feb 17 '17 at 00:11
  • Unless this is intended for practicing (although I would *suspiciously* wonder: Practicing *what*?), you should paint the hands in **one** component. – Marco13 Feb 17 '17 at 00:23
  • Yes this is a practice. I was intending to separate rendering and left rendering done by basic components. I was planning to do that initially though. – Yu Fang Feb 17 '17 at 01:06

1 Answers1

1

Use JLayeredPane. Like this

public ClockFrame(){
    int frameWidth = 1000;
    int frameHeight = 1000;
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setPreferredSize(new Dimension(frameWidth, frameHeight));
    setLayout(new BorderLayout());

    JLayeredPane pane = new JLayeredPane();
    pane.setOpaque(true);
    pane.setBackground(Color.BLACK);
    add(pane);

    SecondHand sHand=new SecondHand("sechand.png");
    MinuteHand mHand=new MinuteHand("minhand.png");

    mHand.setBounds(0, 0, frameWidth, frameHeight);
    sHand.setBounds(0, 0, frameWidth, frameHeight);

    pane.add(mHand, 1);
    pane.add(sHand, 2);

    pack();
    setResizable(false);
    setVisible(true);
}

You have to set position and size of JLayeredPane components manually, because JLayeredPane as no LayoutManager

Here is the result of the modification

Flood2d
  • 1,338
  • 8
  • 9
  • I tried to use JLayeredPane to replace the original panel, but 2 JComponent still insist occupy 2 different dimension of their preferred size. I am thinkingthat the problems maybe lie in ClockHand original settings. – Yu Fang Feb 17 '17 at 02:12
  • related posts, http://stackoverflow.com/questions/19415170/what-is-setbounds-and-how-do-i-use-it – Yu Fang Feb 17 '17 at 02:54
  • http://stackoverflow.com/questions/1783793/java-difference-between-the-setpreferredsize-and-setsize-methods-in-compone – Yu Fang Feb 17 '17 at 02:55
  • Or a `GridBagLayout` :P – MadProgrammer Feb 17 '17 at 03:05
  • My advice, if you are trying to learn swing is to stop and learn Java FX instead. It's way more powerful – Flood2d Feb 17 '17 at 03:11