Disable a JComboBox based off the item of another ComboBox - java

So here is what I am trying to do. If a user selects an item in JComboBox1, I want to be able to disable JComboBox2. But only if they select "Unavailable". I have read stuff about action listeners and so forth, but is there just a way for me to use like an if statement:
Here is what I was thinking:
if (jComboBox1.getSelectedItem().equals("Unavailable") == true) {
jComboBox2.setEnabled(false);
}

That would certainly work, but you would have to call that piece of code periodically. Much better would be to use an ActionListener - it will definitely help you in the future. You have to create a class which implements the ActionListener, such as
//This class should be a private class inside the class which holds the JComboBoxes.
private class DisableActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JComboBox cb = (JComboBox)e.getSource();
if (cb.getSelectedItem().equals("Unavailable")) {
jComboBox2.setEnabled(false);
}
}
}
For this to work, you have to attach the ActionListener to the first JComboBox - the ActionListener is no good by itself! To do this, use the addActionListener() method on the JComboBox, adding an instance of this newly created class.
Now, to dissect the code:
private class DisableActionListener implements ActionListener
Here, we create a class which implements the ActionListener interface. With this, we are creating our own model of an ActionListener. When you implement an interface, you have to override all of the interface's methods, so we have to override the standard actionPerformed(ActionEvent e) method on the interface. This method is what will be called whenever you select or deselect an item(an ActionEvent will be dispatched); therefore, you have to put the logic of what you want to happen inside this method.
JComboBox cb = (JComboBox)e.getSource();
Every ActionEvent which causes the actionPerformed() method to be called will contain extra data. One of the pieces of the data is the source of the ActionEvent - what made this action happen? In this case, we know that the source is a JComboBox since we only attached the ActionListener to the JComboBox, so we can cast the source of the ActionEvent, which is an Object, to the JComboBox which sent the event.
The rest is the if logic you wrote yourself, with the syntax error fixed:
You wrote
(jComboBox1.getSelectedItem().equals("Unavailable") == true),
but the equals() method on the String already returns true, so the (== true) part is an unneeded redundancy. In your case, you basically get (true == true).
Anyway, hope this helps!

Related

implement ActionListener in the same class for three buttons

I have three buttons in a frame, two of which I want to edit a String with, which is a package public member in the main Class (Lab2TestDrive), something like
public class Lab2TestDrive{
...
String cale;
public static main void(String[] args){
JButton button1.. button2.. button3..
}
Can I implement an ActionListener on Lab2TestDrive, and override the actionPerformed(...) method in there? But if I do that, I don't know how I would be able to know which button triggered the actionPerformed method.
I know I could make a separate class,
public class ButtonListener implements ActionListener {
JButton button;
ButtonListener(JButton button){
this.button = button;
}
#Override
public void actionPerformed(ActionEvent arg0) {
if(button.getText().equals("Save")){
};
}
}
But then I don't know how I could access the "cale" variable :(
First: You should not let your ActionEvent be called arg0.
Then: You can technically do it all in one class. Your ActionEvent parameter has a method called getSource() which will get you the button that fired the event.
In theory, you could also create a third class storing your cale variable and give a reference to that class as a parameter to the constructor of your listener.
However, that seems very unintuitive.
You could also give a reference to your Lab2TestDrive object to the constructor of your Listener and then call a method from that class from within your actionPerformed.
Truth be told, none of those options really strikes me as great coding practice, but they should all work.

ActionEvent confusion

I'm very new to Java and I'm confused about the ActionEvent class.
I was under the impression that to use a class you had to create a new object for example:
SomeClass aClass = new SomeClass();
But in this piece of code:
private class theHandler implements ActionListener{
public void actionPerformed(ActionEvent event){
Event.getSource()
// etc...
}
}
How come you don't need to:
ActionEvent event = new ActionEvent();
Event become an instance of the ActionEvent class without having explicitly tell it.
I'm sorry of this is a dumb question, I'm teaching my self Java, and this is thoroughly confusing to me.
ActionEvent is created somewhere, but it's just not being created explicitly by you. Rather, it's being created in the JButton's code (actually the code is in the AbstractButton class, a parent class for JButton) for notifying all ActionListeners that listener are attached to it. You can view the source file to see the details if you desire.
When you use implements in Java, what you are doing is using an interface. Interfaces require certain methods to be implemented in your code and offer a way to ensure new classes that implement a certain interface have methods that can be called.
Thus, in your example:
private class theHandler implements ActionListener{
public void actionPerformed(ActionEvent event){
event.getSource()
// etc...
}
}
The ActionListener interface is being implemented by theHandler and therefore the method, actionPerformed(ActionEvent event) is required to be implemented by your class. There is no explicit ActionEvent event = new ActionEvent(); being created here because the ActionEvent is actually being passed through as a parameter to actionPerformed and is otherwise being created somewhere else.
Specifically for your example, you can also do the following instead of using the implements keyword on your class:
public class theHandler {
public theHandler() {
JButton button = new JButton();
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// do some stuff here
}
});
}
}
It's really quite simple, there is a thing called static methods. These are methods you can use from a class without making objects of them.
Like the Math class and all it's functions fx. a static method could look like this:
public class HiClass {
public static String sayHi() {
return "Hi!";
}
}
You would then use it in some context like this:
System.out.println( HiClass.sayHi() );
This would print out the string the method returns in your console.
You might ask "why wouldnt I just make all my methods in my classes static then?" there are many reasons, main one I can think of is that when you program you always try to restrcit responsibilities to classes that makes sense, so that the code is more manageable and easier to alter as the program grows.
This is not specific to the context your mentioning though, but it seemed to me your real question is how you can use methods without creating an object?
Hope it answers your question?

