0

I intend to implement a clock with secondhand, but I cannot display second hand properly.

My code shows bellow, ClockFrame new a SecondHand and pass panel to SecondHand. SecondHand is expected to get seconds and update itself. I think g2.drawImage(bImage, 0, 0, null); show my bitmap, but not at all. I am really confused. Thanks in advance.

Clock.java

import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Clock {
  public static void main(String[] a) {
      ClockFrame c=new ClockFrame();
  }
}

SecondHand.java

import java.awt.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.util.Calendar;
import java.io.*;
import java.awt.image.*;

 public class SecondHand extends JComponent implements Runnable{

    private JPanel fpanel;
    private BufferedImage bImage;
    private Thread secThread;
    private Point center;
    double radPerSec = Math.PI/648000;
    public SecondHand(String path,Point p,Object o){
    try {
        bImage = ImageIO.read(new File(path));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    //setLocation((int)p.getX(),(int)p.getY());
    setLocation(0,0);
    center=p;
    ((JPanel)o).add(this);
    fpanel=(JPanel)o;

    secThread=new Thread(this);
    secThread.start();

}

public void run() {
   while(true) {           
          try{
                Thread.sleep(1000);
                Graphics2D g2 = (Graphics2D) getGraphics();
                g2.drawImage(bImage, 0, 0, null);
             //fpanel.repaint();

           } catch (InterruptedException e) {

             e.printStackTrace();
           }
    }

}


}

ClockFrame.java

import java.awt.*;
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(null);//!important
    setVisible(true);
    setResizable(false);
    panel.setBackground(Color.BLACK);
    SecondHand sHand=new SecondHand("./res/icon/sechand.png",new   Point(450,300),panel);


  }
}
Yu Fang
  • 520
  • 5
  • 17
  • You did not add sHand to ClockFrame, and instead of getGraphics override paintComponent in your thread. – Lemonov Feb 15 '17 at 12:21
  • But I add sHand to the panel on frame. So i think i dont have to add that again on frame? – Yu Fang Feb 15 '17 at 12:25
  • You need to add like this panel.add(sHand); and this.add(panel). If you just declare and initialize them you just create object of panel not asociated with visible frame. – Lemonov Feb 15 '17 at 12:29
  • I did. there is a ((JPanel)o).add(this); in SecHand constructor. – Yu Fang Feb 15 '17 at 12:30
  • Java is passing arguments by-value so I think that you are actually not adding the component to the right panel. – Lemonov Feb 15 '17 at 12:35
  • Take a look [here](https://docs.oracle.com/javase/tutorial/uiswing/painting/closer.html). This will help to understand, how to do a custom painting in Java. – Sergiy Medvynskyy Feb 15 '17 at 12:58

1 Answers1

2

The SecondHand component was not appearing for two reasons:

  1. It was not added to panel.
  2. panel has no layout, so it would have been shown at a size of 0 x 0.

As mentioned in comments, do nut use getGraphics(), but instead override the paintComponent(Graphics) method. To trigger that method, use a Swing based Timer to call repaint(). For better help sooner, post a Minimal, Complete, and Verifiable example like as seen below. One way to get image(s) for an example is to hot link to images seen in this Q&A. Below I just create a new buffered image.

Other problems I see in the source. Every JComponent is an ImageObserver so use it instead of null when drawing an image. Look at the other code comments carefully for other tips.

import java.awt.*;
import java.awt.image.BufferedImage;
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());
        // this is NOT the way to go
        //panel.setLayout(null);//!important
        panel.setLayout(new GridLayout());
        setResizable(false);
        panel.setBackground(Color.RED);
        SecondHand sHand = new SecondHand("./res/icon/sechand.png", new Point(450, 300), panel);
        panel.add(sHand); // THIS is impoertant
        // this should be done after all components are added!
        setVisible(true);
    }

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

class SecondHand extends JComponent implements Runnable {

    private JPanel fpanel;
    private BufferedImage bImage;
    private Thread secThread;
    private Point center;
    double radPerSec = Math.PI / 648000;

    public SecondHand(String path, Point p, Object o) {
        try {
            bImage
                    = new BufferedImage(900, 600, BufferedImage.TYPE_INT_RGB);
            //ImageIO.read(new File(path));
        } catch (Exception e) {
            e.printStackTrace();
        }
        //setLocation((int)p.getX(),(int)p.getY());
        setLocation(0, 0);
        center = p;
        ((JPanel) o).add(this);
        fpanel = (JPanel) o;

        secThread = new Thread(this);
        secThread.start();
    }

    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
                Graphics2D g2 = (Graphics2D) getGraphics();
                g2.drawImage(bImage, 0, 0, null);
                //fpanel.repaint();

            } catch (InterruptedException e) {

                e.printStackTrace();
            }
        }
    }
}
Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433