Multiple button with multiple actionlistener - java

I am doing a small Java project and using MVC graphical user interfaces to write.
In this project I have dozens of button with different function.
Since I am using MVC to write, I won't use anonymous class listener. I would separate the actionlistener class in the Controller class. As I have dozens of button ,that mean I need to create dozens of actionListioner class for it??
If there is any way to simplify the code?

MVC is a structure to make easier to trace projects. It should not be a problem I think. Research please there are lots of information about it. You should use e.getSource(). Try this:
JButton b1;
JButton b2;
public void actionPerformed(ActionEvent e) {
if (e.getSource() == b1) {
// Do something...
}
if (e.getSource() == b2) {
// Do something else...
}
}
Please look these:
One action listener, two JButtons
How to add action listener that listens to multiple buttons
http://www.java2s.com/Tutorial/Java/0260__Swing-Event/Useoneinnerclasstohandleeventsfromtwobuttons.htm

This is always a difficult thing for people to get their heads around. Instead of letting the controller worry about the actual buttons, it should be worried about what the view is allowed to do (ie the actions it can perform), which (presumably updates the model).
So, your view would actually handle the buttons events internally, but, instead of changing the state itself, it would notify the controller the a particular state has changed or action has been performed.
This communication would be managed via a series of interface contracts. This means that are particular controller is expecting to control a particular type of of view, but neither care about the actual implementation, so long as the contract between the two is maintained
With this in mind, it then means that your view can do what ever it likes and generate the "events" in anyway it likes, so long as the contract is upheld and you're not exposing parts of your view to other parts of the program which has no reason to reference it

Related

how to implement MVC pattern for word guessing game?

