How to change the color of multiple ellipses using a loop (JFreeChart) - jfreechart

I have drawn multiple ellipses using a loop as shown below, and the results are perfect using one color for all the ellipses, but my target is to color each ellipse with different color. Is there any way to let the property Color.BLUE change its value in each iteration?
for (int i = 0; i < 3; i++)
{
XYShapeAnnotation unitCircle1 = new XYShapeAnnotation(
new Ellipse2D.Double((FinalArayOfOptpar[s][i] - Math.abs(FinalArayOfOptpar[s][i + 2])),
(FinalArayOfOptpar[s][i + 1] - Math.abs(FinalArayOfOptpar[s][i + 3])),
Math.abs(FinalArayOfOptpar[s][i + 2] * 2.0), Math.abs(FinalArayOfOptpar[s][i + 3] * 2.0)),
new BasicStroke(0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
10.2f), Color.BLUE);
xyPlot.addAnnotation(unitCircle1);
}

tens of XYShapeAnnotations will be created…so creating multiple instances of XYShapeAnnotation will not work for my purpose.
Happily, an instance XYShapeAnnotation is small—just 48 bytes each in the example below. You'll want to profile to be sure.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.geom.Ellipse2D;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.XYShapeAnnotation;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* #see https://stackoverflow.com/a/35236100/230513
*/
public class AnnotationTest {
private static final BasicStroke stroke = new BasicStroke(2.0f);
private static final int N = 16;
private static final int S = 8;
public static void main(String[] args) {
EventQueue.invokeLater(new AnnotationTest()::display);
}
private void display() {
XYDataset data = createDataset();
JFreeChart chart = ChartFactory.createXYLineChart("ArcTest", "X", "Y",
data, PlotOrientation.VERTICAL, true, true, false);
XYPlot plot = chart.getXYPlot();
XYLineAndShapeRenderer renderer
= (XYLineAndShapeRenderer) plot.getRenderer();
renderer.setBaseShapesVisible(true);
for (int i = 0; i < N; i++) {
double x = data.getXValue(0, i) - S / 2;
double y = data.getYValue(0, i) - S / 2;
Ellipse2D.Double ellipse = new Ellipse2D.Double(x, y, S, S);
Color color = Color.getHSBColor((float) i / N, 1, 1);
renderer.addAnnotation(new XYShapeAnnotation(ellipse, stroke, color));
}
ChartFrame frame = new ChartFrame("Test", chart);
frame.pack();
frame.setVisible(true);
}
private static XYDataset createDataset() {
XYSeriesCollection result = new XYSeriesCollection();
XYSeries series = new XYSeries("ArcTest");
for (int i = 0; i < N; i++) {
series.add(i * S, i * S);
}
result.addSeries(series);
return result;
}
}

Related

Rubberband effect for scrolling containers

