Same Jbutton selected state across multiple instances of same JPanel? - java

I have a toggle JButton that, when clicked, either installs or uninstalls some listeners elsewhere (but that's somewhat irrelevant I believe, as it could be just about any code that you don't want executed any number of times in a row, hence, the toggle, you click it once, it does something, you click it again, it undoes that something or whatever). My problem is that I have several instances of this button (or more specifically, several instances of its parent JPanel). This restriction is not my doing and I cannot prevent this. Basically, I'm left with a situation where the user can toggle the button "on" a bunch of times in succession, and needless to say, this screws things up for me.
The buttons themselves are not all visible to the user at once, only one can be seen at any given time. I tried using a component listener, but componentHidden() and componentShown() are never called.
I tried making the button a singleton, but that just had this weird effect of only displaying the button on the last panel it was added to.
I'm kinda stumped. The behaviour I want is simple: Multiple instances of this toggle button that sync their selected state. Ideas?
P.S. I suppose I could construct a list of the instances and update all the other's state when one of them is clicked, but I wonder if there's something simpler out there.
Thanks

Yes, the buttons must all be distinct, but they can either share the same ButtonModel or the same Action. Usually, I try to have them share Actions by creating a single Action that extends AbstractAction, and use it to set the Actions of all the same buttons.

No big reveal here. I solved my problem using my own suggestion, that is, I simply kept a list of all the instances of the button and set their states when any one of them was clicked in an action they all share.

Related

Adding KeyListener to TitleAreaDialog

I have a TitleAreaDialog with a TableViewer which allows the user to select a row from the table. The problem is, that the content of the table may change over time. I would like to implement a refresh behaviour commonly found in browsers (e.g. by pressing F5 the content of the table should refresh).
Below is a screenshot which should hopefully make the scenario a little clearer:
It looks like there is a possible solution in this question, but I think it is flawed for several reasons:
The listener isn't properly detached (e.g if I reopen my dialog I have two filters on my Display)
It doen't add the listener to the TitleAreaDialog or a Widget where I believe it belongs from an architectural point of view.
I would like to avoid manual listener-attaching/detaching (e.g. the listener should get disposed together with the TitleAreaDialog)
Long story short: What is the proper way of adding a KeyListener to a TitleAreaDialog (or Dialog in general) without using the filter mechanism as described in the aforementioned question?
I know that this question somehwhat fails in the SSCCE department, but any pointers into the right direction are highly appreciated.
Adding a Listener for key events is a tricky thing. You want the Listener to be fired when none of the contained Controls has focus and you want it to fire even if a child of the Dialog has focus.
There are basically two solutions to this problem:
The obvious choice: Use addFilter when the Dialog is created and removeFilter when the dialog is closed (in close()).
Create a Listener for SWT.KeyUp and add it to ALL children of the Dialog. This is necessary for the event to fire independent of the focus control.
I prefer solution 1, since it's less clutter and SWT will take care of everything (well, except for adding and removing the filter). Adding a Listener to all child controls is nothing you really should do, but it would do the job as well.
If you don't want to add and remove the filter each time, create a subclass Dialog or TitleAreaDialog that does it once, and reuse it by subclassing again.
If adding and removing the filter is too much hassle in general, then I'm afraid there is no easier solution.

Instanceof, Enum Or Multiple Listeners for JButtons

On my swing GUI I have lines of data and a number of buttons, the user selects a number of items and then then selects a button.
Each button applies a different rule to the data and so different functions need to be called for every button, I'm using an MVC design pattern and my question is such, How should I handle the different needs of every button?
Create a class 'MyButton' which extends JButton then give this some sort of Enum, I can then create 1 action listener and then check which button has been pressed in the ActionListener by inspecting the Enum.
Similar to above but with a different class for each button then using instanceof to determine which has been pressed.
Implement a separate ActionListener for each button
Other?
Which is the best method to use if any? Any advice would be greatly received!
Implement a separate listener for each button.
First because it's the usual solution. Second, between there's no reason to extend JButton just to do something else when it's clicked. That's the role of the ActionListener. Swing components are designed to be used as is, and you should generally not extend them.
It's MVC: you separate the logic (in Actions) and the view (the button).
There is no need to use an enum or to subclass JButton. What you can do to keep things clean when you have dozens of buttons, is a factory class to create Action instances.
If I get your question correctly, you mean to say, you have a data in line items and every line items have a button, which when pressed invokes a rule pertaining to the line item.
If so, then
If you take the 2nd approach, you need to code inside your action listener every time a new line item added in future.
Third approach will also have same implication as above
First approach sounds quite good. You can have a Factory which may have a hashmap keyed with the enum variables and the respective rule. Inside the action listener get the rule from the factory and invoke it.
This way you get a proper separation of concerns and your action listener will act as a controller, having no knowledge of rules and data items.

How to avoid infinite update loops in Swing?

