Byte Me
Byte Me

Reputation: 27

Adding two components from the same class in a JFrame

So for some homework I have to create a bar chart that represents balances. Just to get familiar with graphics/components I just want to start of by placing two boxes on the screen. It seems the first box is 'drawn' then the second box just overwrites it? Here are the two classes.

Main Class - BalanceChart.java

package balancechart;

import javax.swing.*;

public class BalanceChart {

Double[] Props = new Double[6];

public static void main(String[] args) {
   JFrame f = new JFrame("Balance Chart");
   f.setSize(500, 500);
   f.setDefaultCloseOperation(
   JFrame.EXIT_ON_CLOSE);
   ChartComponent ccOne = new ChartComponent(50, 50, 100, 200);
   ChartComponent ccTwo = new ChartComponent(10, 10, 10, 10);
   f.add(ccOne);
   f.add(ccTwo);
   f.setVisible(true);
}

private void getProps(){
    //ignore
}

}

Component class - ChartComponent.java

package balancechart;

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

public class ChartComponent 
extends JComponent {

private int x, y, w, h;

public ChartComponent(int x, int y, int w, int h){
  this.x = x;
  this.y = y;
  this.w = w;
  this.h = h;
}

public void paintComponent(Graphics g){
  Graphics2D g2 = (Graphics2D) g.create();
  g2.setColor(Color.RED);
  g2.fillRect(w, h, x, y);
}

}

I guess it has something to do with the 2 add procedures I have for the JFrame, I'm just not sure how to go about it.

Thanks in advance

Upvotes: 2

Views: 1580

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285403

You need to run, not walk, to the nearest layout manager tutorial. There you'll find out that a JFrame's contentPane uses BorderLayout by default and that when you add a component to a BorderLayout-using container without additional constants, it is added by default to the BorderLayout.CENTER position, covering anything added previously.

A solution is to create another JPanel that uses a layout of choice, perhaps even just leaving it with JPanel's default FlowLayout, adding your components to it, and then adding that JPanel to the JFrame.

i.e.,

ChartComponent ccOne = new ChartComponent(50, 50, 100, 200);
ChartComponent ccTwo = new ChartComponent(10, 10, 10, 10);
JPanel container = new JPanel(); // JPanel uses FlowLayout by default
container.add(ccOne);
container.add(ccTwo);
f.add(container, BorderLayout.CENTER); // just to be clear
f.pack();
f.setVisible(true);

Please check out this tutorial link: Laying Out Components Within a Container


Edit
As MadProgrammer points out, you've another problem here:

public void paintComponent(Graphics g){
  Graphics2D g2 = (Graphics2D) g.create();
  g2.setColor(Color.RED);
  g2.fillRect(w, h, x, y);
}

in that you don't call the super method, and so old images won't be cleared when needed, and this will matter greatly if you try to do some animation say by changing your w, h, x, or y in a Swing Timer. To solve this, be sure to call the super's method. Also, paintComponent should be protected not public, and you should use the @Override annotation to be sure that you're correctly overriding the method. And if you absolutely need to create a new Graphics context, then you should dispose of it when done so as not to run out of resources. Do not dispose of a Graphics context given to you by the JVM (such as the one passed into your paintComponent(...) method's parameter, as that can have unwanted side effects:

@Override
protected void paintComponent(Graphics g){
  super.paintComponent(g);
  Graphics2D g2 = (Graphics2D) g.create();
  g2.setColor(Color.RED);
  g2.fillRect(w, h, x, y);
  g2.dispose(); // only do this if you create your own Graphics context
}

Edit 2
Also, you should get in the habit of trying not to set the sizes of anything, but instead letting the GUI's components and layout managers set their own size when asked to do so as this will lead to a more pleasing and flexible GUI program.


Edit 3
You state in comment:

I fixed up the code but I don't seem to have the 2 red squares appear anywhere and the window starts up in a really small size. I still have a lot of learning to do and I can't see why the added code would of done this.

Your problem is that your JComponent, the ChartComponent's default preferredSize will be either 0,0 or 1,1; I forgot which, but it doesn't matter, since in either case, the component won't be big enough to be seen. To solve this, give your class a getPreferredSize() method override that helps set its size. e.g,:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;    
import javax.swing.*;

public class BalanceChart {

   Double[] Props = new Double[6];

   public static void main(String[] args) {
      JFrame f = new JFrame("Balance Chart");
      //  f.setSize(500, 500);
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      ChartComponent ccOne = new ChartComponent(50, 50, 100, 200);
      ChartComponent ccTwo = new ChartComponent(10, 10, 10, 10);
      JPanel container = new JPanel();
      container.add(ccOne);
      container.add(ccTwo);
      f.add(container);
      f.pack();
      f.setLocationByPlatform(true);
      f.setVisible(true);
   }

   private void getProps() {
      // ignore
   }

}

class ChartComponent extends JComponent {

   private static final int PREF_W = 400;
   private static final int PREF_H = PREF_W;
   private int x, y, w, h;

   public ChartComponent(int x, int y, int w, int h) {
      this.x = x;
      this.y = y;
      this.w = w;
      this.h = h;
   }

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

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setColor(Color.RED);
      g2.fillRect(w, h, x, y);
      g2.dispose();
   }

}

Upvotes: 5

Related Questions