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.
Related
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.
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.
I have a general question that is Java related.
I am writing an application that has a GUI menu. I am trying to change one part of the GUI menu based on the selection of a Radio button.
Do I need to:
Redraw the whole window or just update that part with:
setVisible(true)?
If I just use the statement from #1 above .. the GUI is fine -- until I move the mouse over it and then I see the previous button choice. What am I doing wrong?
Swing components have a repaint(), revalidate(), and doLayout() method. One of those should probably be able to redraw whichever pieces you want. However, doLayout is not something that you should be taking responsibility for, that's the layout engines responsibility.
You may also want to check out this post, the first response has a pretty good explanation, and links to an article with more detail.
In terms of the second part of your question, I'm not sure, but we may need to see some code to get an idea. Is the 'replaced area' actually being removed from the view?
..in my application the user select which device platform type they want top test (that choice is a set of two radio buttons on the left). When the user selects either Android or iOS, the center grouping of check boxes changes to reflect a group of android devices they can test or a group of iOS devices that they can test.
Put a panel in the 'center grouping'.
Use a CardLayout for the panel.
Add both iOS & Android controls to the panel with the card layout.
Flip between them as needed.
Call revalidate() on the top level component.
I am trying to write simple vector graphics editor in Java and got stuck with GUI... I have 2 JPanels: First one is for the "canvas area", second one is for the buttons. Canvas area is a Singleton, so then button pressed, it calls method of the Singleton and it adds element to list of the Singleton and re-paints the area. But now, I want to change these buttons to JToggleButtons and don't know how to revert it's state after click on the canvas.
Which design pattern should I use (because I have bad feeling that I'm doing it wrong)?
Have you ever heard of call backs? Once they are understood and implemented correctly, they can work quite nicely.
http://en.wikipedia.org/wiki/Callback_(computer_science)
I like this example too.
http://www.linuxtopia.org/online_books/programming_books/thinking_in_java/TIJ310_019.htm
Make use of the Command and Memento patterns. Implement an Undo Command. Allow commands to store state in the form of a Memento. Restore the state from the Caretaker when you find fit.
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.