I'm trying to create a sub-class of the JButton component that will enable or disable itself based on a condition (which looks like below)
public interface Condition {
public static final Condition TRUE = new Condition() {
public boolean test() {
return true;
} };
public static final Condition FALSE = new Condition() {
public boolean test() {
return false;
} };
public boolean test();
}
However, the JButton code is all based on the actual boolean value stored privately in the JButton class. My question is: which method of JButton can be overridden to update its stored isEnabled boolean (via setEnabled(boolean))? Would it be update(Graphics)? or repaint()? OR some other function?
Edit: Realized that what I'm trying to create is actually impossible, unless you have a separate thread that waits short periods of time and forces the button to check its status (which is gross and I don't want to do that). The fact is, buttons are reactive only. It would be possible to accomplish this with some overhead by whoever uses the button class, but at that point it'd be easier to just write listeners on whatever is actually changing and toggle the button at that point. Woops.
The DefaultButtonModel, for example, maintains a stateMask, which includes a bit for the enabled state. You could implement the ButtonModel interface accordingly.
Addendum: As an alternative, and as noted in the article Key Bindings, "Another advantage of Actions is that they have an enabled state which provides an easy way to disable the action without having to track which component it is attached to." See How to Use Actions for more.
I strongly suggest using Actions to implement such a feature.
You should enable/disable action attached to your button. In Swing same action can be associated with many types of components such as buttons, menu items etc. By disabling a specific action you will automatically disable all associated components.
This becomes very convenient when you have toolbars, context menus etc with the same set of actions.
Related
Pardon my question if it may seem stupid but I'm curious. I am making a program in Java of which will have a GUI, and am curious about the whole idea of properties. Why use them when we can just add data to a class? For example:
class myButton extends Button {
private boolean booleanProperty = false;
myButton(args...) {
// Do something with the property
}
public void setProperty(boolean value) {
this.booleanProperty = value;
}
public boolean getProperty() {
return this.booleanProperty;
}
}
Seems to work just fine for storing additional information on the custom implementation of the button. But what about:
class myButton extends Button {
private SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(false);
myButton(args...) {
// Do something with the property
}
public void setProperty(boolean value) {
this.booleanProperty.set(value);
}
public boolean getProperty() {
return this.booleanProperty.get();
}
}
The only real difference, I am seeing (correct me if I'm wrong) is that that you can attach listeners to the property values, but I feel as if there has to be more than just that. Ideas?
The power of JavaFX's properties is that they can be bound in ways that will automatically update the UI when a change occurs.
As an example consider an element you want to hide if a textField contains no value:
TextField tf = ...
Node container = ...
container.visibleProperty.bind(tf.textProperty.isNotEmpty());
Now as you change the text in tf, you will see container switching whether its visible based on the presence of text.
They really are useful in a lot of ways I even started them using in non UI related stuff. But look at this example: You habe an undomanager class
public class UndoManager {
BooleanProperty canUndo = ...;
BooleanProperty canRedo = ...;
...
}
And you have 3 places from where you can invoke undo/redo.
MenuButton menuUndo;
Button toolbarUndo;
MenuButton contextMenuUndo;
You basically only beed to do this:
menuUndo.disabledProperty().bind(undoManager.undoProperty()):
toolbarUndo.disabledProperty().bind(undoManager.undoProperty());
contextMenuUndo.disabledProperty().bind(undoManager.undoProperty());
and you dont ever have to worry about it again. If you add a new place where an undo can happen you just have to bind it too.
In this case you don't have a benefit, since you do not allow access to the property object itself. Usually this is done.
This allows you to add listeners to the property and be notified, when it changes.
Bindings are using this possibility to keep values the same and properties as well as the Bindings class provide methods for simple conversions of properties.
BooleanProperty booleanProperty = new SimpleBooleanProperty();
booleanProperty.addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
System.out.println("property changed form "+oldValue +" to "+newValue);
}
});
booleanProperty.set(true);
booleanProperty.set(true);
booleanProperty.set(false);
booleanProperty.set(false);
booleanProperty.set(false);
booleanProperty.set(true);
booleanProperty.set(false);
booleanProperty.set(true);
booleanProperty.set(false);
Furthermore it allows you to pass an object representing the property. E.g. code that has to write/read booleanProperty does not need information about the myButton to write/read the property; you can just pass the property.
TableView is an example of a class that makes use of propertys. The columns used with TableView get a property from the items in the TableView and TableView registers a listener to that property. This allows it to change the values displayed in the cells even if the changes are triggered somewhere else in the code. Also for editable cells the properties of the items can be automatically modified.
The use of a javafx property for a pre-made object to hold an arbitrary value for later use. So you can set values to a text field or some other object that doesn't directly effect the shown value
Imagine programming a robot that would take care of resturant customers. How would it respond to customers or any other tasks that would have to be taken care of without using something like property listeners.
The benefit of using property listeners is that you can make your program become Concurrent. If there are no customers coming the next 1 hour your otherwise Sequentially made program would stand and do nothing for the next hour. Maybe switching the word Concurent with flexible in this example would be better, but you should look up Concurent programming and Sequence programming. Those properties allow you to customly make your program concurent.
You should also know that the gui you are using are already use built-in (event listening) features which build on the same principle.
Now what if you made that robot - instead of handing 1 customer at a time - respond depending upon what had to be done instead. Ask customers what the food tasted like (if customers have eaten), take new order(if called upon - by ANYBODY), take dishes(When any customer has paid and there is dish on a table), handle payment(When called upon by anybody). And ofcours handling a new customer arriving at the resturant.
The concurrently made program will handle any task needed by any customer. The sequencly made robot would only handle one customer at a time. Maybe it only then also has to be limited to greeting customers and placing them on seats to be anyhow useful. (You cannot have 1 robot for each customer).
Some people think it is easier to program sequencially can also be said. This is beacuse it can be difficult to keep track of subtasks that has to be done in a particular order. For instance that robot should not look for dishes when there haven´t arrived any customers. And what happens if it receives a payment call - while carrying dish? So it´s hard to prioritize and sort out the different tasks. However when succesfully doing it you program becomes so much more effective. It will be able to mutli task vs just solo-tasking.
And yes the sole purpose of properties is indeed that you can add listeners to them.
It might be confusing for some to answer this but I will try to put my question in the best way. I am working with jdbc and gui. Basically I want to display (in buttons format) the particular data received from my sql database. I could get the data correctly and put it to my array of buttons as their names. In other words, I have an ArrayList of buttons with different names/texts received from my database. Thus i really need to make an arraylist of buttons since data are dynamically populated. My problem is, I am so confused of how am going to create an actionListener to each button. Everytime each button is clicked, it must show the values associated with its name. I don't know how am i supposed to pass at least the names of the buttons to my actionListener method (or action Event Handler). If you find it confusing, here is the code for my buttons.
todayTaskButton.add(new JButton(taskForToday.get(i)));
todayTaskButton.get(i).setPreferredSize(new Dimension(300,75));
todayTaskButton.get(i).setBackground(Color.GRAY);
todayTaskButton.get(i).setFont(new Font("Century Gothic",Font.PLAIN,30));
todayTaskButton.get(i).setForeground(Color.WHITE);
todayTaskButton.get(i).setFocusable(false);
Thank you so much
You don't need to pass the name of the button to the ActionListener. It is automatically detected. You just need to implement the method actionPerformed(ActionEvent) in you class.
Then add the listener to the button :
todayTaskButton.get(i).addActionListener(this);
In your actionPerformed method, you can do:
JButton b = (JButton) e.getSource();
String text = b.getText();
Honestly there are so many ways you might achieve this, the problem is picking the right one for you...
You could...
Create a anonymous class for each button, each time your create them
todayTaskButton.get(i).addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...
}
});
While this can work, it can make the code really messy, you also still need a way to map the action back to the button in some way, which can be done using the actionCommand property or using the source property if you don't mind iterating through the list of available buttons
You could...
Create a purpose build class which implements ActionListener for each button, which possibly takes some kind of reference to the data
todayTaskButton.get(i).addActionListener(new TodayActionListener(taskForToday.get(i)));
This is a little more focused, as you don't really care about the button, as you have the "today" value for the listener, so all the normally repeated code could be isolated into a single class and you would simply pass in the "variable" element
You could...
Take full advantage of the Action API and make individual, self contained actions for each button...
public class TaskAction extends AbstractAction {
public TodayAction(String task) {
putValue(NAME, task);
}
#Override
public void actionPerformed(ActionEvent e) {
// Specific action for task
}
}
Then you could simply use
todayTaskButton.add(new JButton(new TaskAction(taskForToday.get(i))));
While this is similar to the previous option, the Action is a self contained unit of work and has a number of properties which the JButton can use to configure it self. The Action can also be re-used for JMenuItems and key bindings, making it incredibly flexible
Have a closer look at How to Use Actions for more details
I want to programatically set an Eclipse plugin action (button) such as this here:
For example, if the user presses it, I do not want it to toggle off under certain conditions.
This code here creates the action (button):
class MyAction extends Action {
public MyAction() {
super(NAME, IAction.AS_CHECK_BOX);
}
...
Thread.sleep(100); wait a little bit incase there is a thread update issue
if (condition)
setChecked(true); // does not work, it does not force the button to appear as depressed. It just keeps toggling.
...
}
For some reason setChecked(true) does not work.
The problem here I believe is the fact you're calling setChecked inside of Action.run(). Since one of the effects of clicking a checkbox is to check it, you're sneakily trying to cancel the action while it's going on. In fact, I bet the framework code sets checked to true after Action.run() returns, so it's stomping on your change.
Action has a way of letting you control this in a more defined way. Rather than implementing .run(), implement .runWithEvent(Event). This function passes in an Event object that you can use to have finer grained control.
In this case, I think you want to set Event.doit to false. From the docs:
Setting this field to false will cancel the operation.
Another option
Depending on how your condition is calculated, you may want to preemptively enable/disable your checkbox when it changes. This way you can also prevent a tooltip or similar to explain why it's disabled.
I was reading about the Event Style architecture and came across this
There are different ways to deliver notifications, but the most common
technique uses an indirect method call that is made through a pointer
initialized at runtime.
But when Java does not have pointers how does it deliver the notifications ?
Java's event system is based on the Observer pattern, except in Java Swing, everything is called a "listener" instead of "observer", and typically implements EventListener (as you can tell from the beast at the top of that link).
For example, a component such as a JButton allows you to add listeners to it that care about when something happens with the button. If your listener cares about button clicks, you would add an ActionListener to the button, and JButton adds it to an internal list to be used later (specifically, it uses EventListenerList). When the user clicks the button, the JButton class will "fire" an event to all of the ActionListener implementations that have been registered with it.
This is basically the observer pattern because you have a subject that's being observed (the JButton) and an observer that wants to be notified about the subject's changes or events (the ActionListener).
Java doesn't have pointers, per se, but that doesn't mean that this can't be accomplished. In C++, you would pass a function pointer to the subject, and the subject would just call that function. Since Java doesn't have function pointers, you pass an object that implements a particular interface to the subject, and the subject will call an exact method on the interface. In the example above, this would be the ActionListener.actionPerformed(ActionEvent) method.
Note that this method is also popular among other Java libraries besides Swing because of the absence of mechanisms like function pointers and the prevalence of Java interfaces.
Java Swing uses listeners to deliver notifications about events.
Here's a snippet of code from a Swing class
Font font = model.getActivityFont();
activityTextFontButton = new JButton(getFontText(font));
activityTextFontButton.setFont(font);
activityTextFontButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
JFontChooser fontChooser = new JFontChooser();
fontChooser.setSelectedFont(model.getActivityFont());
int result = fontChooser.showDialog(dialog);
if (result == JFontChooser.OK_OPTION) {
Font font = fontChooser.getSelectedFont();
String text = getFontText(font);
model.setActivityFont(font);
activityTextFontButton.setText(text);
activityTextFontButton.setFont(font);
JButton dummy = new JButton(text);
setButtonSizes(activityTextFontButton,
connectorTextFontButton, dummy);
dialog.validate();
dialog.pack();
}
}
});
When the button is pressed, the JButton class executes the code that's part of the ActionListener. That's because the JButton class has a reference to the ActionListener instance and knows that the method to execute is actionPerformed.
There are other ways in Java to drive events (see the Observer / Observed classes), but listeners are a pretty cool way to deliver notifications about events.
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...