I am creating line graph using outputs from a thread, the threads are simulations of incoming and outgoing bill that run over a course of 52 seconds and this will be dipicted on a line graph as shown below to show the bank balance over the 52 seconds!

Currently the program runs fine, when I click start the point gets updated but every a new point is placed on the graph the previous one disappears. How i can i keep all the points on the graph.

I would assume i would have to create 2 new int variable... prevX & prevY.

enter image description here

import java.awt.*;
import javax.swing.*;

public class DrawPanel extends JPanel {

   private static final int X_AXIS_LENGTH = 700;
   private static final int Y_AXIS_LENGTH = 230; // could be changed
   private static final int X_AXIS_OFFSET = 200;
   private static final int Y_AXIS_OFFSET = 85;
   private static final int PanelHeight = 365;
   private static final int PanelWidth = 1000;

   public DrawPanel() {
      this.setBackground(Color.white);
      this.setPreferredSize(new Dimension(PanelWidth, PanelHeight));
   }

   public void paintComponent(Graphics g) {

      int y = ControlPanel.bk1.getBalance(); // balance
      int x = ControlPanel.bk1.getWeek(); // weeks //
      int prevX, prevY;
      int maxX = ContentPanel.controlPanel.getDuration();
      int maxY = 100000;

      int Xleft = 200;
      int Xright = 900;
      int Ytop = 50;
      int Ybottom = 330;// defining axis

      while (ControlPanel.bk1.getBalance() > maxY) {
         int i = maxY / 4;
         maxY = maxY + i;
      }

      Graphics2D g2 = (Graphics2D) g;
      super.paintComponent(g2);
      g2.setColor(Color.BLUE);

      BasicStroke pen = new BasicStroke(4F);
      g2.setStroke(pen);

      g2.drawLine(Xleft, Ytop, Xleft, Ybottom); // set axis
      g2.drawLine(Xleft, 280, Xright, 280);

      int i = X_AXIS_OFFSET + (X_AXIS_LENGTH / 2);
      int ii = X_AXIS_OFFSET + (X_AXIS_LENGTH / 4);
      int iii = ((X_AXIS_LENGTH / 4)) * 3 + X_AXIS_OFFSET;
      BasicStroke spaces = new BasicStroke(1F);
      g2.setStroke(spaces);
      g2.drawLine(i, 280, i, 300);
      g2.drawLine(ii, 280, ii, 300);
      g2.drawLine(iii, 280, iii, 300);

      g2.setStroke(pen);

      Font f = new Font("Serif", Font.BOLD, 14);
      g2.setFont(f);
      g2.drawString("Account Balance (£)", 35, 200);
      g2.drawString("Elapsed Time (Weeks)", 475, 340);

      g2.setColor(Color.BLACK);
      String maxXDisplay = Integer.toString(maxX);
      String maxYDisplay = Integer.toString(maxY);
      g2.drawString(maxYDisplay, 160, 45);
      g2.drawString(maxXDisplay, 900, 300);

      // retrieve values from your model for the declared variables

      // calculate the coords line on the canvas

      double balance = PanelHeight
            - ((((double) y / maxY) * Y_AXIS_LENGTH) + Y_AXIS_OFFSET);
      double weeks = (((double) x / maxX) * X_AXIS_LENGTH) + X_AXIS_OFFSET;

      int xPos = (int) Math.round(weeks);
      int yPos = (int) Math.round(balance); // changing back to int to be used
                                            // in drawing oval

      g2.setColor(Color.RED);
      g.drawOval(xPos, yPos, 2, 2);

   }

   public void reDraw() {
      repaint();
   }

}
有帮助吗?

解决方案

You appear to be only trying to plot one point in your paintComponent method:

g.drawOval(xPos, yPos, 2, 2);

Usually you'll loop through a for loop drawing all the points in this method. For example something like:

  for (int j = 0; j < maxPointCount; j++) {
     x = someMethodToGetX(j);
     y = someMethodToGetY(j);
     double balance = PanelHeight - ((((double) y / maxY) * 
           Y_AXIS_LENGTH) + Y_AXIS_OFFSET);
     double weeks = (((double) x / maxX) * X_AXIS_LENGTH) + 
           X_AXIS_OFFSET;

     int xPos = (int) Math.round(weeks);
     int yPos = (int) Math.round(balance); 

     g2.setColor(Color.RED);
     g.drawOval(xPos, yPos, 2, 2);
  }

Edit 1
Regarding your recent comment:

Tryed that for loop and it makes no difference to the program

My code above is certainly not code that can be cut and pasted into your program and be expected to work, but rather is only to be seen as an example of a concept. A for loop will work if implemented correctly as it's worked for me many times, but yours is not working, so we have to fix your implementation, and in order to do that, we need more information:

  • How are you generating your data points?
  • Are you using a Swing Timer to imitate real-time collection of data?
  • You will need to store your data points as you collect them so your paintComponent can iterate over them. How are you storing your data points? Is it in an ArrayList? Can we see that code?
  • Once we see all this, can we see the code where you try to implement a for loop to draw all the data points?

You will need to make an edit to your question to show this new information. If you do this, please notify me by commenting in this answer.