I'd like to have a rubberband effect on scrolling containers for which I feel the "tensile scrolling" that is build into the Component base class is no sufficient replacement.
Is there a reasonably feasible way like disabling the default overscroll behavior in order to control the property scrollY in a way like in this example - How to create the rubberband effect?
Since there was no answer to my question I answer it myself. Beware that I am not an expert and therefore this might not fit Your purpose!
The default overscroll behaviour can be overridden by extending the Container class and overriding the pointer methods without calling their super methods.
Here is an example:
import com.codename1.ui.Component;
import com.codename1.ui.Container;
import com.codename1.ui.Form;
import com.codename1.ui.Graphics;
import com.codename1.ui.Label;
import com.codename1.ui.animations.Motion;
import com.codename1.ui.geom.Point;
import com.codename1.ui.layouts.BorderLayout;
import com.codename1.ui.layouts.BoxLayout;
public class FormOverscroll extends Form {
FormOverscroll() {
super("FormOverscroll");
setScrollable(false);
setLayout(new BorderLayout());
Container container = new Container(BoxLayout.y()) {
boolean bounce = false;
Motion motion = null;
Point pointPressed = null;
long millisPoint = 0;
int scrollYPressed = 0, scrollYPrevious = 0;
{
// setTensileDragEnabled(false);
setScrollableY(true);
}
#Override
protected boolean isStickyDrag() {
return true;
}
#Override
public void pointerPressed(int x, int y) {
pointPressed = new Point(x, y);
scrollYPressed = scrollYPrevious = getScrollY();
millisPoint = System.currentTimeMillis();
motion = null;
bounce = false;
}
#Override
public void pointerDragged(int x, int y) {
if (null == pointPressed) {
return;
}
int yDist = y - pointPressed.getY();
int scrollY = scrollYPressed - yDist;
if (scrollY < 0) {
Motion motionRubberband = Motion.createCubicBezierMotion(0, scrollY, getHeight(), 0f, 1.2f, 0.5f, 0.6f);
motionRubberband.setStartTime(0);
motionRubberband.setCurrentMotionTime(Math.abs(scrollY));
scrollY = motionRubberband.getValue();
}
setScrollY(scrollY);
}
float getVelocity(int scrollY) {
long millisNow = System.currentTimeMillis();
long timediff = millisNow - millisPoint;
float diff = scrollYPrevious - scrollY;
float velocity = (diff / timediff) * -1f;
scrollYPrevious = scrollY;
millisPoint = millisNow;
return velocity;
}
#Override
public void pointerReleased(int x, int y) {
if (null == pointPressed) {
return;
}
int yDist = y - pointPressed.getY();
int scrollY = scrollYPressed - yDist;
float velocity = getVelocity(scrollY);
motion = Motion.createFrictionMotion(scrollY, Integer.MIN_VALUE, velocity, 0.0007f);
motion.start();
getComponentForm().registerAnimated(this);
pointPressed = null;
}
#Override
public boolean animate() {
boolean animate = super.animate();
if (null != motion) {
int scrollY = motion.getValue();
setScrollY(scrollY);
int target = 0;
if (scrollY < target && !bounce) {
createRubberbandMotion(scrollY, target);
bounce = true;
motion.start();
}
int maxScrollY = Math.max(target, getScrollDimension().getHeight() - getHeight());
if (scrollY > maxScrollY && !bounce) {
createRubberbandMotion(scrollY, maxScrollY);
bounce = true;
motion.start();
}
scrollYPrevious = scrollY;
if (motion.isFinished()) {
motion = null;
}
return true;
}
return animate;
}
private void createRubberbandMotion(int source, int target) {
motion = Motion.createCubicBezierMotion(source, target, 500, 0.0f, 1.0f, 1.2f, 1.0f);
}
#Override
public Component getComponentAt(int x, int y) {
return this;
}
#Override
public void paint(Graphics aGraphics) {
super.paint(aGraphics);
}
};
for (int index = 0; index < 100; index++) {
container.add(new Label("Zeile " + index));
}
add(BorderLayout.CENTER, container);
}
}

Setting up a Timeline with a for loop in JavaFX

