Reputation: 143
I'm programming a simple diagram, with what you can display some points on x, y axes.
public class GraphPlotter extends JPanel {
private static final long serialVersionUID = 1L;
/** Default frame size X for frame in pixels */
private final int DEFAULT_FRAME_SIZE_X = 800;
/** Default frame size Y for frame in pixels */
private final int DEFAULT_FRAME_SIZE_Y = 600;
/** Padding to Frame */
private final int PAD = 30;
/** Radius of dot */
private final int DOT_RADIUS = 3;
/** Padding of label */
private final int LABEL_PAD = 10;
/** Height of label */
private final int LABEL_HEIGHT = 10;
/** Width of label */
private final int LABEL_WIDTH = 100;
/** Max value for x to print */
private int maxValueForX;
/** Scale factor depending to y*/
private int maxValueForY;
/** Label for the x axis */
private String labelForX = "time";
/** Label for the y axis */
private String labelForY;
/**
* List with points to draw. It holds the y coordinates of points. x
* coordinates are spaced
*/
private List<Integer> dataPoints = new ArrayList<>();
/**
*
* Constructor of this class
*
*/
public GraphPlotter(ArrayList<Integer> dataPoints, String labelForY) {
this.dataPoints = dataPoints;
this.maxValueForX = dataPoints.size();
this.maxValueForY = Collections.max(dataPoints);
this.labelForY = labelForY;
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(this);
f.setSize(this.DEFAULT_FRAME_SIZE_X + PAD, this.DEFAULT_FRAME_SIZE_Y + PAD);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
/** method that draws the points and lines between the points */
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
// add labels
JLabel jLabelY = new JLabel(labelForY);
JLabel jLabelX = new JLabel(labelForX);
jLabelY.setSize(LABEL_WIDTH, LABEL_HEIGHT);
jLabelY.setLocation(LABEL_PAD, LABEL_PAD);
add(jLabelY);
jLabelX.setSize(LABEL_WIDTH, LABEL_HEIGHT);
jLabelX.setLocation(w - LABEL_WIDTH - LABEL_PAD, h - LABEL_HEIGHT - LABEL_PAD);
jLabelX.setHorizontalAlignment(SwingConstants.RIGHT);
add(jLabelX);
// add axis
g2.drawLine(PAD, PAD, PAD, h - PAD);
g2.drawLine(PAD, h - PAD, w - PAD, h - PAD);
double xScale = (w - 2 * PAD) / (dataPoints.size() + 1);
double yScale = (h - 2 * PAD) / this.maxValueForY;
int x0 = PAD;
int y0 = h - PAD;
// draw the points as small circles
g2.setPaint(Color.blue);
for (int i = 0; i < dataPoints.size(); i++) {
int x = x0 + (int) (xScale * (i + 1));
int y = y0 - (int) (yScale * dataPoints.get(i));
g2.fillOval(x - DOT_RADIUS, y - DOT_RADIUS, 2 * DOT_RADIUS,
2 * DOT_RADIUS);
}
}
/** Size of List */
private int getSizeOfDataPoints() {
return dataPoints.size();
}
/** Deletes last DataPoint in List */
private void deleteLastDataPoint() {
dataPoints.remove(0);
}
/**
* Ad point and repaint graph.
*
* @param point to draw (y-coord)
*/
public void add(int point) {
if (getSizeOfDataPoints() > this.maxValueForX) {
deleteLastDataPoint();
}
dataPoints.add(point);
this.repaint();
}
public static void main(String[] args) {
ArrayList<Integer> scores = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < 50; i++) {
scores.add(random.nextInt(10));
}
String labelForY = "throughput";
GraphPlotter graphPlotter = new GraphPlotter(scores, labelForY);
graphPlotter.add(5);
}
The labels are displayed at start of the application. If I resize the window of the application, the labels will be displayed all over the window. (see screenshots)
How can I avoid the dublication of the labels? I assume, that the program is adding the same labels in the panel, after the window is repainted. If I write
add(jLabelY);
repaint();
in the paintComponent()
method, this error occures at startup of the application.
I also tried to put the panel into a FlowLayout
, but didn't make any changes.
Upvotes: 0
Views: 136
Reputation: 2890
paintComponent()
can be called at almost arbitrary times by Swing (whenever the component needs to be redrawn; e.g. on resize). Therefore, it should usually be side-effect free. However, you use paintComponent
to add()
labels as children of your panel, which you never remove. Therefore, each time your panel gets redrawn, two labels get added to its children. super.paintComponent()
will then paint them all.
One solution to this would be to keep the two labels as fields of your panel and only update their location in paintComponent
(before calling super.paintComponent()
)
Upvotes: 2