Edit 2
This is a more complete example of what I'm describing, one with a functioning for loop that draws all scaled data points. Of course none of this code can be copied and pasted into your app, but hopefully the concepts contained can be transferred. Please ask if anything looks confusing:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;

public class TestShowGraph {
   private static final int MAX_POINTS = 30;
   private static final int TIMER_DELAY = 800;

   private static void createAndShowGui() {
      ShowGraph showGraphPanel = new ShowGraph(MAX_POINTS);
      TimerListener timerListener = new TimerListener(MAX_POINTS, showGraphPanel);

      JFrame frame = new JFrame("TestShowGraph");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(showGraphPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);

      new Timer(TIMER_DELAY, timerListener).start();
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }  
}

class TimerListener implements ActionListener {
   private static final double EXP_MULTIPLIER = 0.2;

   // array of points created in constructor to hold data that
   // will eventually be displayed in real time.
   // A Swing Timer will copy a point into the pointsList above. 
   private Point2D[] initPoints;

   private int maxPoints;
   private int count = 0;
   private ShowGraph showGraph;

   public TimerListener(int maxPoints, ShowGraph showGraph) {
      initPoints = new Point2D[maxPoints];
      this.maxPoints = maxPoints;
      this.showGraph = showGraph;

      // create all data points that will eventually be 
      // graphed. This is to simulate real-time data collection
      for (int i = 0; i < initPoints.length; i++) {
         double x = (double) i / initPoints.length;
         double y = 1.0 - Math.exp(-1.0 * i * EXP_MULTIPLIER);        
         initPoints[i] = new Point2D.Double(x, y);
      }
   }

   public void actionPerformed(ActionEvent e) {
      if (count < maxPoints) {
         // simply push data from initPoints into the list that will
         // be used to draw the graph
         showGraph.addPoint(initPoints[count]);
         count++;
      } else {
         // unless we've run out of points. Then simply start over
         count = 0;
         showGraph.clearPointsList();
      }

      // repaint so that the GUI will show the points
      showGraph.repaint();
   }
}

@SuppressWarnings("serial")
class ShowGraph extends JPanel {

   private static final int PREF_W = 800;
   private static final int PREF_H = 600;
   private static final int BORDER_GAP = 50;
   private static final Color AXIS_COLOR = Color.blue;
   private static final Color POINTS_COLOR = Color.red;
   private static final Color BACKGRND_COLOR = Color.white;
   private static final Stroke AXIS_STROKE = new BasicStroke(3f);
   private static final Stroke POINTS_STROKE = new BasicStroke(2f);
   private static final double X_SCALE = PREF_W - 2 * BORDER_GAP;
   private static final double Y_SCALE = PREF_H - 2 * BORDER_GAP;
   private static final int POINT_RADIUS = 3;

   // list that the paintComponent method loops through to
   // draw points
   private List<Point2D> pointsList = new ArrayList<Point2D>();


   public ShowGraph(int maxPoints) {
      setBackground(BACKGRND_COLOR);
   }

   public void addPoint(Point2D point2d) {
      pointsList.add(point2d);
   }

   public void clearPointsList() {
      pointsList.clear();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
            RenderingHints.VALUE_ANTIALIAS_ON);
      drawAxises(g2);
      drawPoints(g2);
   }

   private void drawAxises(Graphics g2) {
      // derive a Graphics2D object from the one provided by the 
      // JVM so we can change settings on it without effecting 
      // the Graphics object provided by the JVM
      Graphics2D g2Axises = (Graphics2D) g2.create();
      g2Axises.setStroke(AXIS_STROKE);
      g2Axises.setColor(AXIS_COLOR);
      int x1XAxis = BORDER_GAP;
      int y1XAxis = PREF_H - BORDER_GAP;
      int x2XAxis = PREF_W - BORDER_GAP;
      int y2XAxis = PREF_H - BORDER_GAP;
      g2Axises.drawLine(x1XAxis, y1XAxis, x2XAxis, y2XAxis);
      int x1YAxis = BORDER_GAP;
      int y1YAxis = BORDER_GAP;
      int x2YAxis = BORDER_GAP;
      int y2YAxis = PREF_H - BORDER_GAP;
      g2Axises.drawLine(x1YAxis, y1YAxis, x2YAxis, y2YAxis);
      g2Axises.dispose(); // because we derived this we must dispose it
   }

   private void drawPoints(Graphics2D g2) {
      Graphics2D g2Points = (Graphics2D) g2.create();
      g2Points.setStroke(POINTS_STROKE);
      g2Points.setColor(POINTS_COLOR); 

      for (Point2D p : pointsList) {
         // p points hold data between 0 and 1
         // we must scale our points to fit the display
         // before displaying them
         int pX = (int)(X_SCALE * p.getX()) + BORDER_GAP;
         int pY = PREF_H - (int)(Y_SCALE * p.getY()) - BORDER_GAP;

         // displayed the scaled points
         int radius = POINT_RADIUS;
         g2Points.drawOval(pX - radius, pY - radius, 2 * radius, 2 * radius);
      }
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

}

Luck.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top