I have some working code for the word guessing game. But I fear it does not confine the design rules especially the MVC pattern. The attached image is my GUI currently. I am throwing around objects from one class to another and I hear that it is a bad style. while I agree with that, I am not able to come up with good MVC pattern approach for the word guessing game or the Hangman commonly called.
The main application will have some like this:
public class Application {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
runApp();
}
});
}
public static void runApp() {
Model model = new Model();
View view = new View(model); //not sure if this correct, some suggest it is valid and some not
Controller controller = new Controller(view, model);
}
}
how would I approach this?
The GUI as seen in the attached picture would be the View Class. This includes all JButtons, Textfield, borders, labels etc. Attach actionlisteners to JButtons in the View class
The controller will pass the events to the model. for example, if some letter buttons are clicked, it would pass that letter "A" is clicked to model and the model will either send instructions to controller to update view or it will update view directly. from my understanding of the MVC pattern, the model class must be implemented and tested separately from view and controller. I do not understand how I can achieve this here. I have complete code available. I need to refactor to confine to MVC pattern. kindly pass on your suggestions.
I think one of the areas you are getting confused over is "responsibility". What is each component responsible for and what can it actually do.
The problem isn't that you are passing Objects around you program, but more that the objects you are passing are exposing parts of your application that the recipient has no business knowing about or should be allowed to manipulate.
What I mean by this is, if you were to pass the "buttons" panel to the "guess" panel, because you wanted to have the ability to allow the "guess" panel detect when a button was clicked, you've exposed the "buttons" panel to an area of your application that has no right to actually see it.
What's stopping the "guess" panel from removing components? Nothing...
Instead, we should use interfaces which determine what each part of the application can and can't do and what information is available to it.
This is where you model comes in. The model determines what information is available, how it can be accessed and what events might be triggered to notify interested parties that the model has changed.
For example. Your "buttons" panel would tell the model that the user has made another guess (in response to the user pressing the button). The model would then raise an event, which would notify the "guess" panel that a change has occurred. The "guess" panel then would update it's state accordingly, asking the model for the information it needed in order to represent the current state of the model (as far as it was responsible for).
You could take a look at
Code to Interface, Access by name and Instance Data
Program to an interface
Now, with the MCV pattern, the view must be able to see the model, the controller must be able to see the view and model and the model doesn't care.
The controller is listening for changes to the view (ie user interactions), which it passes to the model. The model fires notifications about changes to it's state and the view responds to those changes by updating itself as required.
For example, the use clicks a button on the "button" panel. The "button" panel's controller detects this event (probably via an ActionListener), it process this action and updates the model.
The model updates it's internal state and fires some kind of event.
The "guess" panel detects this change in the model (via some kind of listener) and updates it's view accordingly (update the guess's and the image as dictated by the model).
Now, remember, Swing doesn't use a pure MCV pattern, it's controls (ie buttons) are both the controller and the view, so just be careful when playing around with these...
I would start with a HangManModel interface which defines all the properties you want to expose, such as the guesses, the "secret" word and perhaps the number of incorrect guesses made and the state of the game (win or lose) for example.
I would also define the listeners that might be registered to the model, which describes the events that this model can generate. You could use a PropertyChangeListener or even a ChangeListener or define your own, based on your own needs, for example...
public interface HangManModel {
public void addGuess(char guess);
public char[] getGuesses();
public String getSecretWord();
public int getState(); // running, win or lose
public void addChangeListener(ChangeListener listener);
public void removeChangeListener(ChangeListener listener);
}
Now this is just an example, personally, I might be tempered to hide the secret word and expose properties about it (like it's length for example). You could also be tempted to provide a setter for the secret word, so the model could be reset...
This would represent the "heart" of your application, around this, you would build your views and controllers.
EDIT : Working example of MVC (netbeans project, made by me) is download here or download here. Who does not know netbeans : in dist is executable .jar file and in src are sources.
It shows MVC pattern with two different views. On the left, you can left or right click to create circle or square and on the right you can see these squares and circles in table. You can change value (like size or position) of square or circle in table and it is updated into model which updates view so on the left you can see how that square or circle moved or resized.
You have good approach, but you got few things wrong. This is a basic, simple model of MVC :
As here you can see, the model DOES NOT send anything into the controller.
How to build MVC application? Mabye better start with the model. The model should have everything except the input/output handling. All the data, all the logic.
So you should have 3 main classes : Controller, View, Model.
For example you just create form with button which in each hit add one "A" letter into the middle of form.
In View class, you have update method, which paints and/or repaints the count of "A" letters into the form.
When you hit the button, it jumps into the method buttonClicked. This calls method on controller, saying that controller what just happend.
Controller see that and manipulates data in the model (in this example calls the method addA). After this, model should know that he was changed, so he call update method on the connected view class which repaints the count of "A" printed in the middle of form.
Addition
You can have multiple views for one model! We can add one more view, which in top-left corner of form prints the number of "A" used. Model can have list of view instead of just view and when changed, he just updates all of them.
Pseudocode
public class Application {
private Model model = new Model();
private Controller controller = new Controller();
private View view = new View();
public Application(){
model.registerView(view);
controller.registerModel(model);
view.registerController(controller);
}
}
Interestion question... So far I heard about MVP and MVVM design patterns used whithin desktop apps, but I have never seen MVC for this type of apps. However, I just took Spring MVC (the best java web framework) and tryed to apply it on desktop apps.
I would create a front controller that handles all events for the app.
This controller gets an event and sends it to EventResolver.
EventResolver returns back the name or something of a method and class which will play a "controller" role to the front controller.
After the front controller creates an instance of this class and calls a method.
In the method body you call some business logic and return model and id for ViewResolver to the front Controler.
6 Again the front controller analyzes the result and calls an approperiate ViewResolver.
Yes, this is how spring MVC works and I just copied it) But why not to use the best!
There's lots of different flavors of MVC, but they all share the same general idea.
The first thing to understand is exactly what the model is. The job of the model is to handle all the logical code. So in this case, the model will track which letters have been guessed, what the word to guess is, whether the game is over, and how many pieces of the stick man are showing.
Basically, you should be able to simulate the game in its entirety just from function calls into the model.
There's a few ways to pass information from the model to the view. The view could poll the model periodically to see if anything has updated. This method is not very elegant. A simple way that is often effective for small-scale projects is to pass a View object into the Model object and whenever anything changes in the model, refresh everything in the view. It's no big deal for a smaller UI to do this. Finally, you can create a Listener registration system (Observer pattern) to have specific parts of the View subscribe to specific events in the model. This method is what I've done for larger UI projects.
The controller's job is to pass user input to the model. For this reason, the controller and view can often be defined in the same classes. This is okay! It's much better to have your JButtons have a click method that calls the model directly rather than telling some Controller class to pass it on to the model.

