Am trying to modify a java code that implements Analog Clock using BufferedImage. I want the face of the clock to be changed dynamically when a user clicks on a button that scrolls through an array preloaded with the locations of images. So far my attempts have failed. I have two classes; The first Class creates and displays the Analog, and the second class attempts to change the face of the Analog clock using a mutator (setAnalogClockFace()) and an accessor (getAnalogClockFace()). The following is the code for the first Class as found on here, with minor modifications:
package panels;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.util.*;
public class Clock extends JPanel{
/**
*
*/
private static final long serialVersionUID = 1L;
private int hours = 0;
private int minutes = 0;
private int seconds = 0;
private int millis = 0;
private static final int spacing = 10;
private static final float threePi = (float)(3.0 * Math.PI);
private static final float radPerSecMin = (float)(Math.PI/30.0);
private int size; //height and width of clockface
private int centerX;//X coord of middle of clock
private int centerY;//Y coord of middle of clock
private BufferedImage clockImage;
private BufferedImage imageToUse;
private javax.swing.Timer t;
public Clock(){
this.setPreferredSize(new Dimension(203,203));
this.setBackground(getBackground());
this.setForeground(Color.darkGray);
t = new javax.swing.Timer(1000, new ActionListener(){
public void actionPerformed(ActionEvent ae){
update();
}
});
}
public void update(){
this.repaint();
}
public void start(){
t.start();
}
public void stop(){
t.stop();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
size = ((w < h) ? w : h) - 2 * spacing;
centerX = size/2 + spacing;
centerY = size/2 + spacing;
setClockFace(new AnalogClockTimer().getAnalogClockFace());
clockImage = getClockFace();
if (clockImage == null | clockImage.getWidth() != w | clockImage.getHeight() != h){
clockImage = (BufferedImage)(this.createImage(w,h));
Graphics2D gc = clockImage.createGraphics();
gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawClockFace(gc);
}
Calendar now = Calendar.getInstance();
hours = now.get(Calendar.HOUR);
minutes = now.get(Calendar.MINUTE);
seconds = now.get(Calendar.SECOND);
millis = now.get(Calendar.MILLISECOND);
g2d.drawImage(clockImage, null, 0, 0);
drawClockHands(g);
}
private void drawClockHands(Graphics g){
int secondRadius = size/2;
int minuteRadius = secondRadius * 3/4;
int hourRadius = secondRadius/2;
float fseconds = seconds + (float)millis/1000;
float secondAngle = threePi - (radPerSecMin * fseconds);
drawRadius(g, centerX, centerY, secondAngle, 0, secondRadius);
float fminutes = (float)(minutes + fseconds/60.0);
float minuteAngle = threePi - (radPerSecMin * fminutes);
drawRadius(g, centerX, centerY, minuteAngle, 0 , minuteRadius);
float fhours = (float)(hours + fminutes/60.0);
float hourAngle = threePi - (5 * radPerSecMin * fhours);
drawRadius(g, centerX, centerY, hourAngle, 0 ,hourRadius);
}
private void drawClockFace(Graphics g){
//g.setColor(Color.lightGray);
g.fillOval(spacing, spacing, size, size);
//g.setColor(new Color(168,168,168));
g.drawOval(spacing, spacing, size, size);
for(int sec = 0; sec < 60; sec++){
int tickStart;
if(sec%5 == 0){
tickStart = size/2-10;
}else{
tickStart = size/2-5;
}
drawRadius(g, centerX, centerY, radPerSecMin * sec, tickStart, size/2);
}
}
private void drawRadius(Graphics g, int x, int y, double angle,
int minRadius, int maxRadius){
float sine = (float)Math.sin(angle);
float cosine = (float)Math.cos(angle);
int dxmin = (int)(minRadius * sine);
int dymin = (int)(minRadius * cosine);
int dxmax = (int)(maxRadius * sine);
int dymax = (int)(maxRadius * cosine);
g.drawLine(x+dxmin, y+dymin, x+dxmax,y+dymax);
}
public void setClockFace(BufferedImage img){
if(img != null){
imageToUse = img;
}else{
try{
imageToUse =
ImageIO.read(getClass().getClassLoader().getResource("https://i.stack.imgur.com/6TEsB.jpg"));
}catch(IOException io){
io.printStackTrace();
}
}
}
public BufferedImage getClockFace(){
return imageToUse;
}
}
The second Class that attempts to set the Clock face is:
package panels;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import panels.Clock;
public class AnalogClockTimer extends javax.swing.JPanel implements ActionListener,
MouseListener {
private Clock clock;
/**
*
*/
private static final long serialVersionUID = 1L;
private JButton prevBtn;
private JTextField clockFaceCount;
private JButton nextBtn;
private JPanel buttonedPanel,leftPanel,rightPanel;
private BufferedImage image;
String[] clockFace;
int arrayPointer = 1;
/**
* Auto-generated main method to display this
* JPanel inside a new JFrame.
*/
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new AnalogClockTimer());
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public AnalogClockTimer() {
super();
initGUI();
}
private void initGUI() {
try {
BorderLayout thisLayout = new BorderLayout();
this.setLayout(thisLayout);
this.setPreferredSize(new java.awt.Dimension(283, 233));
this.setBackground(getBackground());
{
clock = new Clock();
add(clock,BorderLayout.CENTER);
clock.start();
clock.setSize(203, 203);
}
{
buttonedPanel = new JPanel();
FlowLayout buttonedPanelLayout = new FlowLayout();
buttonedPanel.setLayout(buttonedPanelLayout);
this.add(buttonedPanel, BorderLayout.SOUTH);
buttonedPanel.setPreferredSize(new java.awt.Dimension(283, 30));
{
prevBtn = new JButton(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_rest.png")));
prevBtn.setPreferredSize(new java.awt.Dimension(20, 19));
prevBtn.setBackground(getBackground());
prevBtn.setBorderPainted(false);
prevBtn.setEnabled(false);
prevBtn.addMouseListener(this);
prevBtn.addActionListener(this);
buttonedPanel.add(prevBtn);
}
{
nextBtn = new JButton(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_rest.png")));
nextBtn.setPreferredSize(new java.awt.Dimension(20, 19));
nextBtn.setBackground(getBackground());
nextBtn.setBorderPainted(false);
nextBtn.addMouseListener(this);
nextBtn.addActionListener(this);
}
{
clockFaceCount = new JTextField();
clockFaceCount.setPreferredSize(new java.awt.Dimension(50, 19));
clockFaceCount.setBackground(getBackground());
clockFaceCount.setBorder(null);
clockFaceCount.setHorizontalAlignment(SwingConstants.CENTER);
clockFaceCount.setEditable(false);
buttonedPanel.add(clockFaceCount);
buttonedPanel.add(nextBtn);
}
{
clockFace = new String[]{"https://i.stack.imgur.com/NprNw.jpg","https://i.stack.imgur.com/FuBgt.jpg",
"https://i.stack.imgur.com/6TEsB.jpg"};
for(int i = 1; i <= clockFace.length; i++){
if(i == 1){
nextBtn.setEnabled(true);
prevBtn.setEnabled(false);
}
clockFaceCount.setText(arrayPointer+" of "+clockFace.length);
}
}
{
leftPanel = new JPanel();
leftPanel.setPreferredSize(new Dimension(40, getHeight()));
add(leftPanel,BorderLayout.WEST);
}
{
rightPanel = new JPanel();
rightPanel.setPreferredSize(new Dimension(40,getHeight()));
add(rightPanel,BorderLayout.EAST);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void mouseClicked(MouseEvent me) {
if(me.getSource() == prevBtn)
prevBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_pressed.png")));
else
nextBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_pressed.png")));
}
@Override
public void mouseEntered(MouseEvent me) {
if(me.getSource()==prevBtn)
prevBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_hover.png")));
else
nextBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_hover.png")));
}
@Override
public void mouseExited(MouseEvent me) {
if(me.getSource() == prevBtn)
prevBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_rest.png")));
else
nextBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_rest.png")));
}
@Override
public void mousePressed(MouseEvent me) {
if(me.getSource() == prevBtn){
prevBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_pressed.png")));
}else{
nextBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_pressed.png")));
}
}
@Override
public void mouseReleased(MouseEvent me) {
if(me.getSource() == prevBtn)
prevBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_left_hover.png")));
else
nextBtn.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/settings_right_hover.png")));
}
@Override
public void actionPerformed(ActionEvent ae) {
if(ae.getSource() == nextBtn){
{
if(arrayPointer < clockFace.length){
++arrayPointer;
prevBtn.setEnabled(true);
if(arrayPointer == clockFace.length)
nextBtn.setEnabled(false);
}
clockFaceCount.setText(arrayPointer + " of " + clockFace.length);
setAnalogClockFace(arrayPointer);
}
}else if(ae.getSource() == prevBtn){
{
if(arrayPointer > 1){
--arrayPointer;
nextBtn.setEnabled(true);
if(arrayPointer == 1){
clockFaceCount.setText(arrayPointer+" of "+clockFace.length);
prevBtn.setEnabled(false);
}
}
clockFaceCount.setText(arrayPointer + " of "+clockFace.length);
setAnalogClockFace(arrayPointer);
}
}
}
private void setAnalogClockFace(int pointerPosition) {
try{
image = ImageIO.read(getClass().getClassLoader().getResource(clockFace[pointerPosition]));
}catch(IOException io){
io.printStackTrace();
}
}
public BufferedImage getAnalogClockFace(){
return image;
}
}
I've been working on this for days, can someone please help me understand what am not doing right? Any help would be greatly appreciated.
Here is an MCVE using a JLabel to achieve the same result:
package panels;
import java.awt.Dimension;
import javax.swing.ImageIcon;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JTextField;
import java.awt.event.*;
import java.awt.BorderLayout;
@SuppressWarnings({"serial"})
public class ClockPanel extends javax.swing.JPanel implements ActionListener {
private JLabel clockImageLabel;
private JPanel buttonsPanel;
private JButton next,prev;
private JTextField displayCount;
String[] imageFaces;
int pointer = 1;
/**
* Auto-generated main method to display this
* JPanel inside a new JFrame.
*/
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new ClockPanel());
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public ClockPanel() {
super();
initGUI();
}
private void initGUI() {
try {
setPreferredSize(new Dimension(203, 237));
BorderLayout panelLayout = new BorderLayout();
setLayout(panelLayout);
{
clockImageLabel = new JLabel();
clockImageLabel.setPreferredSize(new Dimension(203,203));
clockImageLabel.setHorizontalAlignment(SwingConstants.CENTER);
clockImageLabel.setVerticalAlignment(SwingConstants.CENTER);
add(clockImageLabel,BorderLayout.NORTH);
}
{
buttonsPanel = new JPanel();
{
next = new JButton(">");
next.addActionListener(this);
}
{
prev = new JButton("<");
prev.addActionListener(this);
displayCount = new JTextField();
displayCount.setBorder(null);
displayCount.setEditable(false);
displayCount.setBackground(getBackground());
displayCount.setHorizontalAlignment(SwingConstants.CENTER);
buttonsPanel.add(prev);
buttonsPanel.add(displayCount);
displayCount.setPreferredSize(new java.awt.Dimension(45, 23));
buttonsPanel.add(next);
add(buttonsPanel,BorderLayout.SOUTH);
}
{
imageFaces = new String[]{"https://i.stack.imgur.com/6TEsB.jpg",
"https://i.stack.imgur.com/NprNw.jpg","https://i.stack.imgur.com/FuBgt.jpg"
};
for(int i = 1; i < imageFaces.length; i++){
if(i == 1){
next.setEnabled(true);
prev.setEnabled(false);
}
displayCount.setText(pointer+" of "+imageFaces.length);
setLabelImage(pointer);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void setLabelImage(int pointerPosition){
clockImageLabel.setIcon(new ImageIcon(getClass().getClassLoader().getResource(imageFaces[pointerPosition])));
this.repaint();
}
@Override
public void actionPerformed(ActionEvent ae) {
if(ae.getSource() == next){
if(pointer < imageFaces.length){
++pointer;
prev.setEnabled(true);
if(pointer == imageFaces.length)next.setEnabled(false);
displayCount.setText(pointer+" of "+imageFaces.length);
setLabelImage(pointer);
}
}else if(ae.getSource() == prev){
if(pointer > 1){
--pointer;
next.setEnabled(true);
if(pointer == 1)prev.setEnabled(false);
displayCount.setText(pointer+" of "+imageFaces.length);
setLabelImage(pointer);
}
}
}
}
Here are 1/2 Images for the code: HandlessAnalogClock 1 HandlessAnalogClock 2 HandlessAnalogClock 3