Is it possible to programatically set an Eclipse RCP button as 'checked'? - java

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.

Related

Adding timeout to a user interface program

I'm working on a Java project involving user interface, using the Button class and some action listeners.
I have a few buttons (each with an action listener) and I want to add a timeout to the whole program. That means, if no button was clicked-on in a certain amount of time, a specific action should be performed.
I tried adding it among the basic while loop + isDisposed() function. To my knowledge, this loop checks multiple times whether a button was clicked-on. For some reason, I couldn't get the outcome I wanted.
Is there a way to do so with the classes I mentioned? I also couldn't find any suitable functions in the Button class.
Use a Swing Timer (javax.swing.Timer).
Instanciate it with new Timer(CERTAIN_AMOUNT_OF_TIME, e -> timeoutAction()) (If you have a function timeoutAction), disable repeating with setRepeats(false) and start() it.
When the user clicks a button, call restart() on it.
Also, you’re mentioning the Button class, which is an AWT class. I recommend using Swing’s JButton class instead.
It is highly probable that you are using swing, but since this is not specified, I will give you a general answer, with links to swing examples.
First of all, since all your button clicks will behave in a very similar manner, so you will need a custom ActionListener (example). Your custom action listener should perform the action, but set a timestamp or some kind of date value to the current moment. In parallel, you should have a heartbeat event, which periodically (frequently) runs and compares the current moment with the timestamp set by the last button click. And you can see an example of a periodic task here: How to schedule a periodic task in Java?

Call itemStateChanged() only after user interaction

in my swing application I have a combo box with an ItemListener that does X if the user changes the value (via itemStateChanged()).
However I also have a different function that changes the value of that combo box. In this case I do not want X to be done.
Is there a way to find out if the state change was caused by user interaction or from a function?
Thank you!
Edit: I used the flag method. Thanks for the quick answers. I just want to add, that itemStatechanged is actually called twice, once for deselection and once for selection. This needs to be dealt with otherwise the flag won't have any effect. The problem is discussed here.
There are 2 ways to do the check:
Define a flag isUser. The flag is true by default. Before changing programmatically set it to false and reset after setting the combo-box value. In the listener just check the flag and skip the action if necessary.
Keep a reference to the listener and remove it before setting value, adding after.
From what I understand you could very easily sort out your problem using a flag.
Just make a boolean flag, e.g. isDoneByMethod which will be on entrance to a method set to true and at the end set to false and between these two do the operation on the combobox. Then inside the itemStateChanged() check for the value of the isDoneByMethodflag and act accordingly.
I have the similar kind of situation where I need to differentiate two cases. Both options discussed here (flag and removal/addition of listener) do not work all the time, as the item listener is asynchronously called on EDT thread. However remove and adding the particular item listener is more safe . To further ensure that all the previous actions will be dealt before you add the item listener, I use fireEvents() just before adding the listener again.

java - deactivate a listener

I have a general question regarding listeners.
Lets say I have two JTabbedPanes and both have a ChangeListener. They are both displayed and I want them both to show the same pane (index) so when a user changes the selected pane in one the other changes too.
In brief, one JTabbedPane listener changes the other JTabbedPane using setSelectedTab().
Obviously, the first listener will activate the second listener and the second will reactivate the first in an endless operation.
This will be solved with booleans.
Is there a smarter way to do it?
Is there a way to change a tab without triggering the Listener?
Is there a way to activate the listener only when a user changes it and not the code?
Thank you.
BTW: I always have the same questions with buttons. But with buttons I take the code from the listener and put it in a method. when One button needs to activate a button it calls its code. But in JTabbedPane it is different.
The simple solution is to act only when necessary. For example:
if(currentTab != desiredTab) {
// change tab
}
That will prevent an infinite loop.
If you need to be able to switch the behavior on and off, then using a boolean flag isn't a bad way to go about it. The alternative is the remove the listener, using removeChangeListener. The flag may be more performant as it may avoid memory allocation and deallocation, but a lot depends on the other details of your situation.
share the selectionModel, like
secondTabbedPane.setModel(otherTabbedPane.getModel());

How do I make a listener that fires when the USER selects an item in a JComboBox

I'm looking for a listener that fires ONLY when the user, the one who's using the program, selects an item in the JComboBox. I don't want to use ActionListener or ItemListener because those also fire when I select an item through the program. And I can't use MouseListener either because it only fires when I click the JComboBox, not when I select an item.
I was wondering what the easiest way to do this is? Currently, my solution is messy. When I change the selected item of the jcombobox through code, I set a flag to true. And in my action listener, it only executes if the flag is false.
A) I would recommend you to temporarily remove the listener when you perform the selection programatically.
B) If your programatic change is not an effect of another GUI event you could solve it the following ugly/non-robust/error-prone/"hacky" way: Check EventQueue.isEventDispatchThread() to find out if the click was triggered by the GUI thread (the user).
C) (Oops I just reread your question and saw that you've already discovered the method described below. Basically I would say that this (or the the method described above) is your best alternative.)
Another option is to have a boolean flag called something like nonUserSelection which you set to true before you select a value programatically and reset to false afterwards. In the action listener you simply add an
if (nonUserSelection)
return;

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