Results 1 to 7 of 7
  1. #1
    Serpenthelm is offline Member
    Join Date
    Jan 2012
    Posts
    7
    Rep Power
    0

    Default Events and listeners - reduce coupling

    I have a complex situation, but I'll explain it with a simple example, so please let us think of a solution that can work for bigger things as well.

    I have a JFrame which contain a JPanel full of JButtons. Right now the JPanel is a nested class of the JFrame, but the code is getting too long to read so I want to make JPanel an external class.

    The problem is that the JButtons are using anonymous classes to make the JFrame display different strings. If I make their container an external class, they will no longer be able to act on the JFrame directly.

    So I need to change my code, but this time I want to reduce coupling. If I have JFrame implement an ActionListener itself, then I'd need some way to figure out which JButton was actually clicked. I could use the getSource() method, but then the JFrame class would be very coupled with the external class JPanel, as it would need to know the name of the button inside it.

    Is there a way to make JPanel an extenal class, and handle the events cleanly?

    Here's a really stripped down example of my situation, I'd like an equally simple correction.
    Java Code:
    package sandbox;
    
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class MyFrame extends JFrame {
    	JPanel myPanel;
    	JButton button1;
    	JButton button2;
    	
    	public MyFrame(String title) {
    		super(title);
    		
    		myPanel = new JPanel();
    		setContentPane(myPanel);
    		
    		button1 = new JButton("Button 1");
    		button1.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				MyFrame.this.setTitle("Button 1 clicked");
    			}
    		});
    		myPanel.add(button1);
    		
    		button2 = new JButton("Button 2");
    		button2.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				MyFrame.this.setTitle("Button 2 clicked");
    			}
    		});
    		myPanel.add(button2);
    		
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		pack();
    		setVisible(true);
    	}
    	
    	public static void main(String args[]) {
    		MyFrame myFrame = new MyFrame("No button clicked");
    	}
    }

  2. #2
    pbrockway2 is offline Moderator
    Join Date
    Feb 2009
    Location
    New Zealand
    Posts
    4,574
    Rep Power
    12

    Default Re: Events and listeners - reduce coupling

    Right now the JPanel is a nested class of the JFrame
    Not in the code you posted.

    That code does not add any new behaviour to MyFrame over and above what a frame does by virtue of being a frame. So I'd remove the MyFrame class altogether. (In general frames are just that: gui frames, not generic containers for application state, much as they might be presented that way in simple examples.)

    That leaves the panel. If the panel wants to have buttons that alter the title of the frame of which they are part, they can just use SwingUtilities.getRoot() and do that.

    -----

    Also the frame should be constructed on the event dispatch thread: see Initial Threads (The Java™ Tutorials > Creating a GUI With JFC/Swing > Concurrency in Swing)
    Last edited by pbrockway2; 01-02-2012 at 03:45 AM.

  3. #3
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,316
    Blog Entries
    1
    Rep Power
    26

    Default Re: Events and listeners - reduce coupling

    I would use a Control class a la Model-View-Control (though in this situation simplified as there's no model) as the glue. For e.g.,

    Java Code:
    import java.awt.Dimension;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class MyFrame2 extends JFrame {
    
       public MyFrame2(String title) {
          super(title);
    
          MyPanel2 myPanel = new MyPanel2();
          MyControl control = new MyControl();
          myPanel.setControl(control);
          control.setFrame2(this);
          
          setContentPane(myPanel);
          
          setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          pack();
          setVisible(true);
       }
       
       public static void main(String args[]) {
          new MyFrame2("No button clicked");
       }
    }
    
    class MyPanel2 extends JPanel {
       private static final int PREF_W = 500;
       private static final int PREF_H = 300;
       private MyControl control;
       
       public MyPanel2() {
          JButton button1 = new JButton("Button 1");
          JButton button2 = new JButton("Button 1");
          
          add(button1);
          add(button2);
          
          button1.addActionListener(new ActionListener() {
             
             @Override
             public void actionPerformed(ActionEvent evt) {
                if (control != null) {
                   control.button1Action(evt);
                }
             }
          });
          button2.addActionListener(new ActionListener() {
             
             @Override
             public void actionPerformed(ActionEvent evt) {
                if (control != null) {
                   control.button2Action(evt);
                }
             }
          });
       }
       
       @Override
       public Dimension getPreferredSize() {
          return new Dimension(PREF_W, PREF_H);
       }
       
       public void setControl(MyControl control) {
          this.control = control;
       }
             
    }
    
    class MyControl {
       private MyFrame2 frame2;
       private MyPanel2 panel2;
       
       public void setFrame2(MyFrame2 frame2) {
          this.frame2 = frame2;
       }
       
       public void setPanel2(MyPanel2 panel2) {
          this.panel2 = panel2;
       }
       
       public void button1Action(ActionEvent evt) {
          frame2.setTitle("Button 1 pressed");
       }
    
       public void button2Action(ActionEvent evt) {
          frame2.setTitle("Button 2 pressed");
       }
    }

  4. #4
    Serpenthelm is offline Member
    Join Date
    Jan 2012
    Posts
    7
    Rep Power
    0

    Default Re: Events and listeners - reduce coupling

    Thank you, I guess I could call a method of MyFrame directly, but this pattern seems rather cleaner!

    Quote Originally Posted by pbrockway2 View Post
    Not in the code you posted.
    Also the frame should be constructed on the event dispatch thread: see Initial Threads (The Java™ Tutorials > Creating a GUI With JFC/Swing > Concurrency in Swing)
    Never heard of that. Do I need to do that for every single component, or just for the main window?
    Last edited by Serpenthelm; 01-02-2012 at 06:58 PM.

  5. #5
    pbrockway2 is offline Moderator
    Join Date
    Feb 2009
    Location
    New Zealand
    Posts
    4,574
    Rep Power
    12

    Default Re: Events and listeners - reduce coupling

    As the pages linked to explain, most code that interacts with the Swing framework should be executed on the event dispatch thread. This normally not such a big deal as "Once the GUI is created, the program is primarily driven by GUI events, each of which causes the execution of a short task on the event dispatch thread." So in your example the actionPerformed() methods will run in the EDT (and any methods they call, likewise). The exception is the thread that main() runs in and for that one the SwingUtilities methods allow you to write the Swing code you want to have performed and schedule it to be run on the EDT as soon as possible.

  6. #6
    Serpenthelm is offline Member
    Join Date
    Jan 2012
    Posts
    7
    Rep Power
    0

    Default Re: Events and listeners - reduce coupling

    Somehow I managed to get my previous comment deleted.

    Anyway, that means that I only need to fix the main, I guess. Easy enough.

    Thanks.

    EDIT: the forum says 5 replies, but I can see only 4... and I can't see my new Thread, is there something wrong?
    Last edited by Serpenthelm; 01-03-2012 at 01:46 AM.

  7. #7
    pbrockway2 is offline Moderator
    Join Date
    Feb 2009
    Location
    New Zealand
    Posts
    4,574
    Rep Power
    12

    Default Re: Events and listeners - reduce coupling

    The numbering system is wrong basically. The original post is #1 and replies are numbered from #2... Your other thread was "moderated" (which has something to do with attached images and post count) as has now been approved.

Similar Threads

  1. Replies: 3
    Last Post: 01-13-2012, 12:45 PM
  2. Listeners and events
    By cglacet in forum New To Java
    Replies: 3
    Last Post: 01-20-2011, 03:21 PM
  3. Creating a GUI events with action listeners
    By sidd0123 in forum AWT / Swing
    Replies: 8
    Last Post: 04-03-2010, 12:32 AM
  4. When do we draw the line for loose coupling.
    By h8alfred in forum Advanced Java
    Replies: 0
    Last Post: 03-27-2009, 04:05 AM
  5. coupling
    By srinuvericharla in forum Advanced Java
    Replies: 1
    Last Post: 05-16-2007, 05:06 PM

Posting Permissions

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