I'm trying to write an animated sort for a class I'm in. My goal is to have the sort displayed as vertical white bars that will be rendered on the canvas I've created.
I've attempted to accomplish this using a Timeline and Keyframes, but the output I get is a blank white canvas that after a few moments outputs the finished and sorted array.
I've resorted to just shuffling around code with no success, and can't find any helpful examples online. I'm hoping someone with some more experience with JavaFX animation can help me learn more about how to properly set this up!
Note that in the code below the array created with the random method is commented out because when used it makes the program hang for long time. The code will output in a reasonable time with a smaller array.
import java.util.Random;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.util.Duration;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
public class Project06 extends Application
{
final int SCALE = 16;
final int WIDTH = 64;
final int HEIGHT = 32;
int[][] pixels;
Timeline sortLoop;
int[] myArray = {32,28,22,20,16,13,10,9,5,3};
#Override
public void start(Stage primaryStage) throws Exception
{
pixels = new int[WIDTH][HEIGHT];
int[] myArray = new int[WIDTH];
/*
Random rand = new Random();
for (int i = 0; i < WIDTH; i++)
{
myArray[i] = rand.nextInt((HEIGHT) + 1);
}
*/
Canvas display = new Canvas (WIDTH*SCALE, HEIGHT*SCALE);
GraphicsContext gc = display.getGraphicsContext2D();
GridPane grid = new GridPane();
grid.add(display, 0, 0);
primaryStage.setTitle("Sort");
primaryStage.setScene(new Scene(grid, WIDTH*SCALE, HEIGHT*SCALE));
primaryStage.show();
sortLoop = new Timeline();
sortLoop.setCycleCount(Timeline.INDEFINITE);
// Sort array
for (int i = 0; i < myArray.length - 1; i++)
{
if (myArray[i] > myArray[i + 1])
{
int swap = myArray[i];
myArray[i] = myArray[i + 1];
myArray[i + 1] = swap;
i = -1;
}
// Clear screen by zeroing out pixel array
for (int k = 0; k < WIDTH; k++)
{
for (int j = 0; j < HEIGHT; j++)
{
pixels[k][j] = 0;
}
}
// Draw array with vertical bars (assign values to canvas array)
for (int k = 0; k < myArray.length; k++)
{
for (int j = (HEIGHT - 1); j > ((HEIGHT - myArray[k]) - 1); j--)
{
pixels[k][j] = 1;
}
}
KeyFrame kf = new KeyFrame(Duration.seconds(1), actionEvent -> {
// Render canvas
for (int k = 0; k < WIDTH; k++)
{
for (int j = 0; j < HEIGHT; j++)
{
if (pixels[k][j] == 1)
{
gc.setFill(Color.WHITE);
gc.fillRect((k*SCALE), (j*SCALE), SCALE, SCALE);
}
else
{
gc.setFill(Color.BLACK);
gc.fillRect((k*SCALE), (j*SCALE), SCALE, SCALE);
}
}
}
});
sortLoop.getKeyFrames().add(kf);
sortLoop.play();
}
}
public static void main(String[] args)
{
launch(args);
}
}
First, you are setting the timepoint for all your key frames to the same value (one second), so they all happen simultaneously. You need each key frame to have a different timepoint, so they happen sequentially.
Second, you sort the array, and then the event handlers for the keyframes reference the array. Since the event handlers for the keyframes are executed later, they only see the sorted array. You need to actually manipulate the array in the event handlers for the key frames.
Third, you play the timeline multiple times. You only need to play it once. Additionally, you set the cycle count to INDEFINITE: I think you only need to animate the sort once. (If you actually want it to repeat, you would need to set the array back to its original order at the beginning of the timeline.)
Finally, you have some issues in the implementation of the actual sort algorithm. This is why your application hangs when you randomly populate the array. I won't address those issues here, because the question is about how to perform the animation.
The following code performs a step-by-step animation. It's probably not the correctly-implemented sort, so you won't see the animation you necessarily expect, but it at least repaints the effect of the swaps in an animation:
import java.util.Random;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.util.Duration;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
public class AnimatedSort extends Application
{
final int SCALE = 16;
final int WIDTH = 64;
final int HEIGHT = 32;
int[][] pixels;
Timeline sortLoop;
int[] myArray = {32,28,22,20,16,13,10,9,5,3};
#Override
public void start(Stage primaryStage) throws Exception
{
pixels = new int[WIDTH][HEIGHT];
// int[] myArray = new int[WIDTH];
//
//
// Random rand = new Random();
// for (int i = 0; i < WIDTH; i++)
// {
// myArray[i] = rand.nextInt((HEIGHT) + 1);
// }
Canvas display = new Canvas (WIDTH*SCALE, HEIGHT*SCALE);
GraphicsContext gc = display.getGraphicsContext2D();
GridPane grid = new GridPane();
grid.add(display, 0, 0);
primaryStage.setTitle("Sort");
primaryStage.setScene(new Scene(grid, WIDTH*SCALE, HEIGHT*SCALE));
primaryStage.show();
sortLoop = new Timeline();
// sortLoop.setCycleCount(Timeline.INDEFINITE);
// Sort array
for (int index = 0; index < myArray.length - 1; index++)
{
final int i = index ;
KeyFrame kf = new KeyFrame(Duration.seconds(i+1), actionEvent -> {
if (myArray[i] > myArray[i + 1])
{
int swap = myArray[i];
myArray[i] = myArray[i + 1];
myArray[i + 1] = swap;
// i = -1;
}
// Clear screen by zeroing out pixel array
for (int k = 0; k < WIDTH; k++)
{
for (int j = 0; j < HEIGHT; j++)
{
pixels[k][j] = 0;
}
}
// Draw array with vertical bars (assign values to canvas array)
for (int k = 0; k < myArray.length; k++)
{
for (int j = (HEIGHT - 1); j > ((HEIGHT - myArray[k]) - 1); j--)
{
pixels[k][j] = 1;
}
}
// Render canvas
for (int k = 0; k < WIDTH; k++)
{
for (int j = 0; j < HEIGHT; j++)
{
if (pixels[k][j] == 1)
{
gc.setFill(Color.WHITE);
gc.fillRect((k*SCALE), (j*SCALE), SCALE, SCALE);
}
else
{
gc.setFill(Color.BLACK);
gc.fillRect((k*SCALE), (j*SCALE), SCALE, SCALE);
}
}
}
});
sortLoop.getKeyFrames().add(kf);
}
sortLoop.play();
}
public static void main(String[] args)
{
launch(args);
}
}
The time property of KeyFrame denotes the time since the start of the animation, not the time since the previously added KeyFrame. You need to position. You need to pass different times to the KeyFrame constructor.
Furthermore you "sort" a fresh array instead of using the field. Also your pixels array contains the last value from the start.
Better save the swaps to a data structure and use a Timeline to render the changes step by step:
final int SCALE = 16;
final int WIDTH = 64;
final int HEIGHT = 32;
Timeline sortLoop;
int[] myArray = {32, 28, 22, 20, 16, 13, 10, 9, 5, 3};
private void renderBar(GraphicsContext gc, int barIndex, double canvasHeight, int barHeight) {
double rectHeight = barHeight * SCALE;
gc.fillRect(SCALE * barIndex, canvasHeight - rectHeight, SCALE, rectHeight);
}
#Override
public void start(Stage primaryStage) throws Exception {
int[] myArray = this.myArray.clone(); // copy field (you may also simply delete this declaration, if you never reuse the initial array)
class Swap {
final int lowerIndex, value1, value2;
public Swap(int lowerIndex, int value1, int value2) {
this.lowerIndex = lowerIndex;
this.value1 = value1;
this.value2 = value2;
}
}
final double canvasHeight = HEIGHT * SCALE;
Canvas display = new Canvas(WIDTH * SCALE, canvasHeight);
GraphicsContext gc = display.getGraphicsContext2D();
primaryStage.setTitle("Sort");
primaryStage.setScene(new Scene(new Group(display)));
primaryStage.show();
// render initial state
gc.setFill(Color.WHITE);
gc.fillRect(0, 0, display.getWidth(), canvasHeight);
gc.setFill(Color.BLACK);
for (int i = 0; i < myArray.length; i++) {
renderBar(gc, i, canvasHeight, myArray[i]);
}
// Sort array & save changes
List<Swap> swaps = new ArrayList<>();
for (int i = 0; i < myArray.length - 1; i++) {
if (myArray[i] > myArray[i + 1]) {
int swap = myArray[i];
myArray[i] = myArray[i + 1];
myArray[i + 1] = swap;
swaps.add(new Swap(i, myArray[i], swap));
i = -1;
} else {
// no change
swaps.add(null);
}
}
sortLoop = new Timeline();
sortLoop.setCycleCount(swaps.size());
final Iterator<Swap> iter = swaps.iterator();
sortLoop.getKeyFrames().add(new KeyFrame(Duration.seconds(1), evt -> {
Swap swap = iter.next();
if (swap != null) {
// clear old area
gc.setFill(Color.WHITE);
gc.fillRect(SCALE * swap.lowerIndex, 0, SCALE * 2, canvasHeight);
// draw new bars
gc.setFill(Color.BLACK);
renderBar(gc, swap.lowerIndex, canvasHeight, swap.value1);
renderBar(gc, swap.lowerIndex+1, canvasHeight, swap.value2);
}
}));
sortLoop.play();
}