I have a JPanel with a set of items (for example combo boxes and text fields). Some action listeners are implemented on those items to register user updates.
If the user selects a value in a JComboBox (for example), the action listener captures the event. The corresponding underlying bean method is called and the panel is refreshed. Changing can have an impact on other fields displayed in the pane.
The problem is that when the panel is refreshed, all listeners are triggered, and they call for a refresh themselves. This leads to an infinite loop.
How can I avoid this? I can't get rid of the listeners, because I need to capture user updates, but I don't want these to fire when I am only refreshing the panel content.
One option is to have a central boolean value or some indicator that each listener can check to prevent the chaining of events.
Another option is to not refresh the field if the value does not change. That way each component is updated at most once per refresh.
I can't get rid of the listeners, because I need to capture user updates, but I don't want these to fire when I am only refreshing the pane content
Then remove the listeners, refresh the pane content and then restore the listeners. This way the listeners only fire when a user change is made.
I think that if your problem is in combobox it just points to a bug. Really, if user changes the value of the combobox, that somehow triggers refresh of the pane the value of the combo box should not be changed second time! So if it is onValueChanged() (or something like this) it should not be called at all when pane is being refreshed.
But if for some reason it happens you can verify whether the old and new values are the same and exit the listener.
If this still does not help I'd suggest you some non-standard solution: try to investigate the stack trace into the listener. Can you identify whether the listener was called as a direct reaction to user's action or after the pane refresh? In this case you can create utility method and put it in the beginning of all relevant listeners.
My applications also suffered from this problem, and solution with the flag, that I should check in every listener and enable/disable in code, feels not very good for me. I always forgot to set this flag to true/false in necessary places.
That is why I decide to implement another solution.
I just subclass all default swing components that I am using often, and implemented custom ValueChanged event that I fire after mouse/keyboard/clipboard/etc events. Now I am always know, that if ValueChanged event is fired, it means, that value was issued by user, not by code. Event handling in this way much more cleaner. This solution solves my problem.

Keep track of Swing GUI "current state"

Sorry the title is fuzzy, but I really coudln't come up with a fitting title.
I'm developing my first application with Swing, and I'm having a hard time figuring out how to keep track of the current view of the application. With I mean with current view is for example if a button has already been pushed. For example, you shouldn't be able to press "Execute" before a file has even been loaded. I've come up with an architechtural solution to this that is really crappy, and I'd like tips on how to improve it.
I have a label called infoText, and it's updated pretty much every time I press a button. Through this, I'm keeping track of the applications state in this fugly way:
if (infoText == LOADING_NARROW){
printSelected(narrow_list);
}else{
printSelected(list);
}
Rather than keeping track of your state with GUI components, use normal Java objects and variables.
Just keep a boolean loadingNarrow in this case that you reference and update when needed.
Also if you are running a large load as the result of a button press and don't want the user to press it again you can disable the button once the load starts and re-enable it later. (Note I am assuming you are running the load on a separate thread so the GUI does not freeze).
Swing Components keep track of their own states.
My advice:
Initiate the application to a default state.
Adjust the settings in an event driven manner. For instance when JButton A is clicked, enable JButtons B and C and set a JTextField.
Check the states of objects with their builtin methods. Example
if((jButtonA.isEnabled() && jTextField.getText().equals("foobar"))
You can also use the mediator pattern to group related components and their actions.
First: Are they different methods, or a copy-paste-error?
printSelecteds (narrow_list);
printSelected (list);
Second: To disable a button you usually use:
ok.setEnabled (false);
If the file is loaded, you call
ok.setEnabled (true);
to enable the JButton "ok".
I don't see how that is related to your info-text, and to your printSelected(s) method. If you pass the state via the GUI, you might loose the one or the other due to race conditions. Changing a label could be the sink of an state change.
You could have mutual exclusive bit patterns to allow interference:
FILE_OPEN = 1;
SEARCHED = 2;
FRIDAY = 4;
to add them bitwise:
state |= FRIDAY
to ask them up in a binary pattern:
if (state | FILE_OPEN) ....
It doesn't look very elegant to me. I guess I'm not sure what your problem is. :)
To fire an action if some button is pressed, you have to implement an actionListener, which could modify your label as well. But the swing eventloop will already check the state of your components. You seem to duplicate the work partly.

toggle button vs image changing button

When to use this functionality and when to use the other? I personally thing that to switch between two different modes one should use a toggle button but i need to convince some people at work. any formal UI literature on the subject? thanks
I don't have references for you, but as a user I can tell you what I would expect.
I would expect the button to change images when you substitute one action for another because you entered a different mode. This is really relevant to save real estate in your toolbars, etc. For example you could have a dedicated play button and stop button with one always being disabled. Using one button saves space since at no point will both be enabled.
I would expect a normal depressed/unpressed toggle button when there is one mode that you either enable or disable. An example of this is "Toggle Mark Occurrences" in Eclipse. Unpressing that toggle button does not constitute a new action, but rather disabling an active mode.
I’m inclined to go with toggling buttons (buttons that “stick” depressed when “on”) rather than swapping images or label for a command button. I can’t cite any formal literature, but my impression is that it makes it easier both to anticipate the action produced by activation and to read the current state. The appearance and behavior of a toggle button is consistent with physical toggle button switches (like the Play buttons on older physical tape recorders). It’s also consistent with option buttons, check boxes, and state menu items, which all indicate their affirmative states through peripheral graphic design rather than labels. When the control looks like a command button (raised appearance), it’s labeled like a command button, the label indicating the action committed like any command button (e.g., “Connect”). When it looks like a state indicator (sunken, like a text box), its labeled suggest its current state (connected).
A single toggle button should only be used when there are simple True and False states to the process (e.g., Connected or not). Otherwise you need two or more “segmented controls” (abutting toggling buttons) to ambiguously indicate the alternatives (e.g., Forward vs. Reverse). This is analogous to using two option buttons in place of a check box.
Swapping labels to indicate changes in a button’s action can work if you use text labels that unambiguously indicate the action committed on activation, e.g., (“Connect” and “Disconnect”). While the Play/Pause button is a defacto standard, I’d otherwise avoid using an icon or image because it may confuse users on whether the label is indicating the current state or the state they’d get on activation (i.e., the opposite). There have been buttons that do one or the other, so the user can’t rely on experience. An image it not clearly a verb or adjective, so labeling with an image is tantamount to using text labels like “Online” and “Offline.” Even if done right, swapping labels has the disadvantage that the user needs to do a weird mental transformation to read the affirmative state (“It says I can disconnect, therefore I must be online now”). It can also mean you need a wordier label.

Categories

Resources