Results 1 to 8 of 8
- 12-16-2012, 12:03 PM #1
Member
- Join Date
- Dec 2012
- Posts
- 14
- Rep Power
- 0
My ChangeListener isn't listening to changes made by my Action Listener
Hello everyone. I'm puzzled by the behaviour of some of my event Listeners, I've written a small expample program to demonstrate my problem. It happens when an ActionListener that I have registered on a JButton fires and calls InsetTab on an instance of JTabbedPane. The JTabbedPane instance has a ChangeListener registered on it that I expected to notice the newly added tab and and perform a few simple tasks on the newly added tab. In this greatly simplified example these tasks are to merely create a new instance of the TabComponent that contains the JButton with the ActionListener registered to it that caused the creation of the new tab, change the title text of the newly created tab and finally to create a new instance of JPanel, colour it green and add it to the new tab window.
The ChangeListener works fine when JTabbedPane.insertTab() is called from the containing JFrame's constructor method as you can see if you compile and run the example code given below. However when JTabbedPane.insertTab() is called from the ActionListener on the instance of JButton, the ChangeListener never fires. Can anyone help me understand why this is the case?
Here's the example code that demonstrates what I'm talking about.
EventTest.java
TabComponent.java:Java Code:package eventtest; import java.awt.Color; import java.awt.Dimension; import javax.swing.GroupLayout; import javax.swing.GroupLayout.SequentialGroup; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class EventTest extends JFrame { private JTabbedPane tabbedPane = new JTabbedPane(); public EventTest() { super(); setDefaultCloseOperation(EXIT_ON_CLOSE); setTitle("Event Test"); GroupLayout layout = new GroupLayout(getContentPane()); getContentPane().setLayout(layout); SequentialGroup hGroup = layout.createSequentialGroup(); SequentialGroup vGroup = layout.createSequentialGroup(); layout.setHorizontalGroup(hGroup); layout.setVerticalGroup(vGroup); hGroup.addComponent(tabbedPane); vGroup.addComponent(tabbedPane); tabbedPane.addChangeListener(new PaneChangeListener()); tabbedPane.insertTab("This title text will be replaced by the " + "ChangeListener associated with this instance of " + "JTabbedPane", null, null, null, tabbedPane.getTabCount()); pack(); setLocationRelativeTo(null); } private class PaneChangeListener implements ChangeListener { /* I don't understand why this listener is fired when InsertTab is * called in EventTest's constructor, but is not fired when InsertTab * is called from TabComponent. */ @Override public void stateChanged(ChangeEvent evt) { JTabbedPane s = (JTabbedPane) evt.getSource(); s.setTitleAt(s.getTabCount() - 1, "Tab #" + Integer.toString(s.getTabCount())); s.setTabComponentAt(s.getTabCount() - 1, new TabComponent(s)); JPanel panel = new JPanel(); panel.setPreferredSize(new Dimension(500, 100)); panel.setBackground(Color.GREEN); s.setComponentAt(s.getTabCount() - 1, panel); } } public static void main(String[] args) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { new EventTest().setVisible(true); } }); } }
Java Code:package eventtest; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.GroupLayout; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTabbedPane; public class TabComponent extends JPanel { JTabbedPane parentPane; private static ActionListener defaultActionListener; public TabComponent(JTabbedPane pane) { super(); parentPane = pane; JLabel label = new JLabel() { @Override public String getText() { int indexInTabPane = parentPane.indexOfTabComponent(TabComponent.this); if (indexInTabPane != -1) { return parentPane.getTitleAt(indexInTabPane); } else { return "Not assigned to a TabbedPane"; } } @Override public void setText(String text) { int indexInTabPane = parentPane.indexOfTabComponent(TabComponent.this); if (indexInTabPane != -1) { parentPane.setTitleAt(indexInTabPane, text); } } }; JButton button = new JButton("Add a tab"); if (defaultActionListener == null) { defaultActionListener = new ButtonActionListener(); } button.addActionListener(defaultActionListener); button.setFocusable(false); // This block of code is just LayoutManager stuff. GroupLayout layout = new GroupLayout(this); this.setLayout(layout); GroupLayout.SequentialGroup hGroup = layout.createSequentialGroup(); GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup(); layout.setHorizontalGroup(hGroup); layout.setVerticalGroup(vGroup); int gapSize = 2; hGroup.addGap(gapSize) .addComponent(label) .addGap(gapSize) .addComponent(button) .addGap(gapSize); vGroup.addGap(gapSize) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(label) .addComponent(button)) .addGap(gapSize); } protected class ButtonActionListener implements ActionListener { /* When the Button is pressed and this ActionListener fires and calls * InsertTab on parentPane,the ChangeListener registered on * parentPane doesn't seem to pick up on the change. What am I missing? */ @Override public void actionPerformed(ActionEvent evt) { JButton s = (JButton) evt.getSource(); parentPane.insertTab("Hey! Where's my TabComponent?", null, null, null, parentPane.getTabCount()); } } }
- 12-16-2012, 01:08 PM #2
Re: My ChangeListener isn't listening to changes made by my Action Listener
Nothing to do with whether the code is called form the constructor or from an ActionListener and everything to do with whether there actually is a change that should be notified. When you add the first tab to a JTabbedPane, it is automatically selected, and that is a change. Adding another tab doesn't change the selection.
Add this line to the end of the actionPerformed(...) code and see the result for yourself:Oh, and using almost any layout other than GroupLayout would have given you much shorter, eminently readable code. Since the JTabbedPane is the only component added to the JFrame, going with the default BorderLayout and adding it at the default position of CENTER would have been a one-liner instead of your 8 lines.Java Code:parentPane.setSelectedIndex(parentPane.getComponentCount() - 1);
dbWhy do they call it rush hour when nothing moves? - Robin Williams
- 12-16-2012, 01:25 PM #3
Re: My ChangeListener isn't listening to changes made by my Action Listener
And the JPanel's label and button could be added to the default FlowLayout, producing virtually the same result and saving another 16 LOC.
See for yourself how much more readable this is:dbJava Code:import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class EventTest extends JFrame { private JTabbedPane tabbedPane = new JTabbedPane(); public EventTest() { setDefaultCloseOperation(EXIT_ON_CLOSE); setTitle("Event Test"); add(tabbedPane); tabbedPane.addChangeListener(new PaneChangeListener()); tabbedPane.insertTab("This title text will be replaced by the " + "ChangeListener associated with this instance of " + "JTabbedPane", null, null, null, tabbedPane.getTabCount()); pack(); setLocationRelativeTo(null); } private class PaneChangeListener implements ChangeListener { @Override public void stateChanged(ChangeEvent evt) { System.out.println("stateChanged"); JTabbedPane tabbedPane = (JTabbedPane) evt.getSource(); tabbedPane.setTitleAt(tabbedPane.getTabCount() - 1, "Tab #" + Integer.toString(tabbedPane.getTabCount())); tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, new TabComponent(tabbedPane)); JPanel panel = new JPanel(); panel.setPreferredSize(new Dimension(500, 100)); panel.setBackground(Color.GREEN); tabbedPane.setComponentAt(tabbedPane.getTabCount() - 1, panel); } } public static void main(String[] args) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { new EventTest().setVisible(true); } }); } } class TabComponent extends JPanel { JTabbedPane parentPane; private static ActionListener defaultActionListener; public TabComponent(JTabbedPane pane) { super(); parentPane = pane; JLabel label = new JLabel() { @Override public String getText() { int indexInTabPane = parentPane.indexOfTabComponent(TabComponent.this); if (indexInTabPane != -1) { return parentPane.getTitleAt(indexInTabPane); } else { return "Not assigned to a TabbedPane"; } } @Override public void setText(String text) { int indexInTabPane = parentPane.indexOfTabComponent(TabComponent.this); if (indexInTabPane != -1) { parentPane.setTitleAt(indexInTabPane, text); } } }; JButton button = new JButton("Add a tab"); if (defaultActionListener == null) { defaultActionListener = new ButtonActionListener(); } button.addActionListener(defaultActionListener); button.setFocusable(false); add(label); add(button); } protected class ButtonActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent evt) { JButton s = (JButton) evt.getSource(); parentPane.insertTab("Hey! Where's my TabComponent?", null, null, null, parentPane.getTabCount()); parentPane.setSelectedIndex(parentPane.getComponentCount() - 1); } } }Why do they call it rush hour when nothing moves? - Robin Williams
- 12-16-2012, 05:01 PM #4
Member
- Join Date
- Dec 2012
- Posts
- 14
- Rep Power
- 0
Re: My ChangeListener isn't listening to changes made by my Action Listener
Right. So a change in the number of tabs in a JTabbedPane is of no concern to a ChangeListener unless the first tab is being added which then sets the selected index which is something that the ChangeListener is concerned with. Thanks for clearing that up. I assumed that using setSelectedIndex() at the end off my ActionListener would cause the ChangeListener to fire because I noticed that when I ran the code and clicked on a newly added tab that, as soon as I did, the ChangeListener would fire and do what I wanted it to. I was reasonably confident that I wasn't using the wrong kind of listener bacause Listeners Supported by Swing Components (The Java™ Tutorials seemed to imply that it was the only one that could be used with a JTabbedPane, but I didn't want to go and throw in a work-around like that without first understanding why what I was trying to do would not work. Is there any sort of event listener I can use to detect a change in the number of tabs in a JTabbedPane, or do I have to stick with switching to a newly created tab and back again to make the CangeListener fire?
- 12-16-2012, 06:23 PM #5
Re: My ChangeListener isn't listening to changes made by my Action Listener
To know what listeners can be used with a Swing component (or any class really) go through the API looking for addXxxListener(...) methods.I was reasonably confident that I wasn't using the wrong kind of listener bacause Listeners Supported by Swing Components (The Java™ Tutorials seemed to imply that it was the only one that could be used with a JTabbedPane
You can use a PropertyChangeListener and listen for the "indexForNullComponent" property.dbJava Code:tabbedPane.addPropertyChangeListener("indexForNullComponent", new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { JTabbedPane tabbedPane = (JTabbedPane) evt.getSource(); tabbedPane.setTitleAt(tabbedPane.getTabCount() - 1, "Tab #" + Integer.toString(tabbedPane.getTabCount())); tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, new TabComponent(tabbedPane)); JPanel panel = new JPanel(); panel.setPreferredSize(new Dimension(500, 100)); panel.setBackground(Color.GREEN); tabbedPane.setComponentAt(tabbedPane.getTabCount() - 1, panel); } });Last edited by DarrylBurke; 12-16-2012 at 06:29 PM.
Why do they call it rush hour when nothing moves? - Robin Williams
- 12-16-2012, 08:45 PM #6
Member
- Join Date
- Dec 2012
- Posts
- 14
- Rep Power
- 0
Re: My ChangeListener isn't listening to changes made by my Action Listener
Thanks for the great information. I'm always referring back to the API anyway because my memory is very bad and I constantly forget method names and signatures, but I don't see any mention of which properies can be listened for, but Im assuming that these are the bound properties I've seen mentioned in the JavaBeans tutorial trail, so I guess I should go and have a good read of that before I start asking stupid questions that have probably been answered a million times before already.
Thanks again for the great information. :)
- 12-16-2012, 09:00 PM #7
Re: My ChangeListener isn't listening to changes made by my Action Listener
When I want to know what property changes are fired I use this:
All aren't bound properties. Bound properties are those which have an accessor and mutator (get../is... and set.. methods).Java Code:public void propertyChange(PropertyChangeEvent evt) { System.out.println(evt.getPropertyName()); }
dbWhy do they call it rush hour when nothing moves? - Robin Williams
- 12-16-2012, 09:20 PM #8
Member
- Join Date
- Dec 2012
- Posts
- 14
- Rep Power
- 0
Similar Threads
-
Action Listening/Handling Troubles.
By gaeronf in forum AWT / SwingReplies: 4Last Post: 11-05-2012, 04:04 AM -
action listener
By skuskusas in forum New To JavaReplies: 4Last Post: 09-04-2012, 07:13 PM -
Action-Listener with multiple Arguments? (Button Listener, specifically)
By Kevinw778 in forum AWT / SwingReplies: 2Last Post: 12-11-2011, 10:44 PM -
GUI Listener not Listening
By m_patten2 in forum AWT / SwingReplies: 2Last Post: 11-24-2010, 01:06 AM -
Action Listener
By greatmajestics in forum AWT / SwingReplies: 8Last Post: 03-25-2010, 05:39 PM


LinkBack URL
About LinkBacks
Reply With Quote

Bookmarks