JFreeChart XYLineAndShapeRenderer show unwanted vales outside range start and finish

Im build a series graph with jfreechart using XYLineAndShapeRenderer, this series need to show values for each day of a month, then I need that the X axis shows values from 1 to 30 or 1 to 31 (depend of current month). The dataset only have X values from 1 to 30/31, but the resultant graph shows ZERO(before 1) and 31/32 after(30/31). I want to show only 1 to 30/31 on X axis. But I dont have success. Follow shows the code that build dataset and graph and resultante image.
How I can show only valid values on X axis in this case ?
// build dataset
private XYDataset createSampleData()
{
List<Integer> diario = new ArrayList<>(Arrays.asList(20, 50, 120, 78, 37, 69, 145));
int dSize = diario.size();
int dPos = 0;
XYSeries serieD = new XYSeries("Diário");
XYSeries serieA = new XYSeries("Acumulado");
int acumulado = 0;
for(int i=1; i < 31; i++) {
int valDay = diario.get(dPos++);
acumulado += valDay;
serieD.add(i, valDay);
serieA.add(i, acumulado);
if( dPos >= dSize ) {
dPos = 0;
}
}
XYSeriesCollection result = new XYSeriesCollection(serieD);
result.addSeries(serieA);
return result;
}
private JFreeChart buildSeriesChartBySeriesData(String title, String labelX, String labelY)
{
NumberAxis xAxis = new NumberAxis(labelX);
xAxis.setAutoRangeIncludesZero(false);
xAxis.setRangeType(RangeType.POSITIVE);
NumberAxis yAxis = new NumberAxis(labelY);
yAxis.setAutoRangeIncludesZero(false);
yAxis.setRangeType(RangeType.POSITIVE);
XYSplineRenderer renderer1 = new XYSplineRenderer();
XYPlot plot = new XYPlot(this.createSampleData(), xAxis, yAxis, renderer1);
plot.setDomainGridlinesVisible(true);
plot.setDomainZeroBaselineVisible(false);
plot.setDomainPannable(false);
plot.setBackgroundPaint(new Color(224, 224,235));
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
plot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
plot.setRangeAxisLocation(AxisLocation.TOP_OR_LEFT);
plot.setDomainPannable(false);
plot.setRangePannable(false);
plot.setDomainZeroBaselineVisible(false);
plot.setRangeZeroBaselineVisible(false);
renderer1.setSeriesPaint(0, Color.blue);
renderer1.setSeriesPaint(1, Color.yellow);
plot.setAxisOffset(new RectangleInsets(3, 3, 3, 3));
plot.setDomainCrosshairVisible(true);
plot.setRangeCrosshairVisible(true);
XYLineAndShapeRenderer localXYLineAndShapeRenderer = (XYLineAndShapeRenderer) plot.getRenderer();
localXYLineAndShapeRenderer.setBaseShapesVisible(true);
localXYLineAndShapeRenderer.setBaseShapesFilled(true);
localXYLineAndShapeRenderer.setDrawOutlines(true);
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
// show item labels:
final XYItemRenderer renderer = plot.getRenderer();
ItemLabelPosition position = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER);
renderer.setBasePositiveItemLabelPosition(position);
final StandardXYItemLabelGenerator generator = new StandardXYItemLabelGenerator();
renderer.setSeriesItemLabelGenerator(0, generator);
renderer.setSeriesItemLabelsVisible(0, true);
renderer.setSeriesItemLabelGenerator(1, generator);
renderer.setSeriesItemLabelsVisible(1, true);
JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, true);
return chart;
}
In the next graph, I draw with timeSeries, and the results is the same, showing the last day of previos month and first day of next month, I don not want to show this values.
The result that I need is like this image(a sample from chartJs):
How I can hide the zero and 31 from result of first top graph ?
long time later...
---- after a long time I make the desired graph myself -----
This code generates the right graph:
private JFreeChart TimeSeriesChartExample()
{
XYDataset dataset = createSampleMonthData();
// Create chart
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"Time Series Chart Example",
"Date",
"Values",
dataset, true, true, false);
// Changes background color
XYPlot plot = (XYPlot)chart.getPlot();
plot.setBackgroundPaint(new Color(224, 224,235));
XYSplineRenderer renderer1 = new XYSplineRenderer();
renderer1.setSeriesPaint(0, Color.blue);
renderer1.setSeriesPaint(1, Color.green);
plot.setRenderer(renderer1);
plot.setAxisOffset(new RectangleInsets(3, 3, 3, 3));
// show item labels:
XYItemRenderer renderer = plot.getRenderer();
ItemLabelPosition position = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER);
renderer.setBasePositiveItemLabelPosition(position);
final StandardXYItemLabelGenerator generator = new StandardXYItemLabelGenerator();
renderer.setSeriesItemLabelGenerator(0, generator);
renderer.setSeriesItemLabelsVisible(0, true);
renderer.setSeriesItemLabelGenerator(1, generator);
renderer.setSeriesItemLabelsVisible(1, true);
DateAxis xAxis = (DateAxis)plot.getDomainAxis();
xAxis.setDateFormatOverride(new SimpleDateFormat("dd/MM/yy"));
ValueAxis domainAxis = plot.getDomainAxis();
domainAxis.setVerticalTickLabels(true);
return chart;
}
This is the resultando graph:
The solution is the follow, I put on the question body too:
private JFreeChart TimeSeriesChartExample()
{
XYDataset dataset = createSampleMonthData();
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"Time Series Chart Example",
"Date",
"Values",
dataset, true, true, false);
// Changes background color
XYPlot plot = (XYPlot)chart.getPlot();
plot.setBackgroundPaint(new Color(224, 224,235));
XYSplineRenderer renderer1 = new XYSplineRenderer();
renderer1.setSeriesPaint(0, Color.blue);
renderer1.setSeriesPaint(1, Color.green);
plot.setRenderer(renderer1);
plot.setAxisOffset(new RectangleInsets(3, 3, 3, 3));
XYItemRenderer renderer = plot.getRenderer();
ItemLabelPosition position = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER);
renderer.setBasePositiveItemLabelPosition(position);
final StandardXYItemLabelGenerator generator = new StandardXYItemLabelGenerator();
renderer.setSeriesItemLabelGenerator(0, generator);
renderer.setSeriesItemLabelsVisible(0, true);
renderer.setSeriesItemLabelGenerator(1, generator);
renderer.setSeriesItemLabelsVisible(1, true);
DateAxis xAxis = (DateAxis)plot.getDomainAxis();
xAxis.setDateFormatOverride(new SimpleDateFormat("dd/MM/yy"));
ValueAxis domainAxis = plot.getDomainAxis();
domainAxis.setVerticalTickLabels(true);
return chart;
}
This is the result:
Code as tested:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYSplineRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;
/**
* #see https://stackoverflow.com/a/49909020/230513
*/
public class ChartTest {
private void display() {
JFrame f = new JFrame("ChartTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new ChartPanel(createTimeSeriesChartExample()){
#Override
public Dimension getPreferredSize() {
return new Dimension(1000, 400);
}
});
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private XYDataset createSampleMonthData() {
List<Integer> diario = new ArrayList<>(
Arrays.asList(20, 50, 120, 78, 37, 69, 145));
int dSize = diario.size();
int dPos = 0;
XYSeries serieD = new XYSeries("Diário");
XYSeries serieA = new XYSeries("Acumulado");
int acumulado = 0;
for (int i = 1; i < 31; i++) {
int valDay = diario.get(dPos++);
acumulado += valDay;
serieD.add(i, valDay);
serieA.add(i, acumulado);
if (dPos >= dSize) {
dPos = 0;
}
}
XYSeriesCollection result = new XYSeriesCollection(serieD);
result.addSeries(serieA);
return result;
}
private JFreeChart createTimeSeriesChartExample() {
XYDataset dataset = createSampleMonthData();
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"Time Series Chart Example",
"Date",
"Values",
dataset, true, true, false);
// Changes background color
XYPlot plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(new Color(224, 224, 235));
XYSplineRenderer renderer1 = new XYSplineRenderer();
renderer1.setSeriesPaint(0, Color.blue);
renderer1.setSeriesPaint(1, Color.green);
plot.setRenderer(renderer1);
plot.setAxisOffset(new RectangleInsets(3, 3, 3, 3));
XYItemRenderer renderer = plot.getRenderer();
ItemLabelPosition position = new ItemLabelPosition(
ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER);
renderer.setBasePositiveItemLabelPosition(position);
final StandardXYItemLabelGenerator generator =
new StandardXYItemLabelGenerator();
renderer.setSeriesItemLabelGenerator(0, generator);
renderer.setSeriesItemLabelsVisible(0, true);
renderer.setSeriesItemLabelGenerator(1, generator);
renderer.setSeriesItemLabelsVisible(1, true);
DateAxis xAxis = (DateAxis) plot.getDomainAxis();
xAxis.setDateFormatOverride(new SimpleDateFormat("dd/MM/yy"));
ValueAxis domainAxis = plot.getDomainAxis();
domainAxis.setVerticalTickLabels(true);
return chart;
}
public static void main(String[] args) {
EventQueue.invokeLater(new ChartTest()::display);
}
}

