views:

128

answers:

2

Here's my JFrame code:

public static void main(String[] args) {
    JFrame jf = new JFrame();
    jf.setSize(600,600);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    MyCustomWidget widget = MyCustomWidget.createWidget(400, 400);
    widget.setVisible(true);
    // just to set x and y
    widget.setLocation(40, 40);

    jf.getContentPane().add(widget);
    jf.setVisible(true);
}

and here's the code for MyCustomWidget:

public class MyCustomWidget extends JComponent {

    public void paint(Graphics g)
    {
        super.paint(g);
    }

    public static MyCustomWidget createWidget(int width,int height)
    {
        MyCustomWidget tw = new MyCustomWidget();
        tw.setBounds(0,0,width,height);
        tw.setBackground(Color.RED);
        return tw;
    }
}

the thing is, the JComponent is not shown in the window, and I don't understand why. I even added a widget.setVisible(true) just to make sure it is visible. Nothing works. Can you spot what I'm doing wrong?

After the modifications you guys suggested, the code now is:

package javaapplication2;

public class Main {

    public static void main(String[] args) throws IOException {

        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                JFrame jf = new JFrame();
                jf.setSize(600,600);
                jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                jf.setLayout(null);

                JComponent container = (JComponent) jf.getContentPane();
                container.setDebugGraphicsOptions(DebugGraphics.FLASH_OPTION);
                DebugGraphics.setFlashColor(Color.RED);
                DebugGraphics.setFlashCount(2);
                DebugGraphics.setFlashTime(100);

                MyCustomWidget widget = MyCustomWidget.createTimeline(400, 400);

                container.add(widget);
                jf.setVisible(true);
            }

        });


    }

}

and:

public class MyCustomWidget extends JComponent {

    public void paintComponent(Graphics g)
    {
        setForeground(Color.BLACK);
        drawLines(g);
    }

    // a little something to see that something is drawed
    private void drawLines(Graphics g)
    {
        int distanceBetween = getHeight() / numberOfLines;
        int start = 0;
        int colourIndex = 0;
        Color colours[] = {Color.BLUE,Color.WHITE,Color.YELLOW};

        for(int i = 0;i < distanceBetween;start+=distanceBetween,i++)
        {
            g.setColor(colours[colourIndex]);
            g.drawLine(0,start,40,40);
            colourIndex %= colours.length;
        }
    }

    private int numberOfLines = 4;

    public MyCustomWidget()
    {
        setOpaque(true);
    }

    public static MyCustomWidget createTimeline(int width,int height)
    {
        MyCustomWidget tw = new TimelineWidget();
        tw.setBounds(0,0,width,height);
        return tw;
    }
}
+2  A: 

Here is what happens here :

  • Default layout of your JFrame's content pane is BorderLayout. This means your component is resized to the whole size of content pane. To fix this anywhere before adding your component do
 jf.getContentPane().setLayout(null);
  • Background is not drawn automatically in direct descendants of JComponent. You can either make your component opaque (setOpaque(true)), extend from JPanel or override paintComponent method like this
 public void paintComponent (Graphics g) {
    super.paintComponent (g);
    g.setColor(getBackground());
    g.drawRect(0, 0, getWidth(), getHeight());
 }

EDIT:

To comply with Swing threading rules the code in main method should run on EDT thread. That mean it has to be wrapped into

SwingUtilities.invokeLater(new Runnable() {
     public void run() {
         // your code goes here
     } 
}
eugener
This kind of seems to work ... but, sometimes when I run the JFrame nothing is displayed, and other times, the widget's displayed correctly. I'm developing on Kubuntu 9.04, and using:java version "1.6.0_0"/OpenJDK Runtime Environment (IcedTea6 1.6.1) (6b16-1.6.1-3ubuntu1)/OpenJDK Client VM (build 14.0-b16, mixed mode, sharing)
Geo
The code in your main method should be wrapped into SwingUtilities.invokeLater to comply with Swing threading rules
eugener
It is in `invokeLater`, but sometimes it still won't show.
Geo
Either call super.paintComponent or use setOpaque(true) instead of overriding paintComponent
eugener
I tried both of them. Still 9 out of 10 runs don't display anything. Also, when nothing gets displayed the JFrame kind of freezes, as in I can't stop it unless I explicitly kill the process. I'm lost.
Geo
It has to do with you using DebugGraphics. When I remove 4 lines related to DebugGraphics everything works fine ALL the time.
eugener
+2  A: 

By default JComponents are not opaque, so your background never gets painted. A call to setOpaque(true) should do the trick.

2 comments on your code:

  1. if you are going to write custom painting code, override paintComponent(), not paint()
  2. Any changes to UI components must be made on the EventDispatchThread (EDT) failing to do this will result in generally bad things ranging from inconsistent behavior to a full crash. So, in your main you need to wrap your code in an invokeLater:

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            // your code goes here
        }
    }
    
Devon_C_Miller