2

I have this class, let's say Foo. This class is responsible for creating/showing a JFrame, which requires heavy customization.

public class Foo{
    private static JFrame frame;

    public static void createAndShowFrame(){
        //do stuff
    }

    public static JFrame getFrame(){
        return frame;
    }
}

And I have this other class, let's say Launcher, that serves as the entry-point of the application. This class is responsible for initiating the construction of the GUI

public class Launcher{
    public static void main(String[] args){
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run(){
                Foo.createAndShowFrame();
            }
        });
    }
}

The design problem is getFrame(). This method was required because other dialogs require this as their parent frame. Unfortunately, this exposes the frame and seems to void the static-utility method.

I guess my question is, is there a more sound design approach to this? Am I making any sense? I basically wanted to create and show a frame without having to extend it.

See my Rule of Thumb question.

Community
  • 1
  • 1
mre
  • 43,520
  • 33
  • 120
  • 170

2 Answers2

1

I don't see the advantage of the use of invokeLater() (EDIT - in this case (since you call it from main() ) . If you have a heavy GUI processing to do, just do it on main thread (because you have to anyway). If most of the work can be done in background, do it in background and publish the results on the main thread. (using invokeLater()). [This part is only my opinion, not based on some docs etc...]

Finally, if you don't want to expose the frame, create a method setChildComponent(JComponent component) that will receive a JComponent and set the frame as its parent internally. This way you would avoid exposing the private JFrame.

MByD
  • 135,866
  • 28
  • 264
  • 277
  • 3
    Isn't the fact that you *must* do AWT/Swing related calls on the EDT a striking advantage of `invokeLater`? – Waldheinz May 31 '11 at 18:06
  • 1
    All GUI related changes (which includes creating Frames and other Components) should occur in the EDT, which is the point of `invokeLater` (or `invokeAndWait`, alternatively). Often it works even if you do it on another class, but it is not guaranteed to do so, since Swing is not thread-safe. – Paŭlo Ebermann May 31 '11 at 18:21
  • @Waldheinz & @Paŭlo Ebermann - This is not the point. the calls on main (as in this example) are calls on main thread anyway. This is why I didn't find the use of `invokeLater` relevant. In other cases this is of course useful. Sorry for not being clear. – MByD May 31 '11 at 19:05
1

Independently of the question of exposing the JFrame or encapsulating it, why does this class (the methods/fields) have to be static? The object oriented way would be to have them ordinary (instance) methods:

public class FrameCreator {
    private JFrame frame;

    public void createAndShowFrame(){
        //do stuff
    }

    public JFrame getFrame(){
        return frame;
    }
}

Then in your launcher class, you would create an object of this class and call it's methods:

public class Launcher{
    public static void main(String[] args){
        final FrameCreator f = new FrameCreator();
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run(){
                f.createAndShowFrame();
            }
        });
    }
}

If you need to access the created frame from somewhere else, pass this code the FrameCreator instance that created the frame.

Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
  • @Ebermann, I think I am making this needlessly complicated. thanks for the suggestion! :) – mre May 31 '11 at 18:31
  • @Ebermann, I suppose I'll bite the bullet and risk exposing the `JFrame`. – mre May 31 '11 at 19:01
  • About the exposure, some `addToFrame(JComponent)` method like MByD proposed could work. But callers then could simply use `getParent()` (some times) to get at the JFrame anyway. – Paŭlo Ebermann May 31 '11 at 19:13