How do i remove the milliseconds from my timer

I am making this game for school and I am trying to add a timer to levels. I have the timer working but not the way I want it to. It refreshes and it has milliseconds. I have searched every website for an answer but I can only find with dates and times or how do display them. I need the exact opposite.
package GameState;
import Main.GamePanel;
import TileMap.*;
import Entity.*;
import Entity.Enemies.*;
import Audio.AudioPlayer;
//timer imports
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
public class Level1State extends GameState {
private TileMap tileMap;
private Background bg;
private static int cnt;
private Player player;
private ArrayList<Enemy> enemies;
private ArrayList<Explosion> explosions;
private HUD hud;
private AudioPlayer bgMusic;
public Level1State(GameStateManager gsm) {
this.gsm = gsm;
init();
}
public void init() {
tileMap = new TileMap(30);
tileMap.loadTiles("/Tilesets/grasstileset.gif");
tileMap.loadMap("/Maps/level1-1.map");
tileMap.setPosition(0, 0);
tileMap.setTween(1);
bg = new Background("/Backgrounds/grassbg1.2.jpg", 0.1);
player = new Player(tileMap);
player.setPosition(100, 100);
populateEnemies();
explosions = new ArrayList<Explosion>();
hud = new HUD(player);
bgMusic = new AudioPlayer("/Music/level1-1.mp3");
bgMusic.play();
}
private void populateEnemies() {
enemies = new ArrayList<Enemy>();
Slugger s;
Point[] points = new Point[] {
new Point(200, 100),
new Point(860, 200),
new Point(1525, 200),
new Point(1680, 200),
new Point(1800, 200)
};
for(int i = 0; i < points.length; i++) {
s = new Slugger(tileMap);
s.setPosition(points[i].x, points[i].y);
enemies.add(s);
}
}
public void update() {
// update player
player.update();
tileMap.setPosition(
GamePanel.WIDTH / 2 - player.getx(),
GamePanel.HEIGHT / 2 - player.gety()
);
// set background
bg.setPosition(tileMap.getx(), tileMap.gety());
// attack enemies
player.checkAttack(enemies);
// update all enemies
for(int i = 0; i < enemies.size(); i++) {
Enemy e = enemies.get(i);
e.update();
if(e.isDead()) {
enemies.remove(i);
i--;
explosions.add(
new Explosion(e.getx(), e.gety()));
}
}
// update explosions
for(int i = 0; i < explosions.size(); i++) {
explosions.get(i).update();
if(explosions.get(i).shouldRemove()) {
explosions.remove(i);
i--;
}
}
}
public void draw(final Graphics2D g) {
// draw bg
bg.draw(g);
// draw tilemap
tileMap.draw(g);
// draw player
player.draw(g);
// draw enemies
for(int i = 0; i < enemies.size(); i++) {
enemies.get(i).draw(g);
}
// draw explosions
for(int i = 0; i < explosions.size(); i++) {
explosions.get(i).setMapPosition(
(int)tileMap.getx(), (int)tileMap.gety());
explosions.get(i).draw(g);
}
// draw hud
hud.draw(g);
ActionListener actListner = new ActionListener() {
public void actionPerformed(ActionEvent event) {
cnt += 1;
g.drawString("Counter = "+cnt, 120, 120);
}
};
Timer timer = new Timer(1000, actListner);
timer.start();
}
public void keyPressed(int k) {
if(k == KeyEvent.VK_LEFT) player.setLeft(true);
if(k == KeyEvent.VK_RIGHT) player.setRight(true);
if(k == KeyEvent.VK_UP) player.setUp(true);
if(k == KeyEvent.VK_DOWN) player.setDown(true);
if(k == KeyEvent.VK_W) player.setJumping(true);
if(k == KeyEvent.VK_E) player.setGliding(true);
if(k == KeyEvent.VK_R) player.setScratching();
if(k == KeyEvent.VK_F) player.setFiring();
}
public void keyReleased(int k) {
if(k == KeyEvent.VK_LEFT) player.setLeft(false);
if(k == KeyEvent.VK_RIGHT) player.setRight(false);
if(k == KeyEvent.VK_UP) player.setUp(false);
if(k == KeyEvent.VK_DOWN) player.setDown(false);
if(k == KeyEvent.VK_W) player.setJumping(false);
if(k == KeyEvent.VK_E) player.setGliding(false);
}
}
this is the part i need help with:
ActionListener actListner = new ActionListener() {
public void actionPerformed(ActionEvent event) {
cnt += 1;
g.drawString("Counter = "+cnt, 120, 120);
}
};
Timer timer = new Timer(1000, actListner);
timer.start();
Can anyone help me? I just can't get it to stop refreshing and it won't remove the milliseconds either.
Thank you in advance
P.S.
I have a feeling the first second runs way slower than the others.
P.P.S.: i have looked at "how to implement timers" but none of those worked and I found this one on a website that doesn't return an error.

