For my programming class I'm working on a clock. The clock has to be set at an initial time, which I cannot figure out how to do. The clock I'm currently working with just uses the system time. I've tried setting a time using cal.set but then it just freezes on what I want to be the initial time and time doesn't progress. How can I edit this to allow me to have a set initial time, but have the clock still work?
package Clock;
package Clock;
import java.applet.Applet;
import java.awt.Color;
import java.lang.Object;
import javax.swing.JPanel;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JFrame;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class Component extends Applet implements Runnable {
private static final long serialVersionUID = 1L;
public static String name = "My Clock";
public static int size = 600;
public static boolean isRunning = false;
public static Graphics g;
public static Image screen;
public Numbers number;
public static JFrame frame;
public static void main(String [] args) {
Component component = new Component();
frame = new JFrame();
frame.add(component);
frame.setSize(size+6, size + 28);
frame.setTitle(name);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
component.start();
}
public void start() {
requestFocus();
number = new Numbers();
isRunning = true;
Thread th = new Thread(this);
th.start();
}
public void run() {
screen = createVolatileImage(size, size);
while (isRunning) {
tick();
render(g);
try {
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void tick() {
}
public double time;
public int anim;
public int anim2;
public int anim3;
public int anim4;
public int center = size/2;
public int radius = (size-40)/2;
public void render(Graphics g) {
// Drawing to image
screen = createImage(size, size);
g = screen.getGraphics();
//Drawing the background
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, size, size);
// Drawing the frame(outside circle)
g.setColor(Color.black);
g.fillOval(5, 5, size - 10, size - 10);
g.setColor(Color.white);
//g.setColor(new Color(new Random().nextInt(255). new Random().nextInt(255), new Random().nextInt(255)));
//g.drawOval(10, 10, size - 20, size - 20);
g.fillOval(20, 20, size - 40, size - 40);
number.render(g);
// Math and Drawing for Lines
for (int i = 0; i < 60; i++) {
radius = size - 40;
anim = center + (int) ((Math.sin(i % 60.0 / 60 * Math.PI * 2) * (radius / 2)));
anim2 = center - (int) ((Math.cos(i % 60.0 / 60 * Math.PI * 2) * (radius / 2)));
radius = size - 60;
anim3 = center + (int) ((Math.sin(i % 60.0 / 60 * Math.PI * 2) * (radius / 2)));
anim4 = center - (int) ((Math.cos(i % 60.0 / 60 * Math.PI * 2) * (radius / 2)));
g.drawLine(anim, anim2, anim3, anim4);
}
// Math for hour hand
radius = size - 140;
// time = System.currentTimeMillis() % 3600000 / 3600000 * Math.PI;
int t = (int) (System.currentTimeMillis() + 17300000) + 3600000+ 3600000 + 3600000 + 3600000 + 3600000 + 3600000 + 3600000 + 3600000;
anim = center
+ (int) ((Math.sin(t % 43200000.0
/ 43200000 * Math.PI * 2) * (radius / 2))) + 7;
anim2 = center
- (int) ((Math.cos(t % 43200000.0
/ 43200000 * Math.PI * 2) * (radius / 2))) + 7;
// Drawing the hour hand
g.setColor(Color.black);
g.fillOval(center - 8, center - 8, 16, 16);
g.drawLine(center, center, anim, anim2);
g.drawLine(center + 1, center, anim + 1, anim2);
g.drawLine(center, center + 1, anim, anim2 + 1);
g.drawLine(center - 1, center, anim - 1, anim2);
g.drawLine(center, center - 1, anim, anim2 - 1);
g.drawLine(center + 1, center + 1, anim, anim2);
g.drawLine(center + 1, center - 1, anim, anim2);
g.drawLine(center - 1, center + 1, anim, anim2);
g.drawLine(center - 1, center - 1, anim, anim2);
// Math for minute hand
radius = size - 90;
// time = System.currentTimeMillis() % 3600000 / 3600000 * Math.PI;
anim = center
+ (int) ((Math.sin(System.currentTimeMillis() % 3600000.0
/ 3600000 * Math.PI * 2) * radius / 2));
anim2 = center
- (int) ((Math.cos(System.currentTimeMillis() % 3600000.0
/ 3600000 * Math.PI * 2) * radius / 2));
// Drawing the minute hand
g.setColor(Color.black);
g.drawLine(center, center, anim, anim2);
g.drawLine(center + 1, center, anim + 1, anim2);
g.drawLine(center, center + 1, anim, anim2 + 1);
g.drawLine(center - 1, center, anim - 1, anim2);
g.drawLine(center, center - 1, anim, anim2 - 1);
//Math for second hand
DateFormat dateFormat = new SimpleDateFormat("ss");
Calendar cal = Calendar.getInstance();
String s = dateFormat.format(cal.getTime());
radius = size - 70;
// time = System.currentTimeMillis() % 60000 / 60000 * Math.PI;
anim = center
+ (int) ((Math.sin(Integer.parseInt(s) % 60.0 / 60 * Math.PI
* 2) * (radius / 2)));
anim2 = center
- (int) ((Math.cos(Integer.parseInt(s) % 60.0 / 60 * Math.PI
* 2) * (radius / 2)));
// Drawing the second hand
g.setColor(Color.red);
g.drawLine(center, center, anim, anim2);
g.drawLine(center + 1, center, anim + 1, anim2);
g.drawLine(center, center + 1, anim, anim2 + 1);
g.drawLine(center - 1, center, anim - 1, anim2);
g.drawLine(center, center - 1, anim, anim2 - 1);
// Center circle
g.fillOval(center - 5, center - 5, 10, 10);
g.setColor(Color.black);
g.fillOval(center - 2, center - 2, 4, 4);
// g.setColor(new Color(new Random().nextInt(255), new Random().nextInt(255), new Random().nextInt(255)));
// g.fillRect(0, 0, getWidth(), getHeight());
// Drawing to screen
g = getGraphics();
g.drawImage(screen, 0, 0, size, size, this);
g.dispose();
}
}
and
package Clock;
import java.applet.Applet;
import java.awt.Color;
import java.lang.Object;
import javax.swing.JPanel;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JFrame;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class Numbers extends JPanel {
private static final long serialVersionUID=1L;
public int size = Component.size;
public int center = size/2;
public void setFont(Font font) {
super.setFont(font);
repaint();
}
public String getDay() {
DateFormat dateFormat=new SimpleDateFormat("dd");
Calendar cal = Calendar.getInstance();
String s = dateFormat.format(cal.getTime());
int day = Integer.parseInt(s);
String d = day + "";
// sets ordinal indicator
switch(day) {
case 1:
case 21:
case 31:
d += "st";
break;
case 2:
case 22:
d += "nd";
break;
case 3:
case 23:
d += "rd";
break;
default:
d += "th";
}
return d;
}
public String getHour() {
DateFormat dateFormat = new SimpleDateFormat("HH");
Calendar cal = Calendar.getInstance();
String s = dateFormat.format(cal.getTime());
int hour = Integer.parseInt(s) -1;
String n = hour + "";
if(hour < 10) {
n=hour+"";
}
return n;
}
public String getMonth() {
DateFormat dateFormat = new SimpleDateFormat("MM");
Calendar cal = Calendar.getInstance();
String s = dateFormat.format(cal.getTime());
int month = Integer.parseInt(s);
// sets month name to number
String m = "";
switch (month)
{
case 1:
m= "January";
break;
case 2:
m= "February";
break;
case 3:
m= "March";
break;
case 4:
m= "April";
break;
case 5:
m= "May";
break;
case 6:
m= "June";
break;
case 7:
m= "July";
break;
case 8:
m= "August";
break;
case 9:
m= "September";
break;
case 10:
m= "October";
break;
case 11:
m= "November";
break;
case 12:
m= "December";
}
return m;
}
public void render(Graphics g) {
g.setColor(Color.black);
DateFormat dateFormat = new SimpleDateFormat(":mm:ss");
Calendar cal = Calendar.getInstance();
String s = dateFormat.format(cal.getTime());
int n = center - ((s.length() *13)/2);
//265
g.setFont(new Font("Arial", 1, 20));
s = (Integer.parseInt(getHour(), 10) % 12 + 1) + "" + dateFormat.format(cal.getTime());
n = center - (s.length() * 10 / 2);
g.setColor(Color.DARK_GRAY);
g.fillRoundRect(250, 348, 100, 30, 6, 6);
g.setColor(Color.LIGHT_GRAY);
g.fillRoundRect(252, 350, 96, 26, 6, 6);
g.setColor(Color.BLACK);
g.drawString("TIME", 275, 345);
g.drawString("DATE", 275, 225);
g.drawString("AM", 255, 150);
g.drawString("PM", 315, 150);
g.drawString(s, n, 370);
int p = Integer.parseInt(getHour(), 10);
if(p < 11 || p == 24) {
g.fillOval(265, 160, 10, 10);
g.drawOval(325, 160, 10, 10);
} else {
g.drawOval(265, 160, 10, 10);
g.fillOval(325, 160, 10, 10);
}
dateFormat = new SimpleDateFormat("yyyy");
cal = Calendar.getInstance();
s = getMonth() + " " + getDay() + ", " + dateFormat.format(cal.getTime());
n = center - (int) ((s.length() * 10.25) / 2);
g.setColor(Color.DARK_GRAY);
g.fillRoundRect(200, 228, 200, 30, 6, 6);
g.setColor(Color.LIGHT_GRAY);
g.fillRoundRect(202, 230, 196, 26, 6, 6);
g.setColor(Color.BLACK);
g.drawString(s, n, 250);
s = Component.name;
n=center - (int)((s.length()*10)/2);
g.drawString(s, n , 450);
g.setFont(new Font("Arial", 1, 30));
int radius = size - 100;
for(int i = 0; i < 12; i++) {
double anim = (int) ((Math.sin((i+1) % 12.0 / 12 * Math.PI * 2) * (radius / 2)));
double anim2 = (int) ((Math.cos((i+1) % 12.0 / 12 * Math.PI * 2) * (radius / 2)));
if(i >= 9){
anim -= 10;
}
g.drawString((i+1) + "", center + (int) anim - 6, center - (int) anim2 + 12);
}
}
}
Lot's of issues -- where to even begin?
You've named a class Component, a name that will easily cause conflicts with a key Java core GUI class, java.awt.Component. Rename it to something else.
This same class extends Applet but is not being used as an Applet. Rather it is being used as a component to be added to a JFrame -- this makes no sense, trying to add one top-level window into another, and would require some justification as to why you're doing it in such a strange fasion. Why not extend JPanel or JComponent something else that makes more sense?
You're using a Graphics field and drawing to it, something that risks NullPointerException. Instead Google and read the Swing drawing tutorials and follow their lead -- draw passively within the paintComponent method of a JPanel. There are other important details to understand which the tutorials will show and tell you.
You're drawing with a Graphics object obtained by calling getGraphics() on a component, something that will lead to unstable drawings and possible NullPointerExceptions. Again read the tutorials on how to do this correctly.
You're making Swing calls in a background thread, something that can lead to intermittent difficult to debug threading errors. Use a Swing Timer to make things easier on yourself. Google the tutorial for the gory details.
You appear to be creating a JPanel, Numbers, but aren't adding it to the GUI (that I can tell), but rather are trying to render it in a strange way -- why, I have no idea. Don't do this. Again do graphics as per the Swing drawing tutorials. Here's the links:
Lesson: Performing Custom Painting: introductory tutorial to Swing graphics
Painting in AWT and Swing: advanced tutorial on Swing graphics
..... more
Related
How do I change the background color of this scene? what am I missing? I tried the following:
This command actually resolves / has no error BUT it doesn't change the color.
scene.setFill(Color.GRAY);
This command also resolves / has no error but it also doesn't change the color.
Scene scene = new Scene(pane, 250, 250, Color.GRAY);
Thank you for your response.
CODE: ===================================================
...
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import java.util.Calendar;
import java.util.GregorianCalendar;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;
public class DisplayResizableClock extends Application {
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create a clock and a label
ClockPane2 clock = new ClockPane2();
//clock.setF;
String timeString = clock.getHour() + ":" + clock.getMinute()
+ ":" + clock.getSecond();
Label lblCurrentTime = new Label(timeString);
// Place clock and label in border pane
BorderPane pane = new BorderPane();
pane.setCenter(clock);
pane.setBottom(lblCurrentTime);
BorderPane.setAlignment(lblCurrentTime, Pos.TOP_CENTER);
// Create a scene and place the pane in the stage
Scene scene = new Scene(pane, 250, 250);
scene.setFill(Color.GRAY);
primaryStage.setTitle("Display Resizable Clock"); // Set the stage title===========
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
pane.widthProperty().addListener(ov ->
clock.setWidth(pane.getWidth())
);
pane.heightProperty().addListener(ov ->
clock.setHeight(pane.getHeight())
);
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
//=====================
class ClockPane2 extends Pane {
private int hour;
private int minute;
private int second;
/** Construct a default clock with the current time*/
public ClockPane2() {
setCurrentTime();
}
/** Construct a clock with specified hour, minute, and second */
public ClockPane2(int hour, int minute, int second) {
this.hour = hour;
this.minute = minute;
this.second = second;
}
/** Return hour */
public int getHour() {
return hour;
}
/** Set a new hour */
public void setHour(int hour) {
this.hour = hour;
paintClock();
}
/** Return minute */
public int getMinute() {
return minute;
}
/** Set a new minute */
public void setMinute(int minute) {
this.minute = minute;
paintClock();
}
/** Return second */
public int getSecond() {
return second;
}
/** Set a new second */
public void setSecond(int second) {
this.second = second;
paintClock();
}
/* Set the current time for the clock */
public void setCurrentTime() {
// Construct a calendar for the current date and time
Calendar calendar = new GregorianCalendar();
// Set current hour, minute and second
this.hour = calendar.get(Calendar.HOUR_OF_DAY);
this.minute = calendar.get(Calendar.MINUTE);
this.second = calendar.get(Calendar.SECOND);
paintClock(); // Repaint the clock
}
/** Paint the clock */
private void paintClock() {
// Initialize clock parameters
double clockRadius =
Math.min(getWidth(), getHeight()) * 0.8 * 0.5;
double centerX = getWidth() / 2;
double centerY = getHeight() / 2;
// Draw circle
Circle circle = new Circle(centerX, centerY, clockRadius);
circle.setFill(Color.YELLOW); //=====changed color==============
circle.setStroke(Color.BLACK);
Text t1 = new Text(centerX - 5, centerY - clockRadius + 12, "12");
Text t2 = new Text(centerX - clockRadius + 3, centerY + 5, "9");
Text t3 = new Text(centerX + clockRadius - 10, centerY + 3, "3");
Text t4 = new Text(centerX - 3, centerY + clockRadius - 3, "6");
// Draw second hand
double sLength = clockRadius * 0.8;
double secondX = centerX + sLength *
Math.sin(second * (2 * Math.PI / 60));
double secondY = centerY - sLength *
Math.cos(second * (2 * Math.PI / 60));
Line sLine = new Line(centerX, centerY, secondX, secondY);
sLine.setStroke(Color.RED);
// Draw minute hand
double mLength = clockRadius * 0.65;
double xMinute = centerX + mLength *
Math.sin(minute * (2 * Math.PI / 60));
double minuteY = centerY - mLength *
Math.cos(minute * (2 * Math.PI / 60));
Line mLine = new Line(centerX, centerY, xMinute, minuteY);
mLine.setStroke(Color.BROWN); //changed color to brown======================
// Draw hour hand
double hLength = clockRadius * 0.5;
double hourX = centerX + hLength *
Math.sin((hour % 12 + minute / 60.0) * (2 * Math.PI / 12));
double hourY = centerY - hLength *
Math.cos((hour % 12 + minute / 60.0) * (2 * Math.PI / 12));
Line hLine = new Line(centerX, centerY, hourX, hourY);
hLine.setStroke(Color.GREEN);
getChildren().clear(); // Clear the pane
getChildren().addAll(circle, t1, t2, t3, t4, sLine, mLine, hLine);
Group ticks = new Group();//create tick hands============================
Group numbers = new Group(); //create numbers==========================
// creating the big ticks (12)===============================
for (int i = 0; i < 12; i++) {
/*creating a line with a width of 10 and placing at 'clockRadius'
distance away from center*/
Line tick = new Line(0, clockRadius, 0, clockRadius - 10);
tick.setTranslateX(centerX);
tick.setTranslateY(centerY);
//applying proper rotation to rotate the tick
tick.getTransforms().add(new Rotate(i * (360 / 12)));
//adding to ticks group
ticks.getChildren().add(tick);
}
// creating the small ticks=========================================
for (int i = 0; i < 60; i++) {
//lines will have a width of 5
Line tick = new Line(0, clockRadius, 0, clockRadius - 5);
tick.setTranslateX(centerX);
tick.setTranslateY(centerY);
tick.getTransforms().add(new Rotate(i * (360 / 60)));
ticks.getChildren().add(tick);
}
// creating the numbers==================================================
int num = 12; // starting with 12
for (int i = 0; i < 12; i++) {
//finding proper position x and y by applying the equation
double x = centerX + (clockRadius - 20) * Math.sin((i % 12) * (2 * Math.PI / 12));
double y = centerY - (clockRadius - 20) * Math.cos((i % 12) * (2 * Math.PI / 12));
//defining a text with hour label, (x-5 and y+5 are used to align text
//in proper position, considering font height & width)
Text t = new Text(x - 5, y + 5, "" + num);
numbers.getChildren().add(t);
num++;
if (num > 12) {
num = 1;
}
}
// adding ticks and numbers======================
getChildren().add(ticks);
getChildren().add(numbers);
}
#Override
public void setWidth(double width) {
super.setWidth(width);
paintClock();
}
#Override
public void setHeight(double height) {
super.setHeight(height);
paintClock();
}
}
...
I have looked all over the internet to figure out what the issue was as well. But, I managed to find a way to change the scene.
Instead of using the setfill() method for the scene, use the node's setStyle() method (in this case BorderPane).
For example, if you use something like:
pane.setStyle("-fx-background-color: grey;");
It should set the color of the pane, which is inside the scene, to grey. The best part is that the command can be placed before or after setting the scene to work.
Here is an image of one of my scenes after using the command to get a black background as an example:
So i'm trying to make a health + shield bar in my game. If you have ever played League of Legends or Heroes of the Storm, i'm trying to create a health and shield bar that works like that. if not, I have some images for you:
(stackoverflow will not let me post more than 2 links, so just imagine a full health bar :) )
The first example is just the normal health bar displaying health. I got this to work fine by multiplying the percentage health (health/maxHealth) and multiplying that number by the length of the health bar (51)
This second example shows how the health and shield should look when the player is at full health. This is working fine too.
My problem comes here, when the player is not at full health. as you can see, in the first picture, Kalista has around 550 health. Then as she gains the shield, her health bar goes to around 850 total and the 300 health shield is grey. Then once she's taken damage to around 300 health, the 300 health shield is no longer compressed like when it was in the 850 health. My HUD health bar works until this point. Even when the health bar is not at its full capacity, it tries to compress the shield and health into what just the health bar was.
Here's my current code:
package net.masterzach32.sidescroller.assets.gfx;
import java.awt.*;
import java.awt.image.BufferedImage;
import net.masterzach32.sidescroller.assets.Assets;
import net.masterzach32.sidescroller.entity.EntityPlayer;
import net.masterzach32.sidescroller.util.LogHelper;
public class HUD {
private EntityPlayer player;
private BufferedImage image;
private Font font;
double b0 = 31, b1 = 20, hx = 31, mx = 20;
public HUD(EntityPlayer p) {
player = p;
try {
image = Assets.getImageAsset("hud");
font = new Font("Arial", Font.PLAIN, 14);
}
catch(Exception e) {
e.printStackTrace();
}
}
public void render(Graphics2D g) {
g.drawImage(image, 0, 15, null);
double h0 = player.getHealth() / player.getMaxHealth();
double h1 = h0 * hx;
double m0 = player.getShield() / player.getMaxShield();
double m1 = m0 * mx;
if((int) (h1 + m1) <= hx + mx) {
int f = (int) (mx - m1);
h1 += f;
}
LogHelper.logInfo("" + (int) (h1 + m1));
if(h1 >= b0) b0 = h1;
if(h1 < b0) b0 -= .7;
if(m1 >= b1) b1 = m1;
if(m1 < b1) b1 -= .7;
// health bar
g.setColor(new Color(200, 0, 0));
g.fillRect(17, 18, (int) b0, 13);
g.setColor(new Color(0, 170, 0));
g.fillRect(17, 18, (int) h1, 13);
// mana bar
g.setColor(new Color(200, 0, 0));
g.fillRect((int) (17 + b0), 18, (int) b1, 13);
g.setColor(Color.BLUE);
g.fillRect((int) (17 + h1), 18, (int) m1, 13);
g.setFont(font);
g.setColor(Color.WHITE);
if(player.getOrbCurrentCd() > 0) g.drawString("" + (player.getOrbCurrentCd() / 60 + 1), 0, 12);
else g.drawString("" + (player.getOrbCurrentCd() / 60), 0, 12);
g.drawString(player.getLevel() + " - " + (int) player.getExp() + "/" + (int) player.getMaxExp(), 1, 70);
g.setFont(font);
g.drawString((int) (player.getHealth()) + "/" + (int) (player.getMaxHealth()), 16, 29);
}
}
I have coded a clock using Java,
it will display the clock includes seconds,
this is how I set the Timer
Timer timer = new Timer(1000, new TimerListener());
class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}
repaint() will work on the Clock panel.
the program will display clock normally,
the only problem is that the time on the clock is 1 or 2 seconds slower than real time.
then i change the response time to 100,
Timer timer = new Timer(100, new TimerListener());
this time there is no delay compare to real time.
I just don't understand why. Can somebody explain to me how Timer works, thank you.
ps.
this is my Clock code
public class Clock extends JPanel {
public double hour;
public double minute;
public double second;
public Clock() {
setFont(Common.SetFont.font);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
FontMetrics fm = g.getFontMetrics(Common.SetFont.font);
int xCenter = getWidth() / 2;
int yCenter = getHeight() / 2;
int radius = (int)(Math.min(xCenter, yCenter) * 0.7);
int radius1 = (int)(radius * 0.8);
g.drawOval(xCenter - radius, yCenter - radius, 2 * radius, 2 * radius);
for (int i = 1; i <= 12; i++) {
g.drawString(i + "", (int)(xCenter + radius1 * Math.sin(i * Math.PI / 6)) - (int)(fm.stringWidth(i + "") / 2), (int)(yCenter - radius1 * Math.cos(i * Math.PI / 6)) + (int)(fm.getAscent() / 2));
}
Calendar calendar = new GregorianCalendar();
hour = calendar.get(calendar.HOUR);
minute = calendar.get(calendar.MINUTE);
second = calendar.get(calendar.SECOND);
// draw hour line
g.drawLine(xCenter, yCenter, xCenter + (int)(radius1 * 2 / 5 * Math.sin(2 * Math.PI * (hour + minute / 60) / 12)), yCenter - (int)(radius1 * 2 / 5 * Math.cos(2 * Math.PI * (hour + minute / 60) / 12)));
//draw minute line
g.drawLine(xCenter, yCenter, xCenter + (int)(radius1 * 3 / 5 * Math.sin(2 * Math.PI * (minute + second / 60) / 60)), yCenter - (int)(radius1 * 3 / 5 * Math.cos(2 * Math.PI * (minute + second / 60) / 60)));
//draw second line
g.drawLine(xCenter, yCenter, xCenter + (int)(radius1 * 5 / 6 * Math.sin(2 * Math.PI * (second) / 60)), yCenter - (int)(radius1 * 5 / 6 * Math.cos(2 * Math.PI * (second) / 60)));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(2000, 1000);
}
}
and this is the code of Clock Display
public class jClockAnimation extends JFrame {
Common.Clock clock = new Common.Clock();
public jClockAnimation() {
Timer timer = new Timer(100, new TimerListener());
add(clock, BorderLayout.NORTH);
add(new MessagePanel(), BorderLayout.SOUTH);
timer.start();
}
public static void main(String[] args) {
new Common.SetFrame(new jClockAnimation(), "Clock");
}
class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}
class MessagePanel extends JPanel {
public MessagePanel() {
setFont(Common.SetFont.font);
}
#Override
protected void paintComponent(Graphics g) {
String string = new String((int)clock.hour + ": " + (int)clock.minute + ": " + (int)clock.second);
FontMetrics fm = g.getFontMetrics();
g.drawString(string, getWidth() / 2 - fm.stringWidth(string) / 2, getHeight() / 2 + fm.getAscent() / 2);
}
#Override
public Dimension preferredSize() {
return new Dimension(400, 200);
}
}
}
I wrote this polar clock today and i am almost finished exept i want to align my text inside the line similar to this. Does anyone know how to do this? Ive tried to use FontRenderContext and font metrics but i cant seem to get it to work. Here is the whole source code so you can compile it and see for yourselves.
import java.applet.Applet;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.util.Calendar;
import java.util.TimeZone;
public class Clock extends Applet implements Runnable {
int[][] colorsInt = {{20,20,20},{100,100,50},{50,100,100},{10,170,50},{79,29,245},{24,69,234},{253,24,103}};
Color[] colors;
int size;
int radius;
boolean anitalias = false;
static final float HPI = (float)(Math.PI / 180f);
public void start() {
enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
new Thread(this).start();
}
public void run() {
setSize(500, 500); // For AppletViewer, remove later.
// Set up the graphics stuff, double-buffering.
BufferedImage screen = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D)screen.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
WritableRaster wr = screen.getRaster();
Graphics appletGraphics = getGraphics();
// Some variables to use for the fps.
long fpstn = 1000000000 / 600;
int tick = 0, fps = 0, acc = 0;
long lastTime = System.nanoTime();
// Vars
Calendar c;
size = 500;
radius = size / 2;
Arc2D.Float arch;
float scale, radians;
long miliSecond;
int second, minute, hour, month, year, dayOfWeek, dayOfMonth, dayOfYear, daysInMonth, daysInYear;
float[] tvars = new float[6];
float[] vars = new float[6];
String[] names = new String[6];
FontMetrics fm = g.getFontMetrics();
Font font = g.getFont();
FontRenderContext frc = g.getFontRenderContext();
GlyphVector gv = font.createGlyphVector(frc, "Hello world");
int length = gv.getNumGlyphs();
// Init
initColors();
for (int i = 0; i < vars.length; i++)
vars[i] = 0;
// Game loop.
while (true) {
long now = System.nanoTime();
acc += now - lastTime;
tick++;
if (acc >= 1000000000L) {
acc -= 1000000000L;
fps = tick;
tick = 0;
}
// Update
c = Calendar.getInstance();
miliSecond = c.get(Calendar.MILLISECOND);
second = c.get(Calendar.SECOND);
minute = c.get(Calendar.MINUTE);
hour = c.get(Calendar.HOUR_OF_DAY);
dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
dayOfYear = c.get(Calendar.DAY_OF_YEAR);
dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
month = c.get(Calendar.MONTH);
daysInMonth = c.getActualMaximum(Calendar.DAY_OF_MONTH);
daysInYear = c.getActualMaximum(Calendar.DAY_OF_YEAR);
tvars[0] = (second * 1000 + miliSecond) / 60000f * 360f;
tvars[1] = (minute * 60f + second) / 3600f * 360f;
tvars[2] = (hour * 60f + minute) / 1440f * 360f;
tvars[3] = ((dayOfWeek - 2) * 24f + hour) / 168f * 360f;
tvars[4] = ((dayOfMonth - 1) * 24f + hour) / (daysInMonth * 24f) * 360f;
tvars[5] = dayOfYear / (float)daysInYear * 360f;
for (int i = 0; i < vars.length; i++) {
if (tvars[i] - vars[i] > 1) {
vars[i] += (tvars[i] - vars[i]) / 15;
} else if(tvars[i] - vars[i] < -1) {
vars[i] -= (vars[i] - tvars[i]) / 15;
} else {
vars[i] = tvars[i];
}
}
names[0] = second + " Second" + (second > 1 ? "s" : "");
lastTime = now;
// Render
g.setColor(colors[0]);
g.fillRect(0, 0, size, size);
for (int i = 0; i < vars.length; i++) {
scale = i / (float)vars.length * radius * 1.7f;
g.setColor(colors[0]);
g.fillOval((int)(scale / 2), (int)(scale / 2), (int)(size - scale), (int)(size - scale));
g.setColor(colors[i + 1]);
scale += 15;
arch = new Arc2D.Float(scale / 2, scale / 2, size - scale, size - scale, 450 - vars[i], vars[i], Arc2D.PIE);
g.fill(arch);
g.setColor(Color.WHITE);
radians = (vars[i]) * HPI;// vars[i] - 90
scale = ((float)(vars.length - i) / (float)vars.length * (float)radius / 2f * 1.7f) + 15f;
g.translate(radius, radius);
System.out.println(i + ": " + ((1 - scale / radius) * 2));
for (int j = 0; j < names[0].length(); j++) {
char ch = names[0].charAt(j);
radians = ((vars[i] - (names[0].length() - j) * 2) * (1 + (1 - scale / radius) * 2)) * HPI;
g.rotate(radians);
g.drawString(ch + "", 0, -scale);
g.rotate(-radians);
}
g.translate(-radius, -radius);
/*float x = (float)Math.cos(radians) * scale;
float y = (float)Math.sin(radians) * (vars.length - i) / vars.length * radius / 2 * 1.7f;
g.drawRect((int)x + size / 2, (int)y + size / 2, 10, 10);*/
}
scale = vars.length / (float)vars.length * radius * 1.7f;
g.setColor(colors[0]);
g.fillOval((int)(scale / 2), (int)(scale / 2), (int)(size - scale), (int)(size - scale));
g.setColor(Color.WHITE);
g.drawString("FPS " + String.valueOf(fps), 20, 30);
// Draw the entire results on the screen.
appletGraphics.drawImage(screen, 0, 0, null);
do {
Thread.yield();
} while (System.nanoTime() - lastTime < 0);
if (!isActive()) {
return;
}
}
}
public void initColors() {
colors = new Color[colorsInt.length];
for (int i = 0; i < colors.length; i++) {
colors[i] = new Color(colorsInt[i][0], colorsInt[i][1], colorsInt[i][2]);
}
}
}
Here's a simple example of rotating text.
Addendum: You'll want to adjust the the text's radial starting point by stringWidth(name[n]). Your program appears to be rotating individual characters in a effort to follow the arc, while the example appears to be drawing the text in a straight line tangent to the arc. The latter approach may prove simpler. For example, this variation centers the labels across the arc's getStartPoint():
for (int i = 0; i < vars.length; i++) {
...
String s = names[0];
int w = fm.stringWidth(s);
int h = fm.getHeight() + fm.getMaxDescent();
Point2D p = arch.getStartPoint();
int x = (int) p.getX();
int y = (int) p.getY();
radians = (vars[i]) * HPI;
g.rotate(radians, x, y);
g.drawString(s, x - w / 2, y + h);
g.rotate(-radians, x, y);
}
For convenience the code above does rotate() to and fro; for comparison, here's the original example showing repeated concatenations of rotate():
import java.awt.*;
import java.awt.geom.AffineTransform;
import javax.swing.*;
/** #see http://stackoverflow.com/questions/6238037 */
public class RotateText extends JPanel {
private static final Font f = new Font("Serif", Font.BOLD, 32);
private static final String s = "Hello World!";
private static final Color[] colors = {
Color.red, Color.green, Color.blue, Color.cyan
};
private Graphics2D g2d;
private AffineTransform at;
public RotateText() {
setPreferredSize(new Dimension(400, 400));
}
#Override
public void paintComponent(Graphics g) {
g2d = (Graphics2D) g;
g2d.setFont(f);
g2d.setColor(Color.black);
g2d.fillRect(0, 0, getWidth(), getHeight());
at = g2d.getTransform();
int w = this.getWidth();
int h = this.getHeight();
int w2 = g2d.getFontMetrics().stringWidth(s) / 2;
int h2 = 2 * g2d.getFontMetrics().getHeight() / 3;
render(0, w / 2 - w2, h - h2);
render(1, h2, h / 2 - w2);
render(2, w / 2 + w2, h2);
render(3, w - h2, h / 2 + w2);
g2d.setTransform(at);
g2d.setColor(Color.yellow);
g2d.fillRect(w / 3, h / 3, w / 3, h / 3);
}
private void render(int n, int x, int y) {
g2d.setColor(colors[n]);
g2d.setTransform(at);
g2d.rotate(n * Math.PI / 2, x, y);
g2d.drawString(s, x, y);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
//#Override
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new RotateText(), BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
});
}
}
You have to be able to draw text along the curves. There are several ways to do it, but the simplest one is to use Stroke API. You can find an example at http://www.jhlabs.com/java/java2d/strokes/
The other way is using affine transforms. The example is at http://www.java2s.com/Code/Java/2D-Graphics-GUI/Drawtextalongacurve.htm
I'm building a Poker Odds Calc app in Java. I want to select a new card by clicking the card's placeholder which is basically an extended JPanel that I "draw" the card's face and has a mouseListener.
What I have imagined to do is that when I clicked the card, I would like a round menu to pop up around the mouse cursor having a circle in the middle cut in four with each suite in a quarter and a ring around it cut in thirteen for the value of the card. Then I will select suit and value and it would disappear. Do you know any way I could do this? I researched a bit and I think it can be done with JavaFX by making a transparent JDialog but I'm not sure.
Is there a way to draw a totally custom shaped JComponent like a JButton shaped for each quarter of the circle etc.? I have some experience in Java but not GUI building.
Thanks in advance for your time.
edit: Used your comment and have answered my question about the circular dialog (don't know if it's the best way to do it but works for now). Now, is there anyway I know in which area the click belongs (if the click was on a useful area) without hardcoding the coordinates?
I would suggest doing custom graphics rather than trying to customize JButton and so on. When you click on the JPanel you can draw the circle and so on using the java.awt.Shape interfaces and its various implementations such as java.awt.geom.Ellipse2D.
These shapes come with contains() method that can tell you if a point is in the Shape or not. This way, when the user next clicks on the JPanel, you can determine which shape the user clicked on by going through all the shapes and checking.
The code to create the graphics is this in case anyone needs it:
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D.Double;
import javax.swing.JDialog;
/**
*
* #author Dimitris Klimis <dnklimis at gmail.com>
*/
public class CardChooser extends JDialog implements MouseListener {
int sizeX = 140;
int sizeY = sizeX; //in case I don't want it to be circle
int x, y;
Point point;
public CardChooser(Point point) {
x = point.x;
y = point.y;
this.point = point;
this.initComponents();
}
public static int[] getCard(Point point) {
int[] output = {0, 0};
CardChooser chooser = new CardChooser(point);
return output;
}
#Override
public void paint(Graphics g) {
if (g instanceof Graphics2D) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//Drawing the transparent dialog
g2.setPaint(new Color(0.0f, 0.0f, 0.0f, 0.0f));
g2.fillRect(0, 0, getWidth(), getHeight());
//Drawing the circles
g2.setColor(Color.BLACK);
drawCircle(g2, 100, new GradientPaint(0.0f, 0.0f, Color.darkGray, (float) getWidth(), (float) getHeight(), Color.lightGray, false));
drawLines(g2, 13, 100);
int smallCircle = 38;
drawCircle(g2, smallCircle + 3, Color.GRAY);
drawCircle(g2, smallCircle, new GradientPaint((float) (getWidth() * 0.25), (float) (getHeight() * 0.25), Color.lightGray, (float) (getWidth() * 0.75), (float) (getHeight() * 0.75), Color.darkGray, false));
drawLines(g2, 4, smallCircle);
drawCircle(g2, 10, Color.LIGHT_GRAY);
drawSuiteLetters(g2);
drawCardValues(g2);
drawClosingX(g2);
} else {
super.paint(g);
}
}
private void drawCircle(Graphics2D g2, int percentage, Paint fill) {
double perc = (double) percentage / 100.0;
Ellipse2D ellipse = new Ellipse2D.Double(((1 - perc) / 2) * sizeX, ((1 - perc) / 2) * sizeY, perc * sizeX, perc * sizeY);
g2.setPaint(fill);
g2.fill(ellipse);
g2.setColor(Color.BLACK);
g2.draw(ellipse);
}
private void drawLines(Graphics2D g2, int outOf, int percentage) {
double rads = Math.toRadians(360.0 / outOf);
double perc = (double) percentage / 100.0;
Double zeroAxis = new Point.Double(sizeX / 2.0, sizeY / 2.0);
for (int i = 0; i < outOf; i++) {
g2.draw(new Line2D.Double(zeroAxis.x, zeroAxis.y, zeroAxis.x + (zeroAxis.x * perc * Math.sin(rads * i)), zeroAxis.y + (zeroAxis.y * perc * Math.cos(rads * i))));
}
}
private void drawSuiteLetters(Graphics2D g2) {
Double zeroAxis = new Point.Double(sizeX / 2.0, sizeY / 2.0);
g2.setFont(new Font("Courier New", Font.BOLD, 25));
g2.drawString("\u2660", (float) zeroAxis.x - 18, (float) zeroAxis.y - 5);//spades
g2.drawString("\u2663", (float) zeroAxis.x + 3, (float) zeroAxis.y + 20);//clubs
g2.setColor(Color.RED);
g2.drawString("\u2665", (float) zeroAxis.x + 3, (float) zeroAxis.y - 3);//hearts
g2.drawString("\u2666", (float) zeroAxis.x - 18, (float) zeroAxis.y + 19);//diamonds
g2.setColor(Color.BLACK);
}
private void drawCardValues(Graphics2D g2) {
Double zeroAxis = new Point.Double((sizeX / 2.0) - 8, 21);
float xx = (float) zeroAxis.x;
float yy = (float) zeroAxis.y;
g2.setFont(new Font("Arial", Font.BOLD, 24));
String[] letters = {"A", "K", "Q", "J", "T", "9", "8", "7", "6", "5", "4", "3", "2"};
float[] xPosition = {0, 25, 46, 63, 58, 42, 15, -10, -37, -53, -58, -46, -25};
float[] yPosition = {0, 7, 23, 50, 80, 102, 115, 115, 102, 80, 50, 23, 7};
for (int i = 0; i < 13; i++) {
g2.drawString(letters[i], xx + xPosition[i], yy + yPosition[i]);
}
}
private void drawClosingX(Graphics2D g2) {
Double zeroAxis = new Point.Double(sizeX / 2.0, sizeY / 2.0);
g2.draw(new Line2D.Double(zeroAxis.x - 5, zeroAxis.y - 5, zeroAxis.x + 5, zeroAxis.y + 5));
g2.draw(new Line2D.Double(zeroAxis.x - 5, zeroAxis.y + 5, zeroAxis.x + 5, zeroAxis.y - 5));
}
private void initComponents() {
this.addMouseListener(this);
this.setBounds(x - (sizeX / 2), y - (sizeY / 2), sizeX + 1, sizeX + 1);
this.setUndecorated(true);
this.setModal(true);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.setVisible(true);
}
public void mouseClicked(MouseEvent e) {
this.dispose();
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
PS. I extended JDialog cause I couldn't get JPanel to show up...