Java: How can I "bundle" GUI elements into groups and listen to multiple groups cleanly?

I am not skilled in GUI design. After much thought, research and experimentation I've developed several design ideas but still none that seems efficient. One design has a Session god object register a listener on every UI element when created, and every object that cares about any action registers a listener on the Session object. This seems simple and robust, as all messaging goes through a central location so it's less likely that anything is lost. It's brute force though, and seems cumbersome and inefficient.
Another design attempts to create subgroups of objects that speak to each other. This avoids the huge top-level Session and seems more efficient, but also seems error prone.
I'm trying to implement a framework for reuse where I group buttons with related purposes into toolbars and have a hierarchical approach to listening for actions performed by toolbars with relevant operations to the listener. I've gotten to this so far:
public class EditorToolBar extends JToolBar {
public static enum Command {
ZOOMIN,
ZOOMOUT,
FINER,
COARSER,
RESET
}
private ButtonCommandListener listener = new ButtonCommandListener();
public EditorToolBar() {
super("Editor Commands");
JButton button;
for (final Command cmd : Command.values()) {
button = new JButton(cmd.toString());
button.setEnabled(true);
button.setToolTipText(cmd.toString() + " Command");
button.setActionCommand(cmd.toString());
button.addActionListener(listener);
add(button);
}
}
public void addActionListener(ActionListener pNewListener) {
listener.cActionNotifier.addListener(pNewListener);
}
private class ButtonCommandListener implements ActionListener {
private NotifierImp<ActionListener> cActionNotifier = new NotifierImp<ActionListener>();
public void actionPerformed(ActionEvent pEvent) {
for (ActionListener listener : cActionNotifier) {
listener.actionPerformed(pEvent);
}
}
}
} // class EditorTooBar
and the listeners implement something like this:
public void actionPerformed(ActionEvent pEvent) {
switch (EditorToolBar.Command.valueOf(pEvent.getActionCommand())) {
case ZOOMIN:
// do something
break;
case ZOOMOUT:
// do something
break;
case FINER:
// do something
break;
case COARSER:
// do something
break;
case RESET:
// do something
break;
default:
System.out.println("Unknown EditorToolBar Command: "+pEvent.getActionCommand());
return;
}
I can enhance the instructor for the enum to also include tooltip text, images, etc. I'd like to reuse this design with just a different enum describing other toolbars. Listeners will distinguish different button actions using ActionEvent.getActionCommand() and use Command.toValue(String). I'd like this to extend to a hierarchy of classes that are listening: a superclass may implement a listener for one type of toolbar, and subclass add to that by listening for a different toolbar type. If the event is not from the toolbar the subclass is interested in, it can forward the event to the superclass. To make this work, I need a way to distinguish between one toolbar and another, but preferably without having to check for every button event possible from that toolbar. Ideally I'd like to have a toolbar factory, and just specifying an enum would be enough to fully describe a toolbar. Not being able to subclass an enum adds to the challenge here.
Is this a promising design pattern to pursue? I've not seen it anywhere else yet. Is there a better way that I should be using rather than inventing something that is inferior? A link to other options would be welcome.
Edit: Based on the answer from yash ahuja I should clarify that when I mention hierarchy I mean similar to the way that key bindings are handled (i.e. do you have a binding? No, then does your container have a binding? ... until someone consumes the key event) not the actual class hierarchy.
As a way to encapsulate functionality, consider combining JToolBar, discussed in How to Use Tool Bars, with Action, discussed in How to Use Actions. The example cited here exports a single tool bar. In contrast, the StyledEditorKit, illustrated here, exports families of Action subtypes that apply to the current selection of a text component.
The design is pretty good but if you create a hierarchy of Tool bars then, in a situation where a particular button is clicked on particular tool bar the corresponding action performed for that button may not be accurate. Also at times multiple events can be triggered.
Also there are some tool bars for which it is difficult to identify that under which super class they should belong or if they are implementing features from multiple tool bars you need multiple inheritance which Java does not supports.
Possibly a combination of Strategy Pattern and Factory Pattern could solve these issues. Please rethink on this and design your solution, sorry I don't have exact design or source for your question , I have just put my thoughts for your solution.
Regards,
Yash

GWT: Roundtrip Example With Button Click

I'm having a hard time connecting all the dots with GWT's event-listener model. Let's say you have a Button widget, and when the user clicks it, you want text somewhere else on the screen from black to red (just thinking of a super-simple example).
When the user clicks the Button, a button click event gets placed on the Event Bus, which is configured with handlers/listeners that want to be notified when this event happens. How does this tie into Places, PlaceChangeEvents, and the GWT History API?
If someone code provide a super-simple, but functional code example of this "roundtrip" process, from button click, to firing the click event on the bus, to handling the event off the bus, to updating the appropriate place/history objects, and finally, changing the text to red, I think I'd be able to connect many of the currently-missing dots. Thanks in advance!
GWT has many types of events and it is not easy to really understand them all. Some events occur only in logic, others come from the DOM (and can be used either in capture or bubbling), etc.
Just go one step at the time, as you seem to be trying to mix different events together. (a button click and history events are completely independent events). In general, the idea is that many classes provide different kinds of events, and you connect handler for the ones you care about. Your handlers can then call other classes or generate other events. The code that you want is actually pretty simple, this is the only class that you need in your project:
public class Sandbox_gwt implements EntryPoint
{
public void onModuleLoad()
{
final Label label = new Label("I'm red");
label.getElement().getStyle().setBackgroundColor("#FF9999");
Button button = new Button("click me!");
button.addClickHandler(new ClickHandler()
{
#Override
public void onClick(ClickEvent event)
{
label.getElement().getStyle().setBackgroundColor("#99FF99");
label.setText("I'm green");
}
});
RootPanel.get().add(label);
RootPanel.get().add(button);
}
}
You can see the "flow" if you are really interested by debugging this, but there is no need to do a "manual roundtrip" or anything. The history, BTW is a separate class to listen for the forward and back buttons in the browser itself, plus some other stuff, but is not necessary at all to do what you mention.

How to switch between application's windows and communicate with the controller?

When writing a graphical interface, using Java, what's the appropriate way of switching between the different windows of the application, when clicking a button for example? I.E. what are the windows supposed to be, JPanels, JFrames...? And how do all the components 'see' the 'domain controller' (the class that links the graphical package to the application logic package)?
Any guide or reference would be appreciated.
You start your application with your Controller. In the constructor of your controller, you are going to initialize the first GUI you want to open, lets say GUI_A:
private GUI_A gui_a = null;
Controller() {
gui_a = new GUI_A(this);
}
As you might notice, I called the constructor of GUI_A with one parameter: this. this is referencing the instance of the current class, so this is type of Controller. The constructor of GUI_A has to look something like this:
private Controller controller = null;
GUI_A(Controller ctrl) {
controller = ctrl;
}
This is a simple way to get the GUI known to the Controller.
The next thing you would do is displaying GUI_A:
gui_a.setVisible(true);
If you now want to handle button-clicks, you would do it like this:
First, you add the action-performed method to your button. And, as it is best practice in MVC, you don't want to do logic in your view/GUI. So you also create a corresponding method in your Controller for the action-performed, and call it from your GUI:
// Controller
GUI_A_button1_actionPerformed(ActionEvent evt) {
// Add your button logic here
}
// GUI_A
button1_actionPerformed(ActionEvent evt) {
controller.GUI_A_button1_actionPerformed(evt);
}
Usually you don't need to pass the ActionEvent-var to the Controller, as you will not need it often. More often you would read a text out of a TextField and pass it on to your Controller:
// Controller
GUI_A_button1_actionPerformed(String text) {
// Add logic for the text here
}
// GUI_A
button1_actionPerformed(ActionEvent evt) {
controller.GUI_A_button1_actionPerformed(textField1.getText());
}
If you now want to access some fields on your GUI_A from the Controller, be sure not to mark the fields as public in your GUI, but to create public methods which handle how to display the values.
The preferable way is using Actions. You can attach action to each control. When user action happens (e.g. click on button) the appropriate Action is called. Actions can delegate calls deeper into the application logic and call graphical components (JFrams, etc).
suggestion: use tabbed-panel should do this, JPanel is just a Java container, while JFrame should be the outside windows, they are different things. there should be several JPanels on top of One JFrame. your app can have multiple JFrames.
When writing a graphical interface, using Java, what's the appropriate way of switching between the different windows of the application, when clicking a button for example?
Add an ActionListener to the button. In the actionPerformed(ActionEvent) method, do what needs to be done.
I.E. what are the windows supposed to be, JPanels, JFrames...?
I would recommend making the main window a JFrame and using either a JDialog or JOptionPane for most of the other elements. Alternately, multiple GUI elements can be added into a single space in a number of ways - CardLayout, JTabbedPane, JSplitPane, JDesktopPane/JInternalFrame, ..
And how do all the components 'see' the 'domain controller' (the class that links the graphical package to the application logic package)?
One way is to pass a reference to the object between the UIs.

action listeners and event sources in Swing

OK, so if I add an ActionListener to a GUI element, and it's the only element I use that ActionListener with, does it matter which of the following lines (a,b) I use to get the checkbox selected state?
final JCheckBox checkbox = (JCheckBox)this.buildResult.get("cbDebugTick");
checkbox.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent event){
boolean bChecked =
// (a) checkbox.isSelected();
// (b) ((JCheckBox)event.getSource()).isSelected();
model.setPrintDebugOn(bChecked);
}
});
It makes sense to me that if I add the ActionListener object to multiple GUI elements, then I should use (b).
And in (b), is it OK to blindly cast event.getSource() to JCheckBox, since I'm the one who added the action listener, or should I program defensively and do an instanceof check?
note: this question is in the context of event listeners in general; kdgregory has some good points below specifically re: checkboxes which I had neglected to consider.
I'd do neither.
If clicking the checkbox is going to start some action, I'd attach an ItemListener, then just look at the selection state in the ItemEvent.
However, checkboxes don't normally invoke actions, they manage state. So a better approach is to examine all of your checkboxes in response to whatever does kick off the action.
Edit: some commentary about the larger issues that the OP raised.
First, it's important to realize that large parts of Swing represent implementation convenience rather than a coherent behavior model. JCheckBox and JButton have nothing in common other than the fact that clicking within their space is meaningful. However, they both inherit from AbstractButton, which provides implementation details such as the button's label. It also assumes that buttons are "pressed", and that pressing a button will initiate some meaningful behavior (the action). In the case of JCheckbox, however, the button press is not important, the change in state is. That state change is signaled to the ItemListener -- which is also defined on AbstractButton even though state changes are meaningless to other button types (the JavaDoc even says "checkbox").
One of the things that Swing did get right -- if hard to use -- is the idea of that an Action is separate from the control initiating that action. An Action object can be invoked from multiple controls: a menu item, a pushbutton on a dialog, a keystroke, whatever. More important from a design perspective is that it takes you away from the idea of a generic "listener" that tries to figure out what needs to happen. I've seen apps where a single listener receives input from the entire menu system, for example, and then runs through a big if/else chain to figure out which menu item was pressed. Using Actions means you have more classes, but in the long run gives you a more maintainable app.
Finally, from a usability perspective, there's a difference between controls that maintain state, such as JCheckbox and JTextArea, and those that initiate actions, such as JButton and JMenuItem. I have seen a (web) app where clicking on a radio button takes you to a different page. That's bad. Even if you're planning to use listeners internally, to update the state of some model, you should ask yourself why the collection of GUI elements do not in themselves provide you with a model.
For the case where the listener is exclusive (such as an anon listener), I use (a).
If the listener will be reused (eg, this is an instance of ActionListener) I'll write it as:
#Override
public void actionPerformed(ActionEvent event) {
Object src = event.getSource();
if (src == checkbox) {
boolean bChecked = checkbox.isSelected();
// ...
}
}
If you have several checkboxes and they are processed the same way, then instanceof makes sense.
in (b) to be rigourous, you should indeed do a instanceof check, but it's not that important. I would think both these lines are fine and acceptable, though (b) would be "better code"
Although, what is usually done in an action listener is simply call another method customized to your checkbox. So it would look like something like this:
#Override public void actionPerformed(ActionEvent event) {
//your treatment would be in this method, where it would be acceptable to use (a)
onCheckBoxActionPerformed(event)
}
I'd program with b defensively as it's the best-practice option. But if only you are ever going to use the code then there is no reason why you can't do a. However, imagine how happy you will be with yourself if you come back to it at some future point, change something and find you wrote good code which you can directly reuse...

Categories