Aaron Aaron - 5 months ago 13
Java Question

Multiple custom JComponents, only one displayed

I am trying to make a custom JComponent that can be reused over and over in my program. I have set up a simple test of what I need to do, but I can't even get that to work.

class MyComponent extends JComponent {
private String string = "";
private int x;
private int y;

public MyComponent(String string, int x, int y){
this.string = string;
this.x = x;
this.y = y;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString(string, x, y);
}

}

public class GObject {
public static void main(String[] args) {
JFrame Window = new JFrame();
Window.setBounds(30, 30, 300, 300);
Window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

MyComponent com1 = new MyComponent("test123", 100, 100);
MyComponent com2 = new MyComponent("test456", 20, 20);
Window.add(com1);
Window.add(com2);

Window.setVisible(true);
}
}


Technically what I have created is a JLabel that can be positioned anywhere. You would expect to see two string displayed, "test123" and "test456", at those coordinates. However I only see the last string displayed.

enter image description here

JFrame with only one string of text displayed.

EDIT:

Let me upload my actual code. I tried to simplify things by dumbing down my actual code.

Here is what I have:

import java.awt.Graphics;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class HeatG2 {
public static JFrame frame = new JFrame("Test");

public static void main(String[] args){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Sheet sheet = new Sheet();
frame.add(sheet);
frame.setSize(1000, 800);
frame.setVisible(true);
}

}

@SuppressWarnings("serial")
class Sheet extends JPanel{
public Heat test1;
public Heat test2;

public Sheet(){
test1 = new Heat();
test1.setPosition(10, 10);
test1.setHeat(1);
test1.setHeight(150);
add(test1);

test2 = new Heat();
test2.setPosition(10, 310);
test2.setHeat(2);
test2.setHeight(150);
add(test2);
}
}

@SuppressWarnings("serial")
class Heat extends JComponent{
private int x;
private int y;
private int height;
private int heat;
private String driver1 = "";
private String driver2 = "";

public String getDriver1(){
return driver1;
}

public String getDriver2(){
return driver2;
}

public void setDriver1(String driver1){
this.driver1 = driver1;
System.out.println(this.driver1);
}

public void setDriver2(String driver2){
this.driver2 = driver2;
System.out.println(this.driver2);
}

public void setPosition(int x, int y){
this.x = x;
this.y = y;
}

public void setHeight(int height){
this.height = height;
}

public void setHeat(int heat){
this.heat = heat;
}

public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawString(driver1, x, y);
g.drawLine(x, y, x+250, y);
g.drawLine(x+250, y, x+250, y+height);
g.drawString(driver2, x, y+height);
g.drawLine(x, y+height, x+250, y+height);
}
}


Multiple heats need to be added at specified locations on a sheet (JPanel). The Jpanel will then be added to the JWindow.

EDIT 2:

I ended up fixing this issue by not extending component. I used the class as a template for a paintable object instead.

Answer

I need to use absolute positioning because the components will eventually be added to a scroll pane

Scrolling does not work with absolute positing because the scroll pane and its related scrollbars will only work when the preferred size of the panel is greater than the size of the scroll pane. If you don't use a layout manager then you need to manage the preferred size yourself.

You need to use something like the Drag Layout which will manage the preferred size of your panel for you.

Technically what I have created is a JLabel that can be positioned anywhere.

Then technically you should be using a JLabel so you don't reinvent the wheel. Your concept of how components work is wrong. Components have a size and a location. So the custom painting will paint the text relative to (0, 0) of the component. Then you use the setLocation(...) method to position the component in the parent panel.

If you want to do custom painting then you are responsible for determining the preferred size of each component and the size will vary based on the text you specify as a parameter so you need to use FontMetrics. This is another reason to just use a JLable.