I'm doing an app with lots of buttons and menus and I want enable and disable the buttons and menu items when the actions attached to them can or can not be performed. ie the save button and the save menu item only will be active when there are unsaved changes.
Question: How can I do this efficiently/Which is the correct way to do this?
One solution can be have a private variable for each button and menu entry and enable/disable it as needed.
Other solution can be get all the components of the JToolBar and the JMenu in an array and iterate over all them and enable/disable as needed.
But I think there are better solutions. Any help or guideline will be apreciated.
edit: The question is not how to enable/disable a single button or menu item, I will know how can I manage the state of all the buttons and menu items of the app. Which is the best way to achive this?. I have explained some solutions in which I have been thinkin, but none of them convince me.
The Action class already supports this. See the Action#isEnabled and Action#setEnabled methods. Calling the setter will fire an event, on which the UI on which this Action is set will enable/disable itself.
The Action can be seen as the model for your UI buttons/menu items/... . All state is stored and updated in the model, and the view needs to reflect this (MVC pattern).
1) to disable from clicking use:
JButton#setEnabled(boolean)
and
JMenuItem#setEnabled(boolean)
2) to disable ActionListener for some time use a private boolean variable inside
public void actionPerformed (ActionEvent ae) {
if (!enabled) return;
// rest of code
}
Related
I have a question regarding the possibility to dinamically update the visual side of a swing application.
I have created a small program, that works without any compile/logic errors and it does it's thing but it has a flaw. It does not automatically update when user clicks on something.
Let me explain the issue with the underneath picture
I tried adding a repaint and revalidate to anything. but it doesn't seem to work. they get ignored. Really, I added a repaint/revalidate method to EVERYTHING. Still nothing :)
I suggest adding the action event to the checkbox (I called it fullAutomaticCheckBox and the field txtField):
private void fullAutomaticCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {
txtField.setEnabled(fullAutomaticCheckBox.isSelected());
}
To add the event listener:
fullAutomaticCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
fullAutomaticCheckBoxActionPerformed(evt);
}
});
I want the text field to enable itself.
Then you add an ActionListener to the check box to enable/disable the text field depending on the state of the checkbox.
once user inputs a number it will repaint dynamically
If you want the screen to repaint, then you need to invoke the "update calculations" code dynamically. So you can add a DocumentListener to the text field. This will generate an event any time the user adds or removes text in the text field.
Read the section from the Swing tutorial on How to Write a DocumentListener for a basic example to get you started.
Imagine I'm making a simple Word Processor with Java Swing. I've got a set of Actions written to perform text justification. On the MenuBar I've got a menu:
View
Left Justify
Center Jusitfy
Right Justify
This consists of JRadioButtonMenuItems and a ButtonGroup to ensure only one item is selected at any one time.
Also, imagine I've got an equivalent toolbar consisting of JToggleButtons and again a ButtonGroup to ensure only only button can be active at any one time.
The "Left Justify" JRadioButtonMenu and JToggleButton are initialised using the same Action, and so on with the other items.
My question is this: what is the best method for syncronizing the two groups? If I click "Right Justify" icon on the toolbar, I want the group in the Menu to be updated accordingly, and vice versa.
I after a lot of searching I found information here. Basically, you can add this to your action's actionPerformed method:
action.putValue(Action.SELECTED_KEY, Boolean.TRUE);
And this will do all the work for you!
Unfortunately the official Sun tutorials don't cover this aspect (or at least I didn't spot it), hence the difficulty in spotting such a simple approach to resolving my problem.
Observer pattern my friend. The menu bar observe the toolbar, and the toolbar observe the menu bar. They will both be observer and observable. Each one has his own listener which, on a change event, notify the observer (the other one) with the new value in parameter.
One of the great advantage of the observer pattern is that there is very low coupling, so you don't need a lot of refactoring to implement the linking, to modify it or to remove it in the future.
Take a look at the Mediator Design Pattern
If you are using the Swing Actions the components should be disabled/enabled automatically if the action itself is. You can register yourself as a propertyListener to an action as well to monitor other changes. Look at http://java.sun.com/javase/6/docs/api/javax/swing/Action.html for detailed list of which properties are available.
On the other hand (me again), you could just write 1 listener in an external class. A listener for the menu and for the toolbar. When 1 changes, the listener set them both to the new value.
I have a menu with a few JCheckBoxMnuItems. How do I ensure that the Menu stays open until I have done all my selections (i.e. checked the menuitems) and does not close on just clicking one of them?
I'd rather not try to change the normal menu behavior for an application or for a part of the menu tree. A User expects that the menu closes automatically after a menu item is clicked. And, if you kept the menu expanded, what kind of action would you invent to close it manually after you've done your last selection?
If there's a requirement to change more then one setting within one use case, then you should consider to provide a small dialog where the use can apply the changes and confirm them at once. I believe, that's more consistent with typical behaviors of UIs.
And it declutters the menu bar, you'll have just one 'setup' menu item instead of a dozen (?) check box actions :)
I guess menu's aren't supposed to allow multi-selection.
But you may offer keyboard shortcuts to set the menuitems without using the menu at all.
If the set-operation of your flags is a central aspect in your application, I would tend to use a dialog here. These are all suggestions which do not require to change the internal implementation of the existing controls, even though I know, that it would be possible in swing.
I agree that it is better to do this with standard UI. However, if do you want to add checkboxes that do not close the menu it is surprisingly easy:
JCheckBox checkBox = new JCheckBox("Text");
checkBox.setOpaque(false);
checkBox.setRequestFocusEnabled(false);
menu.add(checkBox);
This may not work on every look and feel and the check boxes will not line up with menu items in the same manner as JMenuItems but it seems to be a reasonable place to start.
I have a Java program where I have a JMenu with an arbitrary number of items (in this case, there is one menu item for each dynamic library currently loaded in a different program). I'm running a loop to add JCheckBoxMenuItem s to the menu, since I don't know how many there will be.
How can I set up an action listener for these menu items that is aware of which option called it? Specifically, I want to run the same function but with a different set or parameters for each of the menu items (and a different function again depending on whether the check is being toggled or detoggled).
Could someone point me in the right direction?
While event.getSource() will definitely let you know which particular button the event came from it has the side effect of needing to track the generated buttons or snooping into the button. Also you may want to present a different name of the library to the user (possibly including the version information) than is used to identify the library. Using the "ActionCommand" property of the button may provide a way to separate those issues. So you will need to alter code in the generation of the checkbox menu items and in the listener.
ActionListener actionListener = ... // whatever object holds the method, possibly this
String[] libraries = ... // however you get your library names
JMenu parentMenu = ... // the menu you are adding them to
for (String s : libraries) {
// prettyName is a method to make a pretty name, perhaps trimming off
// the leading path
JCheckBoxMenuItem child = new JCheckBoxMenuItem(prettyName(s), true);
child.setActionCommand(s);
parentMenu.acc(child);
}
The action handler code would be...
public void actionPerformed(ActionEvent evt) {
// the 'current' selection state, i.e. what it is going to be after the event
boolean selected = ((JCheckBoxMenuItem)evt.getSource()).isSelected();
String library = evt.getActionCommand();
... process based on library and state here...
}
Definitely read over this: http://java.sun.com/docs/books/tutorial/uiswing/misc/action.html
In short, add ActionListener to the menuItems. In the actionPerformed method, use event.getSource(). You can add the SAME ActionListener to all your menu items if you want.
event.getSource() should do it.
When you build the menu you can pass the Action object to the JCheckBoxMenuItem configured with whatever options you need for given action (you can also push there the reference to the check box to check the state). This way you will not have to do any kind of processing when the action is actually performed, because the correct action will be invoked.
The clean way to do it is to create a different ActionListener for each. EventObject.getSource is fugly.
I have an Eclipse RCP app I'm working on. It has some view-specific menus and one of the menu items is an item which I would like to display a tick next to when the corresponding functionality is enabled. Similarly, the next time the item is selected, the item should become unticked to reflect that the corresponding functionality is disabled.
My question is this: how do I set the toggle state of these menu items? I have an IHandler to deal with the event when the menu item is selected but I'm unsure how to update the GUI element itself.
Does the StackOverflow community have any thoughts on how I might solve this?
The solution involves having the command handler implement the IElementUpdater interface. The UI element can then be updated as so:
public void updateElement(UIElement element, Map parameters)
{
element.setChecked(isSelected);
}
updateElement is called as part of a UI refresh which can be invoked from the handler's execute command as so:
ICommandService service = (ICommandService) HandlerUtil
.getActiveWorkbenchWindowChecked(event).getService(
ICommandService.class);
service.refreshElements(event.getCommand().getId(), null);
Lots more info here (see Radio Button Command and Update checked state entries)
Maybe things have changed, maybe there's a difference between RCP and an Eclipse plug-in, but I just set the style of my action to toggle, and it handled the toggling automatically. You can see the source code on github.com.
<action
class="live_py.EnableAction"
id="live-py.enable.action"
label="Li&ve Coding"
menubarPath="pyGeneralMenu/pyNavigateGroup"
state="false"
style="toggle">
To see whether the feature is currently enabled, I just look up the action by its id, and then call isChecked().