Java: transparently handle state change event - java

I have a view that has several "flag" buttons (JToggleButton). When the user clicks a flag button, I want to update an array that keeps track of which buttons are flagged. This is pretty simple, and here is what I have done:
...
bflag[i].addItemListener(this); //View listens to state change
...
void itemStateChange(ItemEvent ie) {
try {
jtb = (JToggleButton)ie.getSource();
//Update mark array
}
catch (ClassCastException cce) {}
}
This works just fine, but it is ugly with the try/catch. I would much prefer to do something like this:
void itemStateChange(ItemEvent ie) {
handleStateChange(ie.getSource());
}
void handleStateChange(JToggleButton jtb) {
//handle state change
}
void handleStateChange(Object o) {}
This is much nicer, but the only problem is that the Object method will fire even if the source is a JToggleButton (because a JToggleButton is an Object after all).
I have also considered using double dispatch, but this would require overriding the JToggleButton method that fires itemStateChange(), and I don't know what that is (and that seems unsafe).
Any suggestions on how to get this to work without a try/catch, conditional check, etc.?

You will have to check for the Type explicitly I think.
if(ie.getSource() instanceof JToggleButton){
//toggle button logic
}else{
//something else
}
Alternatively you can use anonymous inner classes to implement your listeners and avoid having to check the source altogether.
Something like this:
toggleBtn.addItemListener(new ItemListener(){
public void itemStateChange(ItemEvent ie){
//handle toggle button event
}
});

Related

Detect if application gains focus (as opposed to window focus)

I have a program that should issue some action when it gets activated after loosing focus to some other application before. I wrote a Focus-Listener to achieve this:
frame.addWindowFocusListener(new WindowFocusListener() {
#Override
public void windowGainedFocus(WindowEvent e) {
<do something when we gain focus>
}
#Override
public void windowLostFocus(WindowEvent e) {
<do something else when we lose focus>
}
});
Problem is, the gain-focus-action is also called when a modal dialog (for instance an authentication dialog) closes - the main window gains focus again. So I somehow would need to detect, if I gain focus from within my program or from the outside. Or, differently put, the focus action should not be located on the main window but on the application itself. What would be a simple way to do this?
Thanks #Aelop for helping me find an answer. e.getOppositeWindow() is null for windows of other applications, so I can neatly distinguish from where I'm coming from:
frame.addWindowFocusListener(new WindowFocusListener() {
#Override
public void windowGainedFocus(WindowEvent e) {
if (e.getOppositeWindow()==null) {
<do something when we gain focus>
}
}
#Override
public void windowLostFocus(WindowEvent e) {
<do something else when we lose focus>
}
});
if you didn't find a good solution use static variable when the focus is lost from a dialog in your application set a static boolean variable to true so when the focus is gained and the variable is true means that the focus is from some window in the application else the focus is from somewhere else i hope you get the idea try it if you didn't find some application or check the type of the source who lost the focus

Keeping Track of Every Time that a Checkbox is checked and unchecked

I have most of my java application done already, so I am now logging all user activity. One thing I want to keep track of is whenever one of my checkboxes is checked and unchecked. I am able to read at the end if the object is checked or unchecked, however I want to know each time the checkbox is used in real time. I want to know how many times the user checks and unchecks the box. Right now I am using something similar to this syntax, but it doesn't print a statement each time the checkbox is checked and unchecked.
public CheckboxAction(String text) {
super(text);
}
#Override
public void actionPerformed(ActionEvent event) {
JCheckBox cbLog = (JCheckBox) event.getSource();
if (cbLog.isSelected()) {
System.out.println("Logging is enabled");
} else {
System.out.println("Logging is disabled");
}
}
An ItemListener seems appropriate here
yourJCheckBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent arg0) {
if (yourJCheckBox.isSelected()) {
// Code to execute when it's selected
}
else {
// Code to execute when not selected
}
}
});
First and foremost, do not override actionPerformed. If you need to - at least call super.actionPerformed before performing your action. Best way is to use addActionListener or in this case as #BoDidely mentioned use an addItemListener.

Concurrency in Java - wait for execution to be finished

