tags:

views:

777

answers:

4

I'm looking for a place to hook some code to programmatically create, size and position a JPanel after the application has finished loading.

I'm just starting with Java. I'm using NetBeans 6.5.1 with jdk1.6.0_13. I've used the new project wizard to create a basic Java/Swing desktop application. This is a SingleFrameApplication that uses a FrameView with a central main JPanel where all the UI elements are placed.

I first tried my code in the FrameView constructor but when I try to arrange my JPanel based on the bounding rectangle of one of the design time controls I added to the UI, that control has not yet finished being positioned and sized so I'm getting all zeros for the coordinates.

I've verified my code works as expected by calling it from a click event after the application has loaded so my problem is finding a way to know when everything is finished being sized and arranged.

I also tried the componentShown event from the main JPanel but I later read that is only fired if setVisible is explicitly called which apparently doesn't happen during normal application startup.

Can anyone provide some pointers? Thanks.

Update:

In addition to what I mention in my answer below, I also read about the Application.ready() method. This would also be a point in time of interest for knowing when the UI part of an application is finished doing everything it needs to do. Communicating to my view from the application seemed a bit messy though.

+3  A: 

I think you want WindowActivated. Have a look at this part of the tutorial.

Charlie Martin
windowActivated seems to be a method of a frame or Dialog. I have access to a SingleFrameApplication, a FrameView and the main JPanel. None of those are a frame or Dialog.
Arnold Spence
+1: I was able to eventually figure out how to get at the windowActivated event. Thanks.
Arnold Spence
+1  A: 

I'd try using getFrame().isValid()

JRL
That sounds good but if I knew where to call it from to have it return true, I'd know where to put my code :)
Arnold Spence
You could have a separate task that runs the method until it returns true, and then do your resizing. You can start the task from within your FrameView constructor.
JRL
+1: getFame() was the key to getting at the JFrame I needed in order to hook into the windowActivated event, thanks.
Arnold Spence
+1  A: 

I assume this is the WYSIWYG editor thing. I'm looking at NetBeans 6.1, so your experiences may vary.

The traditional way to layout Swing components is by using a LayoutManager (or LayoutManager2). According to the NetBeans help, the visual editor supports these so long as they don't require support for constraints.

The procedure goes something like this:

  1. Create a new JavaBean and have it implement LayoutManager (a BeanInfo is required too for palette support - you can create one by right-clicking the bean class)
  2. Build the project
  3. Right-click the bean and choose Tools > Add to Palette... and add it
  4. Right-click the panel for which you want to set the layout and select Set Layout > Your Bean Name

You may find the design-time experience somewhat lacking.

A sample layout implementation:

public class StepLayoutBean extends Object implements Serializable, LayoutManager {

    public void addLayoutComponent(String name, Component component) {
    }

    public void layoutContainer(Container container) {
        Dimension space = container.getSize();
        int xoffset = 0;
        int yoffset = 0;
        for (Component kid : container.getComponents()) {
            Dimension prefSize = kid.getPreferredSize();
            if (prefSize.width + xoffset > space.width) {
                xoffset = 0;
            }
            Rectangle bounds = new Rectangle(xoffset, yoffset, prefSize.width, prefSize.height);
            kid.setBounds(bounds);
            xoffset += prefSize.width;
            yoffset += prefSize.height;
        }
    }

    public Dimension minimumLayoutSize(Container container) {
        Dimension size = new Dimension();
        for (Component kid : container.getComponents()) {
            Dimension minSize = kid.getMinimumSize();
            size.width = minSize.width > size.width ? minSize.width : size.width;
            size.height += minSize.height;
        }
        return size;
    }

    public Dimension preferredLayoutSize(Container container) {
        Dimension size = new Dimension();
        for (Component kid : container.getComponents()) {
            Dimension prefSize = kid.getPreferredSize();
            size.width += prefSize.width;
            size.height += prefSize.height;
        }
        return size;
    }

    public void removeLayoutComponent(Component component) {
    }
}

If a custom layout doesn't fit the bill, have a look at the event bindings under the component's properties panel - though resizing that way might be a recipe for some kind of recursive event storm.

McDowell
+1: I'm certain in the end, this is the way to go. I was really interested in understanding the life cycle of the application framework too. Thanks.
Arnold Spence
+1  A: 

The solution I went with was actually a combination of the answers from Charles Marin and JRL (I upvoted both of your answers for credit, thanks).

I had my FrameView class implement WindowListener.

...
public class MyView extends FrameView implements WindowListener
...

and in my FrameView constructor I added a listener to the application's main frame.

...
getFrame().addWindowListener((WindowListener) this);
...

Then in my implementation of windowActivated I could call the code I had to arrange and size a control on the main JPanel based on the location and size of other controls.

public void windowActivated(WindowEvent e)
{
    // The application should now be finished doing its startup stuff.
    // Position and size a control based on other UI controls here
}
Arnold Spence