A shout out to the Swing gurus out there!!
I've been doing Swing programming for several years but have always been unclear on this.
As you know Swing/AWT gives you several ways to execute a particular action when a button is clicked. I've seen it done several different ways in the applications I've worked on. The project I'm currently working on tends to follow this approach:
someButton.setActionCommand("mycommand");
someButton.addActionListener(listener);
--snip--
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand();
if (command.equals("mycommand"))
doThis();
else if (command.equals("someothercommand"))
doThat();
etc.
This seems kind of clunky to me - is there any benefit to this style of programming, or is it better to use Swing Actions?
Or are there different situations where the different approaches are better/worse?
IMO, it is better to use separate listeners for Actions.
That way you leave the delegating of what action should happen up to Swing. You don't have to compare Strings to decide what to do.
Having one huge ActionListener for more than one action feels like breaking the pattern to me.
From a design point of view, I think it is better to have one class to handle one specific action for a component as opposed to one class that is a "lets handle everything for all components here" type of design.
Also, if you use Action you can a) apply it to more than one component (e.g. a button and a menu item) b) call setEnable to enable/disable it for all components its attached to and c) Also use it to define various settings on the components its attached to (namely, the text label, the tooltip text, the accelerator key, icon, etc.). This last one is done via the putValue method and calling this method again will change the settings for all components its attached to.
Specifically, I would advise to subclass AbstractAction for your needs.
I know that's demo code but since you're working on this stuff I thought I'd mention that swing tends to be really repetitive if you're not careful.
Using Action classes tends to let you refactor better. In swing, one of the best ways to start is to ensure that NO strings are in your code. Nearly every "New" will be in a loop of some sort, reading from a dataset (Often the dataset is as simple as an array)--Once you start reading from a dataset like that, actions can help you a lot.
You use data to create your action, data to create your control, and data to associate the two--in this way you can end up very close to (or at) 0 lines of code for a new control.
Once you start programming this way and can see the patterns, it's at least as quick as the repetitive way and much less error prone.
its Useful if you have several buttons or components that perform the same action (ie. several exit buttons on the same page will use the same code)
Set them all to the same action command and they will all use the same code in the listener
JButton.addActionListener(this);
JButton2.addActionListener(this);
JButton.setActionCommand("exit");
JButton2.setActionCommand("exit");
public void ActionPerformed(ActionEvent e){
if(e.getActionCommand=="exit")
System.exit(0);
}
Related
I'm working on one of my first java applets and I want to start of fairly simple (though I have a good understanding of how code works I dont know much in terms of what methods I all have at my disposal when using java)
I have created a Jframe window that has a JTextarea in it. I would like to execute certain lines of code when certain things are typed into this box. In essence, its a simple text input system. How would I go about doing this or is there a better component to use for this?
in addition to getText(), for JTextField some prefer the getDocument() method. In Java, Listeners are used to capture events, such as "what was typed to the text area". This tutorial will get you started, if you have trouble implementing you can come back with a more specfic question and some code :)
I want to make an app, which will work as interface to several servers.
Why: In web iface provided by default (and we cannot change it) are few things we miss, few could be done better and for sure automation of some stuff would make the job easier.
What do I have: almost finished classes for communication with web interface of a server app.
GUI description:
For some kind of version 0.1: text field for username, radio button to select server and one "go" button. Then several (4-12) action buttons to operate on data, 2x text area with results, one label with some text data - I can manage this.
Then I need to view the data - grid MxN which will load the data, expected size: 7-15 columns, usually 10 rows or less, but rarely it can go over 1k (or even more, but I don't need all to be visible to the user in that case).
What I need: simply an advice.
I wish to start with a simple version (and I'm working on that already, but I'm stuck on too many things - 95% cos and absolutely new to GUI and 5% cos I'm new to java).
I've checked many tutorials, but they're all simple.
Real questions:
1) Verify. In MVC controller should handle all user actions - is it done by view's method which is something like button.addActionListener(param); anotherButton.addActionListener(paramp; ...?
1b) I've seen all implemented via one (nested) class, which was then checking source or smth - is that ok? There will be a lots of buttons etc.
2) How to implement the data grid, when I need to take actions on click / dbl click?
4) First row is header, the rest should be scroll able - should it be in the grid or outside (its own grid):
4a) How to make sure header's size (width) will be the same as in data (I don't want to set up straight size)
4b) I failed to create anything scrollable so far, but thats my bad I guess. How to ensure header will hold on a place and the rest can be scrolled?
5) How should be "data update" implemented? I've got JPanel from which I remove grid component and then I make new one and add data into it (simple, but perhapss there is another way). One of first enhancements will be sorting - use the same way I used for new content?
Thanks a lot for any answer, I know this is not very specific, but example I've found are too simple.
I plan a lots of enhancements, but thats in the future and I don't mind to rework GUI/Controller several times, at least, I'll practise, but I don't want to finish one part of the code and realise I've got to rewrite half of a controller and 1/4 of a view to make it possible.
Note: I plan to use this at work as my tool (if things go right, I could make 25-50% of my work by few clicks :-)
So I really mean this).
Note#2: I'm not new to programing, but I've never created GUI (which is why I've got GUI with menu bar with 2 items and 3 components and almost done web-iface connections).
Note#:3 dragable data header, tabbed data view - thats the plan for the future :-)
MVC in Swing is examined here; use nested classes for ease in prototyping and creating an mcve for future questions; as the need arises, nested classes can be promoted to separate classes having package-private access.
Use JTable; its flyweight implementation of renderers is good for organizing data by row and column.
Item three does not exist, but "always remember to translate cell coordinates" if you plan to drag columns or sort rows.
Use a JScrollPane to keep the table header stationary.
Update the TableModel, and the listening view will update itself in response.
If you are interested not only from the event/messaging architecture, but also on handling mouse/keyboard input, hovering detection, widgets, temporary menus, form re-sizing with widget alignment, dragging and dropping etc. I can advice you to look at this question and my answer with helpful resources.
I am doing a simple GUI painting box program.
However, I have a problem with adding 2 similar separated groups to be corresponding in the same way.
I mean when I click the JRadioButtonMenuItem Line, then the JRadioButton Line below also has to be selected too. What should I do?
Do you need to see my code?, please let me know
Thank you so much.
P/s: it says I need 10 reputation to post image
Share the model between the two radio buttons:
JRadioButton radioButton = new JRadioButton("Line");
JRadioButtonMenuItem radioMenuItem = new JRadioButtonMenuItem("Line");
radioMenuItem.setModel( radioButton.getModel() );
Actually, you should share the Action as well between the two components. Read the section from the Swing tutorial on How to Use Actions for more information and examples.
The exact solution depends a lot on how your code is structured right now. I bet that the standard library has some functionality to accomplish what you want to do, but if you want to go ahead and implement it then you might as well (minimal time input and you learn something).
The most direct solution that comes to my mind is to encapsulate selecting a button in a method that will manipulate all sets of corresponding buttons. I am going to assume that you are using action listeners for the buttons right now, if not you could adapt the idea. In the action listener, you can detect the mouse click and perform some work as necessary. That work should include updating the other buttons appropriately too. You could even create a method that both action listeners call and updates all necessary sets of buttons.
It is also possible to use the same action listener on both sets of the buttons, but you'll need to know which selection the user wants to be active (likely an easy task).
My Java is pretty rusty, so I am not including any example code, but if anything is unclear or you think an example would help I can do so.
Hope at least something here helps you. Good luck!
I've been developing java programs for 1½ year. I'm currently working on a summer project, that involves quite a big Graphical User Interface.
My GUI consists of several tabbed panes. Each pane has its own class. Each pane has SEVERAL jButtons.
Now, I've come to a point, where there's so many anonymous inner classes (for ActionListeners) in my tabbed-pane classes, that I am certain there must be a better way; if not for efficiency, then for maintainability - it's becoming quite a mess.
My question is this: Is there a better to organize listeners, when you have a lot of them in each class? I've thought about clustering the listeners in relevant classes - like the following sample code:
public class SomeListeners implements ActionListener{
#Override
public void actionPerformed(ActionEvent e){
String command = e.getActionCommand();
switch(command){
case "This button":
doThis();
break;
case "That button":
doThat();
break;
}
}
}
Or might there be an even better way?
Thanks in advance :)
You could try the following approach:
Use real classes instead of anonymous classes. Every ListenerClass implements only one Use-Case / Functionality. The Classname should describe the UseCase. Then you can organize the classes in one or more packages to cluster them by categories that fit to the Use-Cases that the Listener in the package implements.
That means, you create an hierarchy of abstraction, that organizes the functionality like a tree-structure.
If some day later somebody has to maintain the Listeners he/she can find the Listener by first looking for a package that fits to the UseCase and then for the UseCase itself. Since you will have less packages then Classes it will be easier and faster to find the Listener.
Another way to think about that: If you have so much Events on one Tab, that you get
problems organizing them in the code, how do you organize them visually on the Tab? Can you handle that in an ergonomic way for the user? Maybe the solution could be in splitting the functionality on more then one Tab? But since I don't know your UI I cannot say too much about that
I would recommand to use single class from type javax.swing.AbstractAction
Example:
Action leftAction = new LeftAction(); //LeftAction code is shown later
...
button = new JButton(leftAction)
...
menuItem = new JMenuItem(leftAction);
leftAction = new LeftAction("Go left", anIcon,
"This is the left button.",
new Integer(KeyEvent.VK_L));
...
class LeftAction extends AbstractAction {
public LeftAction(String text, ImageIcon icon,
String desc, Integer mnemonic) {
super(text, icon);
putValue(SHORT_DESCRIPTION, desc);
putValue(MNEMONIC_KEY, mnemonic);
}
public void actionPerformed(ActionEvent e) {
displayResult("Action for first button/menu item", e);
}
}
Per duffymo: Use dependency injection and pass in the Listeners. This will give you the opportunity to reuse and change them at will.
Per me (hovercraft): It doesn't have to be Spring as Guice would work just fine. And it would work well with treeno's suggestion as well as Tim Herold's suggestion (1+ to them both). It's all about loosening coupling and tightening cohesion as best possible.
At some point, anonymous inner classes go from "convenient" to an evil mess. You have passed that point.
Like Tim, I suggest you use an AbstractAction. However, to expand, create your own abstract subclass that can read its name, icon, description (for tooltips) etc. from a configuration file. That way you can internationalize the code, and others (marketing) can easily change the buttons from "Save" to "SuperSomethingTM" or whatever. And the graphic artist can easily modify the icon. Extend this class for the actual implementation.
One added advantage of AbstractAction is that they can be disabled. So, if there are no changes to be saved, you can easily disable the Save menu, the Save button and the Save icon in the toolbar.
There are various ways to store and read this config info. One is a ResourceBundle.
(Typed on my Nook so this is on the short side, others feel free to expand)
something like as this code
public class SomeListeners implements ActionListener{
#Override
public void actionPerformed(ActionEvent e){
String command = e.getActionCommand();
switch(command){
case "This button":
doThis();
break;
case "That button":
doThat();
break;
}
}
}
talking about EventHandler, theoretically any String, or their combinations in the hierarchy, real componets tree can creating void "do" + "Th" + "is"();, there you can to compare required chars neede for standard ActionListener
output from EventHandler should be Swing Action only, override setEnabled as another params in EventHandler
JSR 296 was meant to provide a framework for what you are doing and many other things that have been mentioned here (i18n, Actions, etc). The most active implementation is the Better Swing Application Framework, or BSAF. A good article on how to use any JSR 296 implementation can be found here.
I've been tasked with making a GUI that essentially takes a bit of user input and does some folder/file manipulation on various drives accessible by the machine the program is being run on. While designing this GUI, I'm starting to realize that MVC will make my life much easier and anyone else who decides to modify code, but I can't really see how this can be done via NetBeans.
I've done a bit of reading up on this topic, and I can't really see any clear cut answers as to whether or not this can be done on NetBeans. Surely it can be done if I programmatically build the GUI, but that somewhat defeats the purpose of why I chose to use NetBeans.
Netbeans is fine to do this.
The key thing to realize is that while all of the basic Swing components are MVC, for the most part you don't interact with them that way. A simple text field has it internal model, but that model isn't your model, the text field is more a primitive.
Your model deals with higher level events (button actions and what not), rather than button presses and arrow moves and mouse clicks.
So, for high level MVC, the primary mechanism of communication is through PropertyChangeListeners. And the basic task of building your app up is wiring the PCLs of the assorted data elements along with their GUI components together.
For example, a simple case is you have a list of items. And that list is rendered on the screen via a JTable, and that table is on a JPanel.
Your list has it's own model, i.e. it's not simply a Java List. It's not a List because standard Java Lists don't support PCL notifications. But your Model would obviously wrap such a List.
Now, the next question is how do you wire up JTable to be associated with your List model.
One, you could subclass JTable and bind it to your Model. Or, more simply, you use the JTable as a primitive, and let the enclosing JPanel manage the interaction between your Model and the JTable.
That means having your JPanel implement PropertyChangeListener, and then, when wiring everything up, you do something like this:
ListModel myModel = new ListModel();
ListPanel myPanel = new ListPanel();
myModel.addPropertyChangeListener(myPanel);
Now, whenever your ListModel is changed, is will notify the ListPanel.
On your ListPanel you can having something like:
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(ListModel.CHANGED)) {
ListModel model = (ListModel) evt.getSource();
DefaultTableModel tm = (DefaultTableModel) listTable.getModel();
tm.setRowCount(0);
for (String s : model.getList()) {
tm.addRow(new Object[]{s});
}
}
}
Now, you can see this simply reloads the entire table model, but you can make your property changes as fine grained as you want. You can also see that if this was some other model (like a Person or something) you can populate individual text fields and whatnot on the panel.
This is a pretty simple GUI, but it shows the fundamentals of how this all wires together. I think a bit of this is lost in the Swing examples which are great for one panel screens but don't scale at all when you start adding other views.
Your JPanels basically become combined VC, as your GUI gains complexity you can factor those kinds of things out, but its works pretty well for reasonable amounts of screens and such.
There are two ways in which Netbeans can help you leverage its codebase: GUI Builder (1) and NB Platform (2).
(1) Netbeans had for a while one of the better drag-n-drop GUI builders in the Java world, codenamed Matisse.
That said, it's been a long time since I worked with it - and I never really liked the generated code, it wasn't very comprehensible (which of course is not the purpose of auto-generated code). For more complex UIs we hand-wrote the layout and the work was bearable, even if not the most pleasant. For simple UIs, I'd try GUI Builder again, for complex UIs with a lot of wired logic, I'd probably still would write it by hand.
To see how the GUI Builder works, take a look at one of the many tutorial videos, e.g. this one:
NetBeans GUI Builder: Adding Components
(2) Netbeans Platform is to Netbeans, what RCP is to Eclipse. A rich set of components developed for an IDE, that can be reused. I briefly looked into NB Platform and we would have used it, if the project didn't change course. Maybe this SO question can shed more light on this aspect: Which Rich Client Platform to use?.
Concerning MVC. There was JSR 296, a generic Swing Application Framework, that looked somewhat promising, but was withdrawn in 2011. That did not stop people to fork it and work on it, as this project shows: Better Swing Application Framework, with a release in mid 2012. Even if you do not use such a framework, please do not put all code in one class (as you mention in you comment), but create a simple model/controller and keep the UI components separate. It does not need to be fancy for a simple app, a minimal MVC-ish separation of concerns might suffice.
I also hit this problem and i found a link which gives a good example how to seperate the controller from the view using the NetBeans GUI builder.
Here is the link.