This one is pretty crazy:
I've got an AppSight recording (for those not familiar, it's a recording of what they did including keyboard/mouse input + network traffic, etc) of a customer reproducing a bug. Basically, we've got a series of items listed on the screen with JCheckBox-es down the left side. We've got a MouseListener set for the JPanel that looks something like this:
private MouseAdapter createMouseListener() {
return new MouseAdapter(){
public void mousePressed( MouseEvent e ) {
if( e.getComponent() instanceof JCheckBox ) {
// Do stuff
}
}
};
}
Based on the recording, it appears very strongly that they click just above one of the checkboxes. After that, it's my belief that this listener fired and the "Do stuff" block happened. However, it did NOT check the box. The user then saw that the box was unchecked, so they clicked on it. This caused the "Do stuff" block to fire again, thus undoing what it had done the first time. This time, the box was checked. Therefore, the user thinks that the box is checked, and it looks like it is, but our client thinks that the box is unchecked as it was clicked twice.
Is this possible at all? For the life of me, I can't reproduce it or see how it could be possible, but based on the recording and the data the client sent to the server, I can't see any other logical explanation.
Any help, thoughts, and or ideas would be much appreciated.
Maybe the user clicked on the checkbox, but before release the mouse button, he moved the mouse away from the component. I'm pretty sure the chechbox won't get checked in this case, although not so sure about the Event Thread behaviour under this scenario.
I don't think you can assume that because the mouse was pressed on the checkbox that it will be also released on the checkbox. Maybe just do something like this:
private MouseAdapter createMouseListener() {
return new MouseAdapter(){
public void mouseReleased( MouseEvent e ) {
if( e.getComponent() instanceof JCheckBox ) {
// And just to be sure....
JCheckBox jcb = (JCheckBox) e.getComponent();
if(jcb.isSelected())
{
// Do stuff
}
}
}
};
}
Related
I'm using java WWsdk.
I am expecting the SelectListener to respond to user clicks on the map when user clicks just the map (i.e. not an icon or placemark,etc..).
It works fine for me when i click on my objects, but it doesn't trigger when i click "empty space". i.e. like water/land.
The docs for SelectListener says
If no object is under the cursor but the cursor is over terrain, the select event will >identify the terrain as the picked object and will include the corresponding geographic >position
This statement makes it sound like i should get an event whenever i don't click an object,but i don't get this.
Am i supposed to add some other kind of layer to get clicks on map to trigger select events?
I use this which is working for me for actions i need performed on objects that get clicked:
this.worldWindowGLCanvas1.addSelectListener(new SelectListener()
{
public void selected(SelectEvent event)
{
//Never goes here for clicks on map, just clicks
//on objects i have already created.
doStuff();
}
}
Add a MouseListener using addMouseListener():
this.worldWindowGLCanvas1.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
doStuff();
}
...
}
You may also want to add the listener to the AWTInputHandler instead of the WorldWindowGLCanvas if you want to prevent World Wind from doing something else with the click. More details in this question.
my question is. Is possible to add a component like a button (button has a functionality that triggered when it is clicked) inside a list component?
This image explain better what I refer:
http://2.bp.blogspot.com/-HThpKcgDyRA/URI_FdpffMI/AAAAAAAAAUI/SficZAPXaCw/s1600/1.png
Yes but it requires some handcoding and it will only work for touch (since you won't be able to assign focus to it).
We normally recommend just using Component/Container hierarchies for these cases rather than dealing with lists but obviously this isn't always practical.
The key is to always use the list action listener to trigger events, nothing else. So when you are in the action handling code of the list you would want to know if it was triggered by your button...
If you are in the GUI builder this is pretty easy:
Button b = ((GenericListCellRenderer)list.getRenderer()).extractLastClickedComponent();
if(b != null && b == myButton) {
// your event code here for the button, the selected entry is list.getSelectedItem()/Index()
}
The handcoded approach is pretty similar with one major caveat, you don't have the extractLastClickedComponent method. So assuming you have a component within the renderer just add an action listener to it. Within the action listener just set a flag e.g.:
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
buttonWasClicked = true;
}
});
// within the list listener we do the exact same thing:
if(buttonWasClicked) {
// for next time...
buttonWasClicked = false;
// your event code here for the button, the selected entry is list.getSelectedItem()/Index()
}
Yes!!! Try it, this is pretty easy:....
http://www.codenameone.com/how-do-i---create-a-list-of-items-the-easy-way.html
http://www.codenameone.com/how-do-i---create-a-list-of-items-the-hard-way-gui-builder-renderer.html
Clicking the button should toggle between setting the textfield as editable or not. When the GUI opens the textfield should be editable.
public void actionPerformed( ActionEvent evt)
{
if(inputField.setEditable() == (true))
{
inputField.setEditable(false);
}
else
{
inputField.setEditable(true);
resultMessage.setText("");
resultMessage.setText("Edit Button Pressed");
}
What am i doing wrong here?
I know that the else statement is right just the start of the IF is wrong, i'm not sure where i'm going wrong.
Additional question:
public void actionPerformed( ActionEvent evt)
{
if(inputField.isEditable() == (true))
{
inputField.setEditable(false);
}
else
{
inputField.setEditable(true);
inputField.setText("");
resultMessage.setText("Edit Button Pressed");
}
if(inputField.getBackground() == Color.RED)
{
inputField.setBackground(Color.WHITE);
}
else
{
inputField.setBackground(Color.RED);
resultMessage.setText("Colour Button Pressed");
}
}
I now currently have 2 IFs but obviously the first IF will stop the second IF from working how do i get around this so that when i press one button that will do the setEditable section and when i press the other button it will do my change colour?
You're checking if setEditable() is true which really makes no sense; after all, it returns void and requires a boolean parameter. The bigger problem is that you shouldn't be checking the editable status via a "setter" field but rather a "getter" field, here isEditable()
if (inputField.isEditable()) {
//....
} else {
//...
}
As MadProgrammer points out, this information is all readily available in the Java API, something you'll want to get very familiar with.
Edit, regarding your new question:
I now currently have 2 IFs but obviously the first IF will stop the second IF from working how do i get around this so that when i press one button that will do the setEditable section and when i press the other button it will do my change colour?
No, the first if/else will have no effect on the second if/else block. Your problem lies elsewhere. Consider asking this with additional information as a new question on stackoverflow if still suck.
Also note that this is unnecessarily wordy:
if(inputField.isEditable() == (true))
and is better written as I have it above:
if (inputField.isEditable())
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.
I'm currently trying to receive key events during a drag and drop, but it seems to me that the focus is taken away while dragging so that I can't listen to any key events.
I'm dragging a JComponent subclass that implements KeyListener and requests the focus in the DragSourceListener's dragEnter method, but my assumption is that the focus is taken away from it afterwards.
Now, who's got the focus and how can I take it away back to my JComponent. Or is there a different approach that is more suitable for dnd?
Thank you in advance.
UPDATE:
It's a lot of code necessary to make this work so I'm only going to post some snippets to show you what I'm trying to do:
public class Stone extends JComponent implements Serializable, KeyListener {
public Stone(...) {
//...
setFocusable(true);
addKeyListener(this);
this.dragSource = DragSource.getDefaultDragSource();
this.dgListener = new StoneDGListener();
this.dsListener = new StoneDSListener();
this.dragSource.createDefaultDragGestureRecognizer(
this,
DnDConstants.ACTION_MOVE,
this.dgListener
);
//...
}
//...
public void keyPressed(KeyEvent e) {
System.out.println("Stone: "+e.getKeyCode());
}
//...
public class StoneDSListener implements DragSourceListener, Serializable {
//...
#Override
public void dragEnter(DragSourceDragEvent dsde) {
//...
Stone.this.requestFocus();
addKeyListener(Stone.this);
}
//...
}
}
What happens is that before I'm dragging the Stone component my JPanel has the focus so it receives any keys I'm pressing.
During the drag I can't listen to any pressed keys(so I don't know who's got the focus) even though I'm requesting it when in dragEnter() and after I release the Stone any key events are send to the Stone.
It's probably not important for the question but to illustrate what I'm doing here's a screenshot:
image showing the "drag" http://img685.imageshack.us/img685/1884/pico.png
(Here I'm dragging the Stone from the collection below to the game field on the top). In this state I don't know how to find out what keys are pressed. I need to figure this out in order to be able to rotate the Stone.
Not sure who has focus during a drag and drop. But an alternative solution to your problem would be to add a KeyEventDispatcher for your Stone class to the KeyboardFocusManager. From the JavaDoc:
The KeyboardFocusManager is both a centralized location for client code to query for the focus owner and initiate focus changes, and an event dispatcher for all FocusEvents, WindowEvents related to focus, and KeyEvents+.
+ my emphasis.
Basically we use similar sort of code to intercept KeyEvents before they hit the Component that has focus.
Just gave it a quick test for your particular drag and drop context and it seems to work alright (as long as your application has focus within the operating system). Essentially something along the lines of:
Public Stone(...) {
// ...
KeyboardFocusManager fm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
fm.addKeyEventDispatcher(
new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e) {
System.out.println("Key Press: " + e.getKeyChar());
return false;
}
}
);
// ...
}
You will need to do a bit of leg-work on enabling and disabling when the user is no longer dragging and dropping as my test currently prints all the time.
I also wonder if it is possible to use the KeyboardFocusManager to determine who actually ends up with focus during a drag and drop?
Anyway, I hope this gives you a few new ideas to try.