Loop, iterate with unexpected results, Propertie

package javaapplication43;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import java.io.FileInputStream;
public class JavaApplication43 {
int totalResults = 45; //
int itemsperPage = 10;
int i = 0;
int j = 0;
int count = 0;
FileOutputStream output = null;
Properties prop = new Properties();
FileInputStream input=null;
public JavaApplication43() throws FileNotFoundException, IOException {
output = new FileOutputStream("config.properties");
// set the properties value
prop.setProperty("totalResults", "45");
prop.setProperty("itemsperPage", "10");
prop.setProperty("?", "?");
// save properties to project root folder
prop.store(output, null);
input = new FileInputStream("config.properties");
// load a properties file
prop.load(input);
// get the property value and print it out
System.out.println(prop.getProperty("totalResults"));
System.out.println(prop.getProperty("itemsperPage"));
System.out.println(prop.getProperty("?"));
}
public void makeLoop() {
for (i = 1; i <= (totalResults / itemsperPage) + 1; i++) {
System.out.println("nextPage " + i);
for (; j < i * itemsperPage; j++) {
if (j > totalResults) {
break;
}
System.out.println("Filenumber " + (j + 1));
}
}
}
public static void main(String[] args) throws IOException {
JavaApplication43 myTest = new JavaApplication43();
myTest.makeLoop();
}
}
*This Code gives the Result:
nextPage1: Filnumber1, Filnumber2...Filenumber10
nextPage2: Filenumber11, Filenumber12.., Filenumber20
nextPage5: Filenumber41, Filenumber42.., Filenumber46
And so on. I expect the result so, if i start the next time with a sheduller it should start
with the nextpage2 and print the files from 11-20,
if i start again the programm it should start with the nextpage 3 and print the files from 21-30 and so on depends on the value wich i have for totalResults.
The Solution is may to save the value in the Property to make it Persistent, so that
if i run the Programm again, it will read the Property config.properties to start on the right index, but i dont know how to iterate, through the loop. ?
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import java.io.FileInputStream;
public class JavaApplication43_with_Main_3 {
public static void main(String[] args) throws IOException {
int totalResults = 45; //
int itemsperPage = 10;
int i = 0;
int j = 0;
FileOutputStream output = null;
Properties prop = new Properties();
FileInputStream input = null;
input = new FileInputStream("config.properties");
// load a properties file
prop.load(input);
// get the property value and print it out
System.out.println("nextPage Prop " + prop.getProperty("nextPage"));
String nextPage = prop.getProperty("nextPage");
int intNextPage = Integer.parseInt(nextPage);
System.out.println("intNextPage " + intNextPage);
for (i = intNextPage; i <= (totalResults / itemsperPage) + 1; i++) {
int jNextPage=intNextPage-1;
System.out.println("nextPage here " + i);
for (j=jNextPage*itemsperPage; j < i * itemsperPage; j++) {
// System.out.println("j ist "+j);
if (j > totalResults) {
break;
}
System.out.println("Filenumber " + (j + 1));
}
String strI = "" + (i + 1);
System.out.println("hello " + strI);
output = new FileOutputStream("config.properties");
prop.setProperty("nextPage", strI);
prop.store(output, null);
break;
}
}
}
This is the does make loop and printing out
nextPage 1, Filenumber1,Filenumber2,..,Filenumber10
then it saves the nextPage value into the Property File.
If you start again, it does printing out
nextPage 2, Filenumber11,Filenumber12,...,Filenumber20
You should have e Propertiy File with the Name, config.properties
and but the key nextPage and the value 1, nextPage=1;--->config.properties

Resources