Syntax of adding an action listener

When I enter the following code:
JButton aButton = new JButton("Button");
aButtin.addActionListener(this);
my IDE (NetBeans) highlights this as a leaking this statement.
Though there never seem to be any negative repercussions from using the statement as such, some docs that I have read indicate that the more proper method is to add the action listener as a new instance of an inner class that implements ActionListener.
What do NetBeans and these docs know that I don't?
What is really meant by a leaking this statement?
Are there negative repercussions that I am unaware of in the use of this in this way?
there are three ways
aButton.addActionListener(this); in the case that class declarations contains implements ActionListener and there is public void actionPerformed(ActionEvent ae) { too
f.i. pseudocode
public class ButtonDemo implements ActionListener{
aButton.addActionListener(this);
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == aButton) {
}
}
}
aButton.addActionListener(new ButtonPress()); is in the case that ActionLIstener is declared as separate class
f.i. pseudocode
public class ButtonDemo {
aButton.addActionListener(new ButtonPress());
}
public class ButtonPress implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
}
}
simpler, clear and without side effects (a.m. two ways) is to create inner anonymous listener
f.i. pseudocode
aButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
If you use this, then in order for this to handle ActionEvents from multiple sources you need to add logic to check the source or command string of the action. This is perfectly reasonable.
If you use other classes, then you can use ActionListeners that are implemented elsewhere, or reuse ones that were designed for a specific common purpose, or define e.g. anonymous inner classes inline which may be convenient in your situation. This is also perfectly reasonable.
Do not think in terms of "advantages" or "disadvantages" -- this is such a common mistake (Is it "bad" to do xyz? Is xyz "good practice"?). You use whatever makes the most sense for your situation and provides the clearest, most maintainable, properly functioning code. Have common sense, be familiar with the language you are working in and the options available, make sane judgments. A language is a way to express an idea, speak (type) clearly.
I guess one disadvantage of using the inner class implementation is that the listener cannot be reused for other buttons , in case, they should have the same listener.
Something like this :
Can you use the same OnClickListener for different buttons?

Method to add ActionListener

