Results 1 to 8 of 8
  1. #1
    jcleland is offline Member
    Join Date
    Dec 2010
    Posts
    3
    Rep Power
    0

    Thumbs down Preferred method for passing toolbar events to JFrame

    Hi,

    I'm very new to Swing/AWT, but professional Java developer of over a decade. I am developing a simple Swing application, this is my first. I have looked at many of the examples for each component, but they all have one thing in common: They're simple and usually comprised of a single method that builds the entire UI. I understand that this is the point when trying to explain how to use a single component: Simplicity. Having said that, here's my problem:

    I'm subclassing my Swing objects, so I have an Application class that extends JFrame. This object creates a subclassed toolbar, let's just call it MyToolBar, which extends JToolBar. This toolbar allows the use to input data in one of two ways, using a ButtonGroup, event handling, and setEnabled() logic on two text fields. This management of enabling/disabling of controls is the reason I like subclassing JToolBar rather than creating it in my application and add()ing to it. So, the toolbar also has a submit button. The submit button needs to communicate with the application so that it can manipulate other panels in the Application (JFrame) contentpane.

    So here's the question: What is the preferred method for communicating between a JToolBar-derived class (or any class that does not take an event listener, but it's children generate events of interest to a parent container) and the container when a child control (such as a button) generates an event? Numerous solutions come to mind, but they involve stuff that I'd rather not do such as making the application available via static get() and calling a function, etc.

    I'm sure this isn't a new question, but I can't seem to find a post that talks about this, nor can I find a complex enough example. Were I to write my application the way the examples are written, however, I'd be left with an unmaintainable mess. Maybe subclassing is the wrong idea, I don't know. Like I said, this is all new to me but I appreciate input and pointers.

    Thanks!
    James

  2. #2
    KevinWorkman's Avatar
    KevinWorkman is offline Crazy Cat Lady
    Join Date
    Oct 2010
    Location
    Washington, DC
    Posts
    4,017
    Rep Power
    10

    Default

    Extending your GUI components is almost definitely not the way to go.

    What sorts of events are you attempting to pass back to the JFrame class?

    Why don't you just pass a reference to and instance of the JFrame class into the ToolBar class constructor, then call methods on that instance whenever you want?

  3. #3
    jcleland is offline Member
    Join Date
    Dec 2010
    Posts
    3
    Rep Power
    0

    Default

    Thanks for the information Kevin, passing around the application reference was definitely something I considered. I just wasn't sure if there was a "standard" or accepted practice for the, in this case, tool bar to container message/event conduit. Certainly, I can work it this way.

    If you don't mind me asking, you sound adamantly opposed to subclassing Swing components. I don't have an opinion on this as I just don't have any experience. I DO know that it's nice to have a MyToolBar class that implements ActionListener and can handle all the little subtleties that occur when, child controls of the toolbar are manipulated. The encapsulation of all of this seems to make the code easier to maintain. On the other hand, I'm asking because if there's a reason that Swing applications are not typically designed this way, it would be nice to know and I could go back and rewrite some of what I've already done.

    Thanks!

    EDIT: Oh, and the toolbar is being used to control the contents of a JPanel or LayeredPane within the JFrame's content pane. The aforementioned components are contained within a split pane and, when a certain toolbar action is performed, the application will want to start a thread (image rendering, could take time) that will eventually update a panel in the split pane.
    Last edited by jcleland; 12-01-2010 at 09:41 PM.

  4. #4
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    11,452
    Rep Power
    20

    Default

    you sound adamantly opposed to subclassing Swing components
    I think you read too much into Kevin's brief statement. If you're changing the behavior of a Swing class, then sure, subclassing is the correct (and probably the only) way to go.

    However, in most of the code we see here (and on other forums) inheritance is misused where composition would suffice. I prefer the idiom of providing a method that returns a Swing component, fully populated and set up to respond to events, rather than subclass a Swing component without introducing any new behavior. Another approach is to create private inner classes for the same.

    Oversimplified examples (typed here, watch out for typos):

    Approach 1 (which I don't like :))
    Java Code:
          // in the class which uses the panel
          frame.add(new SouthPanel(), BorderLayout.SOUTH);
    :
    public class SouthPanel extends JPanel {
       
       public SouthPanel() {
          JButton button = new JButton("Exit");
          button.addActionListener(new ActionListener() {
             
             @Override
             public void actionPerformed(ActionEvent e) {
                System.exit(0);
             }
          });
          add(button);
       }
    }
    Approach 2:
    Java Code:
          // in the same class
          // OR a class that has a reference to an instance of the class with the following code
          // OR make the method a public (or default access) static final method of a utility class
          frame.add(getSouthPanel(), BorderLayout.SOUTH);
    :
       private JPanel getSouthPanel() {
          JPanel panel = new JPanel();
          JButton button = new JButton("Exit");
          button.addActionListener(new ActionListener() {
             
             @Override
             public void actionPerformed(ActionEvent e) {
                System.exit(0);
             }
          });
          panel.add(button);
          return panel;
       }
    Approach 3: similar to Approach 1 except that SouthPanel is declared as a private inner class.

    db
    Last edited by DarrylBurke; 12-02-2010 at 07:00 AM.

  5. #5
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    11,452
    Rep Power
    20

    Default

    the application will want to start a thread (image rendering, could take time) that will eventually update a panel
    I trust you're familiar with, and have respected, Swing's single threaded rule.
    Threads and Swing
    Lesson: Concurrency in Swing (The Java™ Tutorials > Creating a GUI With JFC/Swing)

    db

  6. #6
    KevinWorkman's Avatar
    KevinWorkman is offline Crazy Cat Lady
    Join Date
    Oct 2010
    Location
    Washington, DC
    Posts
    4,017
    Rep Power
    10

    Default

    Quote Originally Posted by jcleland View Post
    If you don't mind me asking, you sound adamantly opposed to subclassing Swing components.
    Darryl pretty much covered it. But I look at it this way: if I'm going through code somebody else wrote (or even that I wrote a while ago), and I see that the person extended, say, JFrame, I'm going to ask myself, "What did this person change about the default JFrame behavior that this needed to be extended?".

    So just to make it more obvious that nothing has been changed, and the GUI component can be trusted to work as its API specifies, I don't extend a class unless I'm changing something about what that class does. That's not just true with GUI programming, but for some reason it's more common. You don't see as much (but sometimes) somebody extending ArrayList when really they just wanted that class to have an ArrayList, not be an ArrayList.

    And for what it's worth, I generally go a slightly different route than Darryl (this might be "worse" than his approaches, but it's what fits inside my head):

    Java Code:
    public class SomePanel{
       private JPanel panel = new JPanel();
    
       public SomePanel(){
          //add some components to panel
       }
    
       public JPanel getPanel(){
          return panel;
       }
     
    }
    
    public class MainClass{
       public static void main(String... args){
          JFrame frame = new JFrame();
          frame.add(new SomePanel().getPanel());
          frame.pack();
          frame.setVisible(true);
       }
    }

  7. #7
    jcleland is offline Member
    Join Date
    Dec 2010
    Posts
    3
    Rep Power
    0

    Default

    Thanks for the replies, guys. I really appreciate the help and input.

    Yes, I am familiar with Swing and thread safety, but I'll need to do some processing outside of the event handler as it may take up to a second or two (or 4?) and this would (from what I understand) kill the UI performance. I figured I would mutex this somehow, I really hadn't gotten that far yet :) My roots are in microcontroller asm through c++, so I tend to think "mutex" in this type of situation. Of course, that would probably involve polling since I'd be outside the event thread and I can't rely on that... Like I said, I really haven't gotten that far yet, but I know I can't do this processing in the event handler due to (from what I've read) the lengthy nature of the task. I do not intent to hit Components with more than one thread, however.

    Your explanations make sense, it'll be tough for me to "change up" though :) In my head, it goes like this: I'm EXTENDING the JToolBar class because I'm adding specific behavior to it. It still contains buttons and text inputs, etc, but I'm also managing the enabling and disabling of items in the toolbar depending on radio button states, etc, so it seems like I want to subclass this and handle the events "internally". It's like packaging all of this "MyToolBar" specific behavior into one class, rather than having a parent container or other class manage states for it.

    Anyway, I'm the Swing newbie here, and I get that, so I'm going to reevaluate my approach. Again, I really appreciate the input.

    James

  8. #8
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    11,452
    Rep Power
    20

    Default

    No, you're NOT adding behavior to JToolBar, you're USING the behavior provided by the API. As such, your class should CONTAIN a JToolbar, not BE a JToolBar.

    I gave you a link to the Swing concurrency tutorial. Go through it to learn the correct ways to run a process on a thread other than the EDT and process the results to update a Swing component ON the EDT -- either using SwingWorker or SwingUtilities#invokeLater (or invokeAndWait, if that happens to be more appropriate -- usually it isn't).

    db

Similar Threads

  1. Replies: 6
    Last Post: 04-12-2010, 12:33 PM
  2. Replies: 2
    Last Post: 04-04-2010, 09:57 PM
  3. Passing data from one JFrame to another JFrame
    By tarami in forum New To Java
    Replies: 3
    Last Post: 08-06-2009, 06:44 PM
  4. Replies: 1
    Last Post: 07-16-2009, 03:15 PM
  5. Passing data from one JFrame to another
    By abhiN in forum New To Java
    Replies: 2
    Last Post: 03-28-2008, 06:39 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •