This is just an exercise in mechanics. I am attempting to create three custom panels that control their own progress bar. It’s part of a time management program I am writing for myself to learn more about Java. The larger program uses dates input by the user to create the framework for the min/max of the progress bar. Both this program and the larger one exhibit the same behavior with multiple bars racing the clock.
The issue I am having is that if I have just one bar everything seems to work just fine, but when I have more than one everything seems to go bust. So I wrote this little program to test some things out. It’s very simple, takes three custom panels, gives them a label and uses a timer event to change the label and the position of the progress bar. My question is If the math lines up (System output shows the calculation) and I’m counting events every second (1000 milliseconds) why is everything beating the count down.
Please forgive my lack of form with my code. I’m more concerned with the logic than the form.
(Most of the below is cut from my larger program, so if you see extraneous bits they really do have a home)
Thank you in advance.
import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.Color;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
public class plaything extends JFrame implements ActionListener
{
myPanel[] mp = new myPanel[3];
JLabel[] jl = new JLabel[3];
short[] tim = new short[3];
short x = 0;
short t = 0; //used to stagger the clocks
short dateSaver; //holds temp dates
public plaything()
{
setSize(400, 350);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(3, 1) );
for(short x = 0; x < 3; x++)
{
mp[x] = new myPanel();
//sets all three bars to different 'times'
dateSaver = (short)(10 + t) ;
tim[x] = dateSaver;
mp[x].setMax( dateSaver );
jl[x] = new JLabel("Expires: " + dateSaver);
this.add(mp[x]);
mp[x].add( jl[x] );
t += 15; // 15 seconds
}
Timer time = new Timer(1000, this);
time.start();
}
public void actionPerformed(ActionEvent e)
{
if ( x < 60 )
{
x++;
}
else
{
x = 1;
}
for(myPanel m : mp)
{
m.tock();
}
for(short x = 0; x < 3; x++ )
{
mp[x].tock();
jl[x].setText( "" + --tim[x] );
}
}
private class myPanel extends JPanel
{
//Fields
private boolean finished = false;
//(x,y) Coords
private short x = 15;
private short y = 50;
//Size and shape
private short width = 200;
private short height = 10;
private short arcSize = 10;
//Bar essentials
private double max; //highest range of bar
private double fill = width; //sets filled in portion
private double tick; //calculates movement per event
private Color urgent = Color.BLUE; // Changes the color depending on the Urgency
//Constructors
public myPanel()
{
this.setBackground( Color.WHITE );
repaint();
}
//Mutators ( tick manipulation )
public void setMax( double maxIn )
{
this.max = maxIn;
System.out.println("Max: " + this.max );
this.tick = (double)width / this.max;
System.out.println("tick: " + this.tick );
}
//Methods
//Tick Manipulation
public void tock()
{
//Ends when zero
if( fill < 1 )
{
fill = width;
finished = true;
tick = 0;
urgent = Color.BLUE;
repaint();
}
else
{
fill -= tick ;
System.out.println("fill is " + fill );
repaint();
}
}
//Paint method
public void paint( Graphics g)
{
super.paint(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor( urgent );
g2.draw(new RoundRectangle2D.Double(x,y + 40, width, height, arcSize, arcSize) );
g2.fill(new RoundRectangle2D.Double(x,y + 40, fill , height, arcSize, arcSize) );
}
}
public static void main(String[] args)
{
plaything pt = new plaything();
pt.setVisible(true);
}
}
My real only concern is where is my logic flawed concerning the progression of the bars and the labels. I hope to find how to make both reach zero together. (two days of research and work on just the bars alone)
Again thank you for your time.
You're calling tock() twice every iteration of your Timer:
for(myPanel m : mp)
{
m.tock(); // ONCE
}
for(short x = 0; x < 3; x++ )
{
mp[x].tock(); // TWICE
jl[x].setText( "" + --tim[x] );
}
You should remove one call, or the other.
Related
I posted this question a bit earlier and was told to make it SSCCE so here goes (if I can make any improvements feel free to let me know):
I'm wondering why when my button "confirm" is clicked the old squares disappear and the redrawn squares do not appear on my GUI (made with swing). The Squares class draws 200 spaced out squares with an ID (0, 1, 2, or 3 as String) inside obtained from a different class (for the purpose of this question, let's assume it is always 0 and not include that class). For clarification: Squares draws everything perfectly the first time (also retrieves the correct IDs), but I want it to redraw everything once the button is clicked with new IDs.
Code for Squares:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.ArrayList;
public class Squares extends JPanel{
private ArrayList<Rectangle> squares = new ArrayList<Rectangle>();
private String stringID = "0";
public void addSquare(int x, int y, int width, int height, int ID) {
Rectangle rect = new Rectangle(x, y, width, height);
squares.add(rect);
stringID = Integer.toString(ID);
if(ID == 0){
stringID = "";
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
FontMetrics fm = g2.getFontMetrics();
int fontAscent = fm.getAscent();
g2.setClip(new Rectangle(0,0,Integer.MAX_VALUE,Integer.MAX_VALUE));
for (Rectangle rect : squares) {
g2.drawString(stringID, rect.x + 7, rect.y + 2 + fontAscent);
g2.draw(rect);
}
}
}
Code for GUI:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GUIReserver extends JFrame implements Runnable{
private int myID;
private JButton confirm = new JButton("Check Availability and Confirm Reservation");
private JFrame GUI = new JFrame();
private Squares square;
public GUIReserver(int i) {
this.myID = i;
}
#Override
public void run() {
int rows = 50;
int seatsInRow = 4;
confirm.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
GUI.getContentPane().remove(square);
square = new Squares();
int spaceNum = 0;
int rowNum = 0;
int offsetX = 200;
int offsetY = 0;
for(int i = 0; i < rows * seatsInRow; i++){
square.addSquare(rowNum * 31 + offsetX,spaceNum * 21 + 50 + offsetY,20,20, 0); //normally the 4th parameter here would retrieve the ID from the main class
rowNum++;
if(rowNum == 10){
rowNum = 0;
spaceNum++;
}
if(spaceNum == 2){
spaceNum = 3;
rowNum = 0;
}
if(spaceNum == 5){
spaceNum = 0;
offsetY += 140;
}
}
GUI.getContentPane().add(square); //this does not show up at all (could be that it wasn't drawn, could be that it is out of view etc...)
GUI.repaint(); //the line in question
}
});
GUI.setLayout(new FlowLayout());
GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GUI.setLocation(0,0);
GUI.setExtendedState(JFrame.MAXIMIZED_BOTH);
square = new Squares();
int spaceNum = 0;
int rowNum = 0;
int offsetX = 200;
int offsetY = 0;
for(int i = 0; i < rows * seatsInRow; i++){
square.addSquare(rowNum * 31 + offsetX,spaceNum * 21 + 50 + offsetY,20,20, 0); //normally the 4th parameter here would retrieve the ID from the main class
rowNum++;
if(rowNum == 10){
rowNum = 0;
spaceNum++;
}
if(spaceNum == 2){
spaceNum = 3;
rowNum = 0;
}
if(spaceNum == 5){
spaceNum = 0;
offsetY += 140;
}
}
GUI.getContentPane().add(square); //this shows up the way I wish
GUI.add(confirm);
GUI.pack();
GUI.setVisible(true);
}
}
Code for main:
public class AircraftSeatReservation {
static AircraftSeatReservation me = new AircraftSeatReservation();
private final int rows = 50;
private final int seatsInRow = 4;
private int seatsAvailable = rows * seatsInRow;
private Thread t3;
public static void main(String[] args) {
GUIReserver GR1 = new GUIReserver(3);
me.t3 = new Thread(GR1);
me.t3.start();
}
}
One major problem: Your Squares JPanels preferred size is only 20 by 20, and will likely actually be that size since it seems to be added to a FlowLayout-using container. Next you seem to be drawing at locations that are well beyond the bounds of this component, and so the drawings likely will never be seen. Consider allowing your Squares objects to be larger, and make sure to only draw within the bounds of this component.
Note also there is code that doesn't make sense, including:
private int myID;
private JTextField row, column, instru draft saved // ???
package question2;ction1, instruction2, seatLabel, rowLabel; // ???
I'm guessing that it's
private int myID;
private JTextField row, column, instruction1, instruction2, seatLabel, rowLabel;
And this won't compile for us:
int rows = AircraftSeatReservation.getRows();
int seatsInRow = AircraftSeatReservation.getSeatsInRow(); // and shouldn't this take an int row parameter?
since we don't have your AircraftSeatReservation class (hopefully you don't really have static methods in that class).
And we can't compile or run your current code. We don't want to see your whole program, but rather you should condense your code into the smallest bit that still compiles, has no extra code that's not relevant to your problem, but still demonstrates your problem. So as Andrew Thompson recommends, for better help, please create and post your Minimal, Complete, and Verifiable example or Short, Self Contained, Correct Example.
I would try to OOP-ify your problem as much as possible, to allow you to divide and conquer. This could involve:
Creating a SeatClass enum, one with possibly two elements, FIRST and COACH.
Creating a non-GUI Seat class, one with several fields including possibly: int row, char seat ( such as A, B, C, D, E, F), a SeatClass field to see if it is a first class seat or coach, and a boolean reserved field that is only true if the seat is reserved.
This class would also have a getId() method that returns a String concatenation of the row number and the seat char.
Creating a non-GUI Airplane class, one that holds two arrays of Seats, one for SeatClass.FIRST or first-class seats, and one for SeatClass.COACH.
It would also have a row count field and a seat count (column count) field.
After creating all these, then work on your GUI classes.
I'd create a GUI class for Seats, perhaps GuiSeat, have it contain a Seat object, perhaps have it extend JPanel, allow it to display its own id String that it gets from its contained Seat object, have it override getBackground(...) so that it's color will depend on whether the seat is reserved or not.
etc.....
So I'm trying to map the pixel on the rgbMap to one on the depthMap so I can get the depth from a color tracked object.
I've noticed the depth map is smaller than the rgb map in addition to the different POV from being on a different spot on the kinect itself.
Is there an efficient way to do this that I'm unaware of? Currently I'm thinking of trying to line up the example pixels and then try to figure out an equation for the offset as you get farther away.
Code below, please not that the color tracking is far from done, and that I'm using mouse pressed for testing the pixel position.
/**
* ControlP5 Controlframe
* with controlP5 2.0 all java.awt dependencies have been removed
* as a consequence the option to display controllers in a separate
* window had to be removed as well.
* this example shows you how to create a java.awt.frame and use controlP5
*
* by Andreas Schlegel, 2012
* www.sojamo.de/libraries/controlp5
*
*/
import java.awt.Frame;
import java.awt.BorderLayout;
import controlP5.*;
import SimpleOpenNI.*;
private ControlP5 cp5;
ControlFrame cf;
SimpleOpenNI context;
Ktracker p,o,b;
float rx,ry,dx,dy;
int def;
void setup() {
size((2 * 640),480);
cp5 = new ControlP5(this);
o = new Ktracker(188,57,49);
// by calling function addControlFrame() a
// new frame is created and an instance of class
// ControlFrame is instanziated.
cf = addControlFrame("Output", 640,480);
// add Controllers to the 'extra' Frame inside
// the ControlFrame class setup() method below.
context = new SimpleOpenNI(this);
context.enableRGB();
context.enableDepth();
smooth();
rx=context.rgbWidth()/2;
ry=height/2;
}
void draw() {
context.update();
background(0,150,0);
image(context.depthImage(),context.rgbWidth(),0);
image(context.rgbImage(), 0,0);
int[] dm = context.depthMap();
o.run();
rectMode(CENTER);
noStroke();
fill(255,255,0);
rect(rx,ry,5,5);
dx=rx;
dy=ry;
fill(0,255,255);
rect(dx+context.rgbWidth(),dy,5,5);
rectMode(CORNER);
if(o.wr<10){
fill(0,0,255);
noStroke();
ellipse(o.currentPoints[0]+context.rgbWidth(),o.currentPoints[1],10,10);
cf.z = dm[int(o.currentPoints[0]*o.currentPoints[1])];
} else {
cf.z=0;
}
}
void mousePressed(){
rx=mouseX;
ry=mouseY;
}
ControlFrame addControlFrame(String theName, int theWidth, int theHeight) {
Frame f = new Frame(theName);
ControlFrame p = new ControlFrame(this, theWidth, theHeight);
f.add(p);
p.init();
f.setTitle(theName);
f.setSize(p.w, p.h);
f.setLocation(100, 100);
f.setResizable(false);
f.setVisible(true);
return p;
}
// the ControlFrame class extends PApplet, so we
// are creating a new processing applet inside a
// new frame with a controlP5 object loaded
public class ControlFrame extends PApplet {
int w, h;
float z;
int abc = 100;
public void setup() {
size(w, h, P3D);
frameRate(25);
z=0;
}
public void draw() {
background(abc);
translate(width/2,height/2,z/100);
sphere(250);
}
private ControlFrame() {
}
public ControlFrame(Object theParent, int theWidth, int theHeight) {
parent = theParent;
w = theWidth;
h = theHeight;
}
public ControlP5 control() {
return cp5;
}
ControlP5 cp5;
Object parent;
}
class Ktracker{
float mx,my,wr;
// A variable for the color we are searching for.
color trackColor;
float[] currentPoints, prevPoints;
Ktracker(int r,int g, int b){
trackColor = color(r,g,b);
currentPoints = new float[2];
prevPoints = new float[2];
prevPoints[0]=0;
prevPoints[1]=0;
}
void run(){
loadPixels();
// Before we begin searching, the "world record" for closest color is set to a high number that is easy for the first pixel to beat.
float worldRecord = 500;
// XY coordinate of closest color
int closestX = 0;
int closestY = 0;
// Begin loop to walk through every pixel
for (int x = 0; x < width/2; x ++ ) {
for (int y = 0; y < height; y ++ ) {
int loc = x + y*width;
// What is current color
color currentColor = pixels[loc];
float r1 = red(currentColor);
float g1 = green(currentColor);
float b1 = blue(currentColor);
float r2 = red(trackColor);
float g2 = green(trackColor);
float b2 = blue(trackColor);
// Using euclidean distance to compare colors
float d = dist(r1,g1,b1,r2,g2,b2); // We are using the dist( ) function to compare the current color with the color we are tracking.
// If current color is more similar to tracked color than
// closest color, save current location and current difference
if (d < worldRecord) {
worldRecord = d;
closestX = x;
closestY = y;
currentPoints[0] = closestX;
currentPoints[1] = closestY;
}
}
}
wr=worldRecord;
// We only consider the color found if its color distance is less than 10.
// This threshold of 10 is arbitrary and you can adjust this number depending on how accurate you require the tracking to be.
if (worldRecord < 10) {
// Draw a circle at the tracked pixel
fill(255,0,0);
//strokeWeight(4.0);
stroke(0,0);
ellipse(currentPoints[0],currentPoints[1],16,16);
}
println("wr: "+wr);
println("worldRecord: "+worldRecord);
}
}
If you want to align the depth map with the RGB map you need to simply tell OpenNI to do so fo you in setup:
context.alternativeViewPointDepthToImage();
Have a look at the AlternativeViewpoint3d sketch in Examples > SimpleOpenNI > OpenNI
OpenNI has the registration done already so all you need to do is enable it when you need it.
I wrote a program to play Maxwell's Demon. It should have a window with 2 sides and a few
dots running around bouncing off the walls. There's a wall in the middle. When you click a
button, a gap opens up in the wall (until you unclick). This should allow a person to try
to get more balls on one side than the other. You can display the count on each side.
This is the main class, I have two other classes one is Dot ( where I make my dots move, and
tell how fast), and the other one is BLueDot(where i create the blue dots).
So what I want is that to display the counts of the balls on each sides? Or How many we
got (balls) on each side of the walls?
Main Program
package dotChaser;
//DotChaser.java
//This program does some simple animation where a dot move around
//the blue dots.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DotChaser extends JFrame implements ActionListener, KeyListener
{
javax.swing.Timer time; // generates ticks that drive the animation
protected double deltaT = 0.020; // how much time for each tick
BlueDot[] blues; // holds the blue dots
int blueCounter = 0; // number of blue dots
//Label howMany = new Label();
JTextField tf;// The text field for the key listener
boolean open; // open= true part. pass through, open = false part. dont pass through
public static void main(String[] args)
{
DotChaser d = new DotChaser();
}
// constructor
public DotChaser()
{
Dot.theDotChaser = this;
//time managment
time = new javax.swing.Timer((int)(1000*deltaT), this);
time.start();
blues= new BlueDot[200] ;
tf = new JTextField("---------------");
add(tf);
tf.addKeyListener(this);
for(int i = 0; i<20; i++)
{blues[blueCounter++] = new BlueDot();
//count++;
//howMany.setText(ballReport());
setLayout( new FlowLayout());
setTitle("Dot Chaser!");
setSize(new Dimension(600,600));
setVisible(true);}
}
// the work its doing
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==time){doTime();}
repaint();
}
// key listener mouse motion
public void keyTyped( KeyEvent k ) { }
public void keyPressed( KeyEvent k )
{
System.out.println("you pressed key="+k.getKeyChar());
open=true;
}
public void keyReleased( KeyEvent k )
{
System.out.println("you released key="+k.getKeyChar());
open=false;
}
// the clock ticked, so tell all the dots to move a little
public void doTime()
{
for (int i= 0; i<blueCounter; i++)
{
blues[i].move(deltaT);
}
}
// make another blue dot (and add it to the blues array)
public void doMoreDots()
{blues[blueCounter++] = new BlueDot();}
// paint all the dots
public void paint(Graphics g)
{
super.paint(g);
for (int i= 0; i<blueCounter; i++)
{
blues[i].drawMe(g);
}
{
// draw the wall
g.setColor( Color.pink );
g.fillRect( 250, 40, 90, 200 );
g.fillRect( 250, 400, 90, 300 );
}
// close wall when false
if ( open == false)
{
g.fillRect(250, 200, 90, 200);
g.fillRect(250, 400, 90, 300);
}
}
}
As I am getting you need to count the total number of dots each side.
The total number of dots you can get from the Array where you are keeping.Add a counter in the below method which will keep the number of dots total.
static int count=0;
public void doMoreDots()
{
blues[blueCounter++] = new BlueDot();
count++;
}
Now ,you need to find out the count for each side,here I will suggest that use another 2 separate counter in that class where you can track moving dots.
Hope it will help you.
So basically I have my main code (TuringSimLS.java) and my animation code (Animation.java)
Animation.java creates a number of boxes (dependent on the length of an array in my TuringSimLS.java. The length of this array does not change). Now there is a variable in my TuringSimLS.java which has a variable pointer (this one changes). This pointer decides which box in my animation is in the middle. For example if there are 7 boxes, and the pointer is 6, the box in the middle will have one box to it's right and five to it's left (making it the 6th of boxes). When the pointer changes all the boxes move until the required box is in the middle. The problem is that my method (which changes the value of pointer) finishes running and then my animation starts. So no animation ends up happening (as the pointer's value returns to the value it initially was in the beginning). I need my animation to happen as soon as the variable pointer's value changes.
Part of my main code (TuringSimLS.java)
public static int[] POINTER = new int[1]; // My global variable. How i tell my Animation.java
// What the current value of pointer is
static String[] processTape(String[][] Quints, String[] Tape, int TapeInitial) {
int pointer = TapeInitial;
POINTER[0] = pointer;
...
...
Animation.main(Quints, Tape, TapeInitial); // <- animation started here
while (!currentDir.equals("H")) { // <- IMPORTANT WHILE LOOP as mentioned below
for (String[] Quint : Quints) {
if (Quint[0].equals(currentState) && Quint[1].equals(Tape[pointer])) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(TuringSimLS.class.getName()).log(Level.SEVERE, null, ex);
}
Tape[pointer] = Quint[3];
...
...
if (currentDir.equals("R")) {pointer += 1;} // pointer changes here
if (currentDir.equals("L")) {pointer -= 1;}
symbolFound = true;
startFound = true;
POINTER[0] = pointer;
//Here is where i want the animation to start as in
//moving of the already drawn boxes
//System.out.println(POINTER[0]);
break;
}
}
}
return Tape;
}
Here is my Animition.java:
package turingsimls;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.*; // Imports ActionEvent, ActionListener
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Animation extends JPanel implements ActionListener
{
Timer tm = new Timer(5, this);
int x = 0;
int xtri = 300;
int ytri = 30;
public static int[] C = new int[1];
public static int[] Number = new int[1];
public static int[] POINTER2 = new int[1];
public void paintComponent(Graphics g) {
super.paintComponent(g); //9
g.setColor(Color.WHITE);
for (int i = 0; i < Number[0]; i++)
g.fillRect((280 + (40 + 20)*i) + C[0], 50, 40, 30);
int xpoly[] = {xtri , xtri + 10, xtri - 10 };
int ypoly[] = {ytri, ytri - 10, ytri - 10};
g.drawPolygon(xpoly, ypoly, xpoly.length);
tm.start();
}
public void actionPerformed (ActionEvent e) {
//Here C changes according to the pointer
//Which in turn changes the XPos of the rectangles
if (!(C[0] == -60 * TuringSimLS.POINTER[0])){
if ((C[0] < -60 * TuringSimLS.POINTER[0]))
C[0] += 10;
if ((C[0] > -60 * TuringSimLS.POINTER[0]))
C[0] -= 10;
}
System.out.println(C[0]);
System.out.println(TuringSimLS.POINTER[0]);
repaint();
}
public static void main(String[][] Quints, String[] Tape, int TapeInitial) {
Animation t = new Animation(); //2
JFrame jf = new JFrame();
jf.setTitle("Animation");
jf.setSize(600, 400);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(t);
Number[0] = Tape.length - 1;
C[0] = -60 * TapeInitial;
}
}
processTape() starts the animation and produces the first rectangles correctly. The problem is the entire "Important while loop" runs before actionPerformed() runs for the second time. So the animation doesnt process the changes of pointer.
In the effort to learn more about applets and Java, I am experimenting making wave applets by drawing lines (drawLine) and making animated line graphs.
I can make a static graph just fine. However I am struggling with the animated aspect of the graph: the axes of the graph should move from left to right, increasing and growing larger than 0.
My problem is translating my needs into a solution. Can anyone give me any pointers with my problem?
I have a multidimensional array indexed by points containing the x and y of a particular point. I have tried modifying my render function to decrease the Xs to make it appear as if it is moving left but this doesn't work right.
What approach am I looking to take? How different will my approach be if the values of Y could change due to user action or added data?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
/**
* A graph that should in the future represent a wave according to my inputs
*
* #authorImprofane
* #version 1
*/
public class Graph extends JFrame
{
private InnerGraph inner;
private int width;
private Random RNG;
private int height;
private int[][] series;
private int xoffset;
int prevx = 0;
int prevy = 0;
/**
* Constructor for objects of class Graph
*/
public Graph(int width, int height) throws InterruptedException
{
RNG = new Random();
setTitle(" Graph");
series = new int[width][2];
this.width = width;
this.height = height;
inner = new InnerGraph(width, height);
add(inner, BorderLayout.CENTER);
setVisible(true);
inner.preparePaint();
pack();
updateGraph();
}
public static void main(String[] args) throws InterruptedException
{
new Graph(300, 300);
}
public void updateGraph() throws InterruptedException
{
// virtual x is how far along on the x axis we are, I ignore the 'real' X axis
int vx = 0;
int point = 0;
int xdecay = 0;
int inc = 5;
// how many times we need to plot a point
int points = (int) java.lang.Math.floor( width / inc );
System.out.println(points);
inner.preparePaint();
// draw all points to graph
// make some junk data, a saw like graph
for (vx = 0 ; vx < points ; vx++) {
series[vx] = new int[] { vx*inc, ( (vx*inc) % 120 ) };
}
Thread.sleep(150);
int n = 5;
while(n > 0) {
System.out.println(xdecay);
inner.preparePaint();
for (vx = 0 ; vx < points ; vx++) {
inner.updateSeries(vx, xdecay);
inner.repaint();
Thread.sleep(50);
}
xdecay += inc;
// shift the data points to the left
int[][] nseries = new int[points][2];
// System.arraycopy(series, 1, nseries, 0, points-1);
n--;
}
}
public class InnerGraph extends JPanel
{
private Graphics g;
private Image img;
private int gwidth;
private int gheight;
Dimension size;
public InnerGraph(int width, int height)
{
gwidth = width;
gheight = height;
size = new Dimension(1, 1);
}
/**
* Try make panel the requested size.
*/
public Dimension getPreferredSize()
{
return new Dimension(gwidth, gheight);
}
/**
* Create an image and graphics context
*
*/
public void preparePaint()
{
size = getSize();
img = inner.createImage( (size.width | gwidth), (size.height | gheight) );
g = img.getGraphics();
}
/**
* Draw a point to the chart given the point to use and the decay.
* Yes this is bad coding style until I work out the mathematics needed
* to do what I want.
*/
public void updateSeries(int point, int decay)
{
g.setColor(Color.blue);
int nx = series[point][0];
series[point][0] -= decay;
if ( point-1 >= 0 ) {
series[point-1][0] -= decay;
}
int ny = series[point][1];
prevx -= decay;
g.drawLine(prevx-decay, prevy, nx-decay, ny );
prevx = nx-decay;
prevy = ny;
}
public void paintComponent(Graphics g)
{
g.drawImage(img, 0, 0, null);
}
}
}
First, it looks like you are subtracting the decay too often in the updateSeries method.
Below is a new version of that method.
public void updateSeries(int point, int decay)
{
g.setColor(Color.blue);
int nx = series[point][0];
series[point][0] -= decay;
if ( point-1 >= 0 ) {
series[point-1][0] -= decay;
}
int ny = series[point][1];
// prevx -= decay;
// g.drawLine(prevx-decay, prevy, nx-decay, ny );
g.drawLine(prevx, prevy, nx-decay, ny );
prevx = nx-decay;
prevy = ny;
}
With those changes, the lines draw better, but they draw so slowly that the animation is hard to see. You probably need to build a new graphics and swap the whole thing so that you don't have to watch each individual line segment being drawn.
For a starter you could check out the following example (and the ones related to this)
Scroll Chart #java2s.com