I have a JTree, a JTable and a JList which displays the same set of objects, but in different order and with different information. If an item is selected from one of the Component, I want to select the same object on the other two Components (meaning they should be highlighted). Naturally I monitor the selection events with a Listener. Here is the problem, when a Component retrieves the selected object, I'll have to make sure the object is selected on the other Components by calling selection methods on them. This, will then notify the selection listeners on the other two components. But each of those events will in turn call selection events on components other than itself, causing an infinite loop going among the three Components.
I see one solution is to use a boolean flag, and make the listeners not propagate the selection if the flag is set. However, this seems cumbersome and not elegant. Is there a way to simply tell JTree, JTable and JList to make the selection but not fire any events (as oppose to fire an event and then catching and stopping it with a boolean flag)?
Take a look at SharedModelDemo. I think it does what you're looking for.
I would use a flag indicating whether it's user changes or internal changes but yu can also remove listeners before selection call and add them after to prevent events firing.
Related
In SWT, I can find plenty of events that fire when text is typed into the combo, the user makes a selection, etc.
Are there any triggers for when the combo list gets updated, though?
E.g., if I the list is
['apple', 'banana']
and it becomes
['apple', 'banana', 'shoe']
is there any trigger for that, and if not, can I create one?
SWT does not send an event if the list of items of a Combo or CComb changes.
If you use a JFace ComboViewer, its IContentProvider gets informed when the viewer's input changes through its inputChanged() method.
If that's not what you want, then you are free to write application code that notifies interested observers about content changes.
Right now, when I have a form with many JComponents, mainly JTextFields, JTextAreas, JComboboxes, JCheckBoxes and JButtons and want to control their behaviour, for instance the change of focus after a certain key was released, I do the following:
I put all my components in a JComponent[] and cycle through it, adding the appropriate listener. When an event is registered by said listener, I check with "instanceof" what kind of JComponent fired the event and assign the proper reaction.
I use this method for instance to cycle with VK_ENTER through the form, or to "firePropertyChange(..)" after a DocumentListener fires, or to add UndoRedoListeners and so on.
My question : is there a better way to do this and if yes, can you explain to me the benefits ?
but my question refers to the general practice of putting all
JComponents in an array and cycling through them for every listener
and every fired event. It works fine enough, but it feels a bit
"uneconomic",so I wanted to know if it is recommended practice, or if
there is a better way of doing it.
I usually write a custom listener (often as an anonymous class) per type/ instance if I have type/ instance specific behavior so that I can avoid instanceof and other other checks.
You'll want to customise the focus tranfersal system.
Take a look at How to Use the Focus Subsystem, in particular Customizing Focus Traversal
I have a JComboBox whose values are retrieved across the net.
I'm looking for a way to indicate that fact to the user, when the user wants to see the list, expands the drop down, and only then the data is being retrieved.
The basic requirements include:
JComboBox's drop-down shouldn't lock the EDT, but the combo's action should not work until there are values.
User should know when all data has been retrieved.
The size (UI real-estate) of the indication should be as small as possible.
Note that the data isn't retrieved until the user wants to see the combo's values (i.e. expands the drop-down list).
The solution i've used:
I've used a SwingWorker to keep the UI responsive. The combo box was overlayed using JIDE's Overlayable with JIDE's InfiniteProgressPanel that listens to the worker.
To avoid locking the EDT, your data retrieval should be done in a background thread. I would use a SwingWorker to find and load the values since this makes available a background thread with other goodies that make it very Swing-friendly. I would make the JComboBox enabled property false until all values have been loaded, and then enable it via setEnabled(true). You will know the SwingWorker is done either through its done() method (by overriding it), or by adding a PropertyChangeListener to the SwingWorker and being notified when its state is SwingWorker.StateValue.DONE.
One way for the user to know that the process is complete is that they will see when the combo box has been re-enabled. If you want a more obvious indicator, you could display a JProgressBar or a ProgressMonitor. This could be displayed in a dialog if you wish to leave the GUI appearance mostly unchanged.
I implemented it by adding "Loading..." item and a special border around the JComboBox. On click separate thread is started adding new items via SwingUtilities.invokeAndWait. When loading is completed the "Loading..." last item is removed.
to not force my users to wait until the data is loaded, combine the answers by eel and stan :-)
start off with the model containing zero or one real value plus the dummy entry "loading"
register a PopupMenuListener and start a SwingWorker loading the data (into a separate datastructure, might be a new model) in its very first menuWillBecomeVisible
while loading, select the dummy entry (and/or whatever else is appropriate to inform the user what's happening), the action has to be aware of "nothing-to-do-yet" as well
listen to the worker, when receiving the DONE replace/fill the data into the combo's model
I have been looking into JTree and TreeCellRenderer. It seems in general, the application (with one JTree) has only one instance of TreeCellRenderer. The application makes multiple calls to TreeCellRenderer's getTreeCellRendererComponent method to decide how each TreeCell is drawn, and such call are made in many occasions (when a cell is selected, deselected, move over, when scrolling, etc.). Why did they decide to do that instead of having multiple instances of TreeCellRenderer, each responsible for one cell??
I am trying to make a JTree where each cell contains a checkbox. The checkbox can be checked/unchecked by the user. Then, the TreeNode userObject's values are set base on the state of these checkboxes. But, from the current JTree design this is impossible - since there is only one instance of JCheckBox, and is only used to show how the Cell looks like (you can't really check it). In some sense I want to separate selection of the TreeCell and the checking of the boxes.
I have some workarounds (implementing MouseAdapter and checking if the mouse click is close by where the checkbox is rendered, then emulate a check on the box by changing its appearence in TreeCellRenderer), but still I want to know if this can be done more directly. Thanks!
Why did they decide to do that instead of having multiple instances of TreeCellRenderer, each responsible for one cell?
This is a nice example of the flyweight pattern.
For a check box tree, I like org.netbeans.swing.outline.Outline, mentioned here, but other examples are available.
Addendum: Reading your question more closely, you ask:
In some sense I want to separate selection of the TreeCell and the checking of the boxes.
This is the correct instinct: The data (checked or unchecked) should be stored in the model (TreeModel), not the view (JCheckBox). The example uses instances of CheckBoxNode in it's (implicit) model, accordingly.
I want to code two JList (categories and items). When I click one category it should select all the items for that category and when I click on one item it should select its categories. So both JList will have a ListSelectionListener listening at each other and changing the selection.
Should I fear about some a kind of "loop" ? Is there a way to tell that an Event has been consumed ? how do people manage that kind of situation ?
Thanks
As you have imagined, each time make selection on listA, you will trigger a ListSelectionEvent to be fired on your listener for listA, whose job it is to find all appropriate items in listB to select. Forcing selection then on listB will trigger events to be handled by your listB listener. This will in turn force selection on listA. Simply using two listeners doesnt solve the problem.
I see two options:
1 - use a single listener. This listener will need to test the source of the event by using the getSource method on the ListSelectionEvent. If the source is listB, remove your listener from the listenerlist of listA, force selection on listA and then readd.
list1.removeListSelectionListener(this);
list1.setSelectedIndex(e.getFirstIndex()); //this would have to be played with to allow for intervals
list1.addListSelectionListener(this);`
2 - use two listeners, however, to avoid the loop, you would need to test whether the item is already selected before attempting to select it. If it is already selected, dont reselect it.
Look at the Beans Binding API. Here's a tutorial for NetBeans.
Two Listeners is good way how to do that, don't worry. Just be sure you create listeners only ONCE, not in loop.
Check where your focus is. If your listener listens to component A and the focus is not on A, do not update other components as A is not the component changed by the user.