JComponent - delegating to JPanel

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • eddiewould
    New Member
    • Jul 2008
    • 4

    JComponent - delegating to JPanel

    Hi, I want to write a custom widget which will act similarly to a JPanel (i.e it can contain other Components), but semantically it's not a kind of JPanel so it shouldn't extend from it.

    Here is some sample code showing what I'm trying to achieve:
    Effectively I expect to see a JLabel with the message "This is a test" as well as a JButton "foo".

    What am I doing wrong? Is this possible? Also, I am aware it would be easier to just extend JPanel - but it's not as nice.

    ProgramEntryPoi nt.java
    -----------------------------------
    import java.awt.Dimens ion;
    import java.awt.Graphi cs;

    import javax.swing.JBu tton;
    import javax.swing.JCo mponent;
    import javax.swing.JFr ame;
    import javax.swing.JLa bel;
    import javax.swing.JPa nel;


    public class ProgramEntryPoi nt {
    public static void main(String[] args)
    {
    new ProgramEntryPoi nt();
    }

    public ProgramEntryPoi nt()
    {
    JFrame frame = new JFrame();
    JPanel mainPanel = new JPanel();
    mainPanel.add(n ew JLabel("This is a test..."));
    mainPanel.add(n ew TestComponent() );
    frame.getConten tPane().add(mai nPanel);
    frame.setSize(n ew Dimension(800,6 00));
    frame.setVisibl e(true);
    }

    public class TestComponent extends JComponent
    {
    private JPanel panel;
    public TestComponent()
    {
    this.panel = new JPanel();
    this.panel.add( new JButton("foo")) ;
    this.panel.setV isible(true);
    }

    public void paint(Graphics g)
    {
    this.panel.doLa yout();
    this.panel.pain t(g);
    }
    }
    }
  • BigDaddyLH
    Recognized Expert Top Contributor
    • Dec 2007
    • 1216

    #2
    I don't understand your motivation: what's wrong with using JPanel?

    Comment

    • eddiewould
      New Member
      • Jul 2008
      • 4

      #3
      It's just not very nice -

      My widget really isn't a panel, it's something in it's own right that just happens to want to take advantage of functionality which exists in JPanel rather than rewriting it from scratch.

      If I extend from JPanel then I expose a whole lot of methods which I don't want to.

      For example:

      public void add(Component c)

      I don't want people adding things to my widget willy-nilly. Especially things my widget isn't expecting. I can't reduce the visibility of this method so all I can do is override it and throw a Runtime Exception if anyone tries to call it. Yuck!

      Comment

      • r035198x
        MVP
        • Sep 2006
        • 13225

        #4
        Use composition rather than inheritance then.

        Comment

        • eddiewould
          New Member
          • Jul 2008
          • 4

          #5
          Have you read my post? That's exactly what I'm trying to do.

          Comment

          • r035198x
            MVP
            • Sep 2006
            • 13225

            #6
            Why extend JComponent then?
            I'd expect your widget class to be like
            [CODE=java]public class Widget
            {
            private JPanel panel;
            public Widget()
            {
            this.panel = new JPanel();
            this.panel.add( new JButton("foo")) ;

            }
            public JPanel showIt() {
            return panel;
            }

            }[/CODE]

            Comment

            • BigDaddyLH
              Recognized Expert Top Contributor
              • Dec 2007
              • 1216

              #7
              Originally posted by eddiewould
              It's just not very nice -

              My widget really isn't a panel, it's something in it's own right that just happens to want to take advantage of functionality which exists in JPanel rather than rewriting it from scratch.

              If I extend from JPanel then I expose a whole lot of methods which I don't want to.

              For example:

              public void add(Component c)

              I don't want people adding things to my widget willy-nilly. Especially things my widget isn't expecting. I can't reduce the visibility of this method so all I can do is override it and throw a Runtime Exception if anyone tries to call it. Yuck!
              You are still not making a lot of sense to me. Your class TestComponent extends JComponent, right? Because you don't want to extend JPanel, right? Please stop right now and at least scroll through the API for JComponent and JPanel:




              What you should see is that JComponent has a whack of methods (several hundred?) and JPanel adds 2 methods and overrides 4. That's it. In particular, the add(Component) method you want to avoid is defined in Container, which JComponent extends.

              Conclusion: when you work in Swing, you have to accept this.

              And what r035198x wrote is very much to the point: it sounds like you want composition, not derivation. Remember that you only really need to derive if there is a method you have to override, and you haven't made any case for that.

              Comment

              • eddiewould
                New Member
                • Jul 2008
                • 4

                #8
                Originally posted by BigDaddyLH
                You are still not making a lot of sense to me. Your class TestComponent extends JComponent, right? Because you don't want to extend JPanel, right? Please stop right now and at least scroll through the API for JComponent and JPanel:




                What you should see is that JComponent has a whack of methods (several hundred?) and JPanel adds 2 methods and overrides 4. That's it. In particular, the add(Component) method you want to avoid is defined in Container, which JComponent extends.

                Conclusion: when you work in Swing, you have to accept this.

                And what r035198x wrote is very much to the point: it sounds like you want composition, not derivation. Remember that you only really need to derive if there is a method you have to override, and you haven't made any case for that.
                It is my understanding that the code example I posted showed composition, not derivation. It *contained* a reference to a JPanel rather than extending from one.

                Anyway, can you guys can confirm that what I was trying to do (having a class which extends JComponent, contains a JPanel and delegates it's methods to the JPanel) is not possible?

                What I want is something which

                * Looks and acts like any other JComponent (JButton, JLabel, JTextArea...)
                * Can be added to a container in the same way as other JComponents
                * Doesn't expose the extra methods in the interface JPanel
                * Has most of the functionality of a JPanel
                * Maintains it's own state in the same way e.g a JButton does

                If this is really not possible then r035198x's solution is probably the best compromise. One issue I have with this is that the logic/data for the widget is now separated from the display.

                Compare with a JTextArea: I can just create one and add it to a Panel/Frame and then forget about it.

                frame.getConten tPane.add(new JTextArea());

                I can then rely on the JTextArea to keep track of it's own internal state and operations.

                r035198x's solution is really a factory for JPanels.

                The code might look something like this:

                TestWidget w = new TestWidget();
                frame.getConten tPane.add(w.sho wIt());


                The issue is I can't just throw away w and let it go out of scope - w has to maintain the state for my widget. It's just not very elegant.

                Comment

                • r035198x
                  MVP
                  • Sep 2006
                  • 13225

                  #9
                  Originally posted by eddiewould
                  ...

                  What I want is something which
                  ...
                  * Doesn't expose the extra methods in the interface JPanel
                  * Has most of the functionality of a JPanel
                  Still not very clear. JPanel is a class not an interface.
                  The two requirements above are not well defined and can be interpreted to be contradicting.


                  Originally posted by eddiewould
                  ...
                  r035198x's solution is really a factory for JPanels.
                  No it is not. That's just a basic example of composition. You would then delegate to the JPanel through methods in your widget.
                  e.g
                  [CODE=java]
                  void add(JComponent c) {
                  panel.add(c);
                  }[/CODE]
                  You thus have control on which methods of JPanel you want to expose.
                  The main disadvantage is that your widget can't be directly added to other Containers. The showIt (perhaps getAddableCompo nent is a better name for it) has to be called first to return the JPanel.

                  Comment

                  Working...