Let's say I have a button called button1. If I want to create an actionListener for the button which method should I choose: (In the second one, you have to extend actionListener interface)
// Imports
public class Test{
JButton test = new JButton();
Test(){
// Pretend there is an adapter
test.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
...
}
});
...
}
or
// Imports
public class Test2 extends ActionListener{
JButton button2 = new JButton();
Test2(){
button2.addActionListener(this);
}
// Pretend there is an adapter
public void actionPerformed(ActionEvent e){
Object src = e.getSource();
if(src == button2){
...
}else{
...
}
}
In the second case, you have to implement the ActionListener interface. Other than that, the answer is "it depends". If it makes sense to reuse the same action listener for several graphical components, then use the second version. If handling the event is a one-shot affair for a single component, then use the first version.
Go for the first. You shouldn't have your GUI classes also implementing your listeners as this is asking the GUI or view class to do too much. By separating out your listener code, even if it's in an anonymous listener class, you'll have an easier time later should you want to completely separate your listener code from your view code.
If every listener is unique, you'll probably want to use the anonymous classes (first example). If you would otherwise have to rewrite the same code over and over again, then implementing it in a named class (as in your second example) would be preferable so you can just reuse the same listener.
However, rather than extending ActionListener (as in your second example), you'll probably find that putting the listener implementation into a different class (even an inner class which implements ActionListener) provides better logical logical separation of your code.

What is the difference between addActionListener(this) and addActionListener(new ActionListener)?

I want to add event handling to buttons- and I noticed that there are two ways to do this.
Implement the ActionListener interface and then append event listeners to the buttons.
Example:
countButton.addActionListener(this);
And the in the ActionPerformed method will run to display the result.
Do not implement the ActionListener interface and instead do this:
countButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
//Execute when button is pressed
System.out.println("You clicked the button");
}
});
How does the second method work exactly?????!!!
Thanks!
It is not necessary to define a second class for the first approach. You just need to add the
public void actionPerformed(ActionEvent e) method inside your class and do whatever you want there, after you make your class implement ActionListener. You could use a second class if you wanted to, but it is not necessary. The disadvantage is that you need to specify the source of the event with long if statements in order to take the appropriate action if you have more than one JButtons i.e.
The second approach is adding an anonymous inner ActionListener to every component. It is a more Object Oriented approach, since you have a clearer separation of the functionality of your widgets. It is of advantage to define an additional method called inside each actionPerformed, in order to be able to use this freely and refer to the containing class:
countButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
doCountButtonAction(e);
// "this" here would refer to the ActionListener (not that useful)
}
});
and implement the method:
private void doCountButtonAction(ActionEvent e) {
// do whatever you need to here
// using "this" here refers to the containing class (i.e. JFrame, JPanel or whatever)
}
Your question is not exactly on listeners as it is on how interfaces work and how you can instantiate a class in Java. Here's some finer points:
Basicaly, what the JButton class offers you is a way to declare a class who's one particular method will be called when an event is triggered on the button, like when it is clicked. If you look at the Javadocs for JButton and ActionListener, you will now how they work:
http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/AbstractButton.html#addActionListener(java.awt.event.ActionListener)
http://download.oracle.com/javase/1.4.2/docs/api/java/awt/event/ActionListener.html
What you can do here in the most old fashioned way possible is to create a class that will be triggered when someone clicks your button:
public class MyButtonActionListener implements ActionListener {
actionPerformed(ActionEvent e) {
System.out.println("Aww, you clicked!");
}
}
Now, once that's done, you can make an insance of it and add it as a listener to your button:
JButton button = new JButton("My button");
MyButtonActionListener myActionListener = new MyButtonActionListener ();
button.addActionListener(myActionListener);
On the other hand, in Java you can instantiate a class anonimousy, which means that instead of having a handler to it's instance (like myActionListener in the above code), you just instantiate it on the fly in the place you need it, and you'll have no handler to use it later. That's what's happening in your code: an ActionListener implementation is delcared on the fly as the parameter for the addActionListener method, that on the fly declaration also includes the statement that your anonymous instance is not just any class, but one that implements ActionListener, and such your anonymous declaration needs to give an implementation of the actionPerformed method.
A third option is to have a class that implements ActionListener (and the actionPerformed method), and inside that class, if you create a JButton and you want to pass it as listener an instance of the ecompasing class, you'll use "this" to reffer to that, as in :
public class MyButtonActionListener implements ActionListener {
private JButton button = new JButton();
public void init() {
button.addActionListener(this);
}
public actionPerformed(ActionEvent e) {
System.out.println("u clicked!");
}
}
There's alot of finer points to this discussion (as in how do you reffer to the "this" on a n anonymous class delcared inside an other class, and how do you reffer to the "this" of the encompassing class instance). I recommend that you read a book on the Sun Certified Java Programmer certification, it has a chapter dedicated to this
That just creates an anonymous class that implements the actionPerformed method. This way you don't have to define a new class for every place that you want to handle an event.
It works the same way as the first technique i.e. The method expects an object which implement ActionListener interface. However, both techniques has its own merits and demerits. The first technique allows utilizing single object on the expense of cluttered if/else code because same method will be handling events for multiple buttons. The second technique allows cleaner separation of logic for each button on the expense of creating multiple anonymous objects (for each button).
Either way, to add an ActionListener you need a class that implements the ActionListener interface (which defines a single method, actionPerformed). addActionListener(this) implies that this implements that interface, and any action performed will call this.actionPerformed.
In the second case, what you're doing is creating a new, anonymous, class that implements the ActionListener interface. When countButton is clicked, the actionPerformed method called is the one in the anonymous class.

Categories