So I am currently doing some work with Multi-Threading in Java and I'm pretty stuck on a, most likely, simple thing.
I currently have a JButton that, when pressed invokes the method as follows:
private void clickTest() throws InterruptedException{
statOrganizer.incrementHappiness();
Thread t = new Thread(new Happiness(workspaceHappy));
t.start();
}
and then takes around 10-30 seconds to complete. During this time however, it is still possible to re-click the JButton so that it messes with how the information is displayed.
What I want to do is during the time this particular thread is "alive", disable the button so that it is no longer possible to click it(and thus activate this thread once it's already going). Once the thread is finished, I want to re-enable the button again.
The button code just looks like this
button.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 1) {
try {
clickTest();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Disable the button right before starting the thread. In the thread, at the end, post an event that would re-enable the button (using invokeLater).
You may also need a cancel option, but that's a separate question.
Try the following:
button.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 1) {
try {
clickTest();
button.setEnabled(false);//this assume 'button' is final
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Then, modify the run method of your Happiness class:
public void run()
{
//your processing code here
...
button.setEnabled(true);
//reference to button can be passed in constructor of Happiness
// or access using getter, ... This really depend on your implementation.
}
The nice solution for this is to use a glass pane to capture all events and stopping them from propagating to any of your UI elements on the panel under the glass pane. Of course while you only have one or two, you can call setEnabled(false) on them manually but glass panes give you more flexibility, you'll never have to worry about adding a new element to your UI and forgetting to disable it during background processing.
Probably an overkill for one button though.
Another, unrelated thing you should consider is the use of Executors instead of launching threads for background tasks. It results in cleaner and more scalable code.

Can't get ItemListener to work for JCheckBox

I am using this code to create a JCheckBox
private final JCheckBox cbDisplayMessage = new JCheckBox("Display");
cbDisplayMessage.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if(e.getItemSelectable() == cbDisplayMessage) {
if(cbDisplayMessage.isSelected()) {
cbDisplayMessage.setSelected(false);
} else {
cbDisplayMessage.setSelected(true);
}
}
}
});
When I run this it causes an StackOverflow error on setSelected(true). Can't figure out what I am doing wrong. Any ideas appreciated....
You can try with ActionListener instead of ItemListener as shown below without causing StackOverflow error.
cbDisplayMessage.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (cbDisplayMessage.isSelected()) {
cbDisplayMessage.setSelected(false);
} else {
cbDisplayMessage.setSelected(true);
}
}
});
There is no need to check the source of the event again because you are sure that you have added this listener on the same object. This is required only if same listener is added for more components.
-- EDIT--
Now Your requirement is clear to me. If you want to toggle the state of the check box then there is no need to do it using listener because that's the default behavior of the check box.
Your listener is called every time the state changes, but you trigger a new state change from within that listener, so each state change results in that listener being called over and over again until your stack is full. Your setup has to be a bit more complicated to do something like that - if you want to change the state of the component you're listening to, you'll want to remove its listener(s), fire your programmatic state change, then re-add them.

How to remove an inner class ActionListener?

I am making a text based game, but I am having a rather large problem. This problem is that when I assign a new ActionListener to a button that already has an ActionListener assigned to it, it does both of the actions. Here's my code:
while(shouldLoop) {
if(Player.loc == 1) {
left.setText("Do nothing");
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
nar1.setText("You are still in a dungeon."); //Here's my first assignment
}
});
right.setText("Pick the lock");
right.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Player.loc = 2;
}
});
} if(Player.loc == 2) {
nar1.setText("You are now outside");
nar2.setText("the door. What now?");
forward.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
nar1.setText("You hear a guard.");
nar2.setText("What do you do now?");
Player.loc = 3;
}
});
left.addActionListener(new ActionListener() { //Here's another
#Override //assignment to
public void actionPerformed(ActionEvent e) {//the same button
nar1.setText("You hear a guard."); //so when I press
nar2.setText("What do you do now?"); //it here, it
Player.loc = 3; //performs the
} //original assignment
});
right.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
nar1.setText("You hear a guard.");
nar2.setText("What do you do now?");
Player.loc = 3;
}
});
right.setText(rgt);
forward.setText(fwd);
back.setText(bck);
left.setText(lft);
forward.setVisible(true);
} if(Player.loc == 3) {
forward.setVisible(false);
right.setText("Sneak around him!");
left.setText("Fight him!");
}
Thanks for helping,
billofbong
Why don't you just hoist the addActionListener code out of the while loop?
Anonymous inner class listeners look nice in quick and dirty example code, but, in practice, they are a horrible idea. You are learning one of the reasons. Other reasons are that they can't readily be subclassed or modified via Dependency Injection types of things, can't readily be shared (say a button, a toolbar icon, and a menu do the same thing), can't readily be enabled / disabled, (say, "Save As" should be disabled cause nothing is open) etc...
For this use case, break them out into some series of actual Listeners, perhaps organized in a class, array, or some Enums, so they can get swapped in and out.
You are mixing data with code in a bad way by hard-coding the logic of your program in the program itself, and this is the main source of your current and future problems. This won't work, at least not without a lot of kludges.
I suggest you try to separate your data out of your code and make your program more MVC-ish, which stands Model-View-Controller (or one of its many variants). For instance the logic of the program is held by the Model and this includes the non-visualized map of the land being explored, the position of the player in this map, his companions, and your inventory of items that you've collected. So you will likely have several non-GUI classes such as Player, Map, Item (this may be an interface), Room, etc... The Map itself, the possible items, there locations, will be specified in a data file, perhaps a text file for a simple program or a database for a more complex one, and you will need classes to read and parse this file(s).
The View of your program is your GUI, and it should be as dumb as possible. Here is where you'll have your buttons, your text display, and if fancy, a graphical display of your game. No program logic goes in here. None.
The Control will be the Action Listeners that you add to your JButtons and any other code that has to deal with handling user input. But this code could be relatively simple, and it's main task is to pass user interactions to the model. So for instance if the left button is pressed, it may be simply something like
model.leftButtonPress();
Then the model will decide what to do with a left button press, if anything. The model will know where you are in the game for instance, if there's a door to your left or if it's a wall, and based on the state of the model your game will perform the requisite action.

Categories