java.awt.AWTEventMulticaster.mouseExited(Unknown Source) - java

So I'm trying to implement a guess and check game where there are letters of the English alphabet displayed then each time one is clicked it goes away if it wasn't part of the word specified. (I guess you can call it hangman but there's going to be more to it). Then once the game is lost setLetters is called again and should reset all the letters back onto the screen. (that's another problem i haven't solved in this and know belongs between the update and setLetters() )
letters = new JLabel[26];
for (int i = 0; i < 26; i++) {
int ch = 'A' + i;
letters[i] = new JLabel("" + (char) ch);
panel.add(letters[i],c);
}
ctrl.setLetters(letters);
in the ctrl class there is
public void setLetters(JLabel[] letters2) {
letterLabel = letters2;
for (int i = 0; i < letters2.length; i++) {
letterLabel[i].addMouseListener(this);
/* i'm assuming this issue is here with adding tons of mouselisteners to the label each time it resets, but i'm not sure how to fix it */
}
}
#Override
public void mousePressed(MouseEvent e) {
for (int i = 0; i < 26; i++) {
if (e.getSource() == letterLabel[i]) {
if (!game.letterAvailable((letterLabel[i].getText().charAt(0)))){
letterLabel[i].setText(" ");
}
else {
game.makeGuess((letterLabel[i].getText().charAt(0)));
}
}
}
update();
}
public void update() {
if (letterLabel != null) {
setLetters(letterLabel);
}
if (panel != null) { // redraw (not important for this error)
panel.repaint();
};
}
the error I get is exponentially that of:
java.awt.AWTEventMulticaster.mouseExited(Unknown Source) OR
java.awt.AWTEventMulticaster.mouseExited(Unknown Source)
depending on how the letters are clicked (have yet to figure out why)

As stated in this answer from HoverCraftFullOfEeels
Don't add the same listener to a component inside of its listener code.
In you're mousePressed you're calling update() which calls setLetter, which adds a listener to the component.
Looks like you will have to do some refactoring. Can't really help you any further without full understanding what you're trying to accomplish.

Related

How to render sprite array efficiently in j2me game?

I am working on a landscape java game.
I have a sprite array like this;
Sprite stickArray[] = new Sprite[10];
and initializing it like this with visibility as false.
for (int j = 0; j < stickArray.length; j++) {
if (stickArray[j] != null) {
stickArray[j].setPosition(stickX, stickY);
stickArray[j].setVisible(false);
}
}
Later I want to position it like one after another vertically on repeating a key.pressBool is false initially.
public void keyRepeatInGame(int keyCode) {
int gameKey = getGameAction(keyCode);
Graphics g = getGraphics();
if (gameKey == FIRE || keyCode == KEY_NUM5) {
pressBool = true;
}
}
Later I have written code like this;
Initially one Sticksprite is there.above this sprite, I want to place each sticks on clalling keyrepeat()in space key.
for (int i = 0; i < stickArray.length; i++) {
if (pressBool) {
if (i == 0) {
stickArray[i].setPosition(stickSprite.getX(),
stickSprite.getY() - stickSprite.getHeight());
stickArray[i].setVisible(true);
} else {
stickArray[i].setPosition(stickArray[i-1].getX(),
stickArray[i-1].getY() - stickArray[i].getHeight());
stickArray[i].setVisible(true);
}
}
}
This code is working partially.Stick is getting added on the sprite,all at once.
How can I change the code to make the sticks repeatedly getting added on calling keyrepeat() only, and make it visible one by one properly?
I changed the code with an additional condition and break statement like this;
if (pressBool) {
if (stickSprite != null && !stickArray[i].isVisible()
&& stickArray[i] != null) {
if (i == 0) {
stickArray[i].setPosition(
stickSprite.getX(),
stickSprite.getY());
stickArray[i].setVisible(true);
break;
} else if (i > 0) {
stickArray[i].setPosition(
stickArray[i].getX(),
stickArray[i - 1].getY()
- stickArray[i].getHeight());
stickArray[i].setVisible(true);
break;
}
}
}
It worked.

Making a notepad in java with a on screen keyboard, cant link it to the text area properly

First of all, thank you for taking your time to read this.
this is what am trying to make:
A Text editor with multiple options.
a button for a virtual keyboard. I've managed to create the buttons, also successfully added all the buttons, however I am having difficulties linking each button to my text area and making each button press work.
Not looking for anything complex also all other aspects of the app works, as you will see from the screenshot provided.
this is the bits of code in relation to my keyboard.
class KbListener implements ActionListener //kb function.
{
public void actionPerformed(ActionEvent e) //checking events.
{
keyboard = new JFrame("VK");
keyboard.setSize(400,300);//setting initial size of app.
keyboard.setVisible(true);//making sure its active.
keyboard.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);//closes when the x is pressed.
JButton[] letter = new JButton[27];
keyboard.setLayout(new GridLayout(3,9));
for (int i = 0;i<27;i++)
{
letter[i] = new JButton(""+(char)('A'+ i));
keyboard.add(letter[i]);
//up until this point all is fine.
letter[i].addActionListener = (new ActionListener());
if(e.getSource() ==letter[A])
textArea.append("A");
}
}
}
You need to create a String that is used in the button and used in its listener both, something like,
for (int i = 0; i < 27; i++) {
final String buttonText = String.valueOf((char) ('A' + i));
letter[i] = new JButton(buttonText);
keyboard.add(letter[i]);
letter[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
textArea.append(buttonText);
}
});
}
Note that buttonText must be final so that it is accessible within the anonymous inner ActionListener class.
Also, consider avoiding magic numbers. For instance, you could do
for (int i = 0; i <= (int)('Z' - 'A'); i++) {
or
int i = 0;
for (char myChar = 'A'; myChar <= 'Z'; myChar++) {
final String btnText = String.valueOf(myChar);
letter[i] = new JButton(btnText);
keyboard.add(letter[i]);
letter[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
textArea.append(btnText);
}
});
i++;
}
Edit
Another and perhaps better way to do this is to use Actions rather than ActionListeners. For instance,...
//....
int i = 0;
for (char myChar = 'A'; myChar <= 'Z'; myChar++) {
final String btnText = String.valueOf(myChar);
MyKeyBoardAction action = new MyKeyBoardAction(btnText);
letter[i] = new JButton(action);
i++;
}
}
private class MyKeyBoardAction extends AbstractAction {
public MyKeyBoardAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
textArea.append(getValue(NAME).toString());
}
}
You also ask about the space character,
do u know how to add a space to the code as well?
That would not work with your for loop but can be added on its own.
Also,
but why avoid the numbers?
Because it's easy to make hard to fix bugs if you use "magic" numbers that don't intrinsically make sense. Also, by using constants, variables rather than hard-coded numbers, your variables make your code self-commenting.
Why don't create direct the action listener?
letter[i].addActionListener = (new ActionListener() {
public void onClick(View view) {
textArea.append(""+(char)('A'+ i));
}
);

Next and previous buttons in array cycles through array too many times each press (more then once)

These two buttons are cycling through an array and when pressed increment to many times and depending on what the maximum index is. I thought it might be because (for backwards a least I have "i set as maximum index" but changing to current index stops the button functioning all together.
btnprev.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = dataArrayMaxIndex; i >= 0; i-- ) {
System.out.println("backwards");
dataArrayCurrentIndex = i;
websitetxt.setText(dataArray[i].getWebsitename());
usernametxt.setText(dataArray[i].getUsername());
passwordtxt.setText(dataArray[i].getPassword());
notestxt.setText(dataArray[i].getNotes());
}
}
});
btnnext.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i<dataArrayMaxIndex; i++) {
System.out.println("foward");
dataArrayCurrentIndex = i;
websitetxt.setText(dataArray[i].getWebsitename());
usernametxt.setText(dataArray[i].getUsername());
passwordtxt.setText(dataArray[i].getPassword());
notestxt.setText(dataArray[i].getNotes());
}
}
});
I am unsure as to fixing this problem and could use some help and suggestions. I feel it would be more helpful for myself to not be given the answer but to have some constructive criticism to lead myself to it, that being said feel free to post an a straight, working answer if that's your thing.
I think that your for loops don't belong in this code as you'll loop all the way to the end or all the way to the beginning with each button press. Instead, simply increment or decrement an index variable and use that index. I assume that you'll be using the dataArrayCurrentIndex for this functionality.
i.e.,
btnprev.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dataArrayCurrentIndex--;
// if you want to do a cyclic loop of the data
if (dataArrayCurrentIndex < 0) {
dataArrayCurrentIndex= maxIndex - 1;
}
System.out.println("backwards");
websitetxt.setText(dataArray[dataArrayCurrentIndex].getWebsitename());
usernametxt.setText(dataArray[dataArrayCurrentIndex].getUsername());
passwordtxt.setText(dataArray[dataArrayCurrentIndex].getPassword());
notestxt.setText(dataArray[dataArrayCurrentIndex].getNotes());
}
});
btnnext.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dataArrayCurrentIndex++;
// if you want to do a cyclic loop of the data
if (dataArrayCurrentIndex >= maxIndex) {
dataArrayCurrentIndex = 0;
}
// etc...
}
});

JLabel updating problems

I am creating a hangman game and I was having trouble getting the jlabel that contained each character of the word to update after the right letter button has been clicked. I have been having trouble with this as I am relatively new to working with Java Guis. Below is the action listener for the letter buttons.
private class LetterHandler implements ActionListener{
private char letterVal;
public LetterHandler(char lv){
letterVal = lv;
}
//checks if clicked button has the correct value as word char
public void actionPerformed(ActionEvent e){
for(int x = 1; x <= selectedWord.wordLength; x++){
if(selectedWord.wordValue.charAt(x - 1) == letterVal){
// JLabel letterValLabel = new JLabel(String.valueOf(letterVal));
wordSpacesArray.get(x-1).setName(String.valueOf(letterVal));
wordSpacesArray.get(x-1).revalidate();
continue;
}
else{
continue;
}
}
checkWin();
triesLeft--;
triesLeftLabel.revalidate();
}
//finds if all jlabels are complete or not
public void checkWin(){
for(int x = 1; x <= wordSpacesArray.size(); x++){
String charVal;
charVal = String.valueOf(wordSpacesArray.get(x-1));
if(charVal != "?"){
System.out.println("youWon");
System.exit(0);
}
else{
break;
}
charVal = null;
}
}
}
Any help is appreciated. Let me know if you need for of the programs code Thanks :)
There are some issues with the code. However, I'll first try to focus on your current problem:
I assume that wordSpacesArray is a list that contains the JLabels of individual letters of the word.
When this ActionListener will be notified, you try to update the labels in wordSpacesArray with the letter that corresponds to this button. However, in order to update the text that is shown on a JLabel, you have to call JLabel#setText(String) and not JLabel#setName(String). So the line should be
wordSpacesArray.get(x-1).setText(String.valueOf(letterVal));
// ^ Use setText here!
Now, concerning the other issues:
As pointed out in the comments, you should use 0-based indexing
The calls to revalidate are not necessary
The use of continue in its current for is not necessary
You should not compare strings with ==, but with equals
// if(charVal != "?") { ... } // Don't do this!
if(!charVal.equals("?")){ ... } // Use this instead
But the charVal in this case will be wrong anyhow: It will be the string representation of the label, and not its contents. So you should instead obtain the text from the label like this:
// String charVal = String.valueOf(wordSpacesArray.get(x-1)); // NO!
String charVal = wordSpacesArray.get(x-1).getText(); // Yes!
The triesLeftLabel will not be updated as long as you don't call setText on it
I think the logic of the checkWin method is flawed. You print "You won" when you find the first letter that is not a question mark. I think it should print "You won" when no letter is a question mark.
You should not call System.exit(0). That's a bad practice. Let your application end normally. (In this case, maybe by just disposing the main frame, although that would also be questionable for a game...)
So in summary, the class could probably look like this:
private class LetterHandler implements ActionListener
{
private char letterVal;
public LetterHandler(char lv)
{
letterVal = lv;
}
// checks if clicked button has the correct value as word char
#Override
public void actionPerformed(ActionEvent e)
{
for (int x = 0; x < selectedWord.wordLength; x++)
{
if (selectedWord.wordValue.charAt(x) == letterVal)
{
wordSpacesArray.get(x).setText(String.valueOf(letterVal));
}
}
checkWin();
triesLeft--;
triesLeftLabel.setText(String.valueOf(triesLeft));
}
// finds if all jlabels are complete or not
public void checkWin()
{
for (int x = 0; x < wordSpacesArray.size(); x++)
{
String charVal = wordSpacesArray.get(x).getText();
if (charVal.equals("?"))
{
// There is still an incomplete label
return;
}
}
// When it reaches this line, no incomplete label was found
System.out.println("You won");
}
}

In Java/Swing, is there a way to legally "attempt to mutate in notification"?

I was wondering if there is some sort of magic I can use to get around an IllegalStateException and allow a JTextField to "attempt to mutate in notification", or in other words to set its own text if its listener is triggered.
For your information, I am trying to program an auto-complete function which returns the most likely match in a range of 12 enums in response to a user's input in the JTextField.
Here is the code sample. You'll have to pardon my clumsy algorithm which creaks out enum results. I've highlighted the code which produces the exception with a comment:
jtfElement1.addCaretListener(new CaretListener() {
#Override
public void caretUpdate(CaretEvent e) {
String s = jtfElement1.getText();
int[] attributes = new int[13];
// iterate through each enum
for (BaseEnumAttributes b: BaseEnumAttributes.values()) {
// iterate through the length of the current text in jtfElement1
for (int i = 0; i < s.length(); i++) {
if (s.length() <= b.toString().length()) {
if (b.toString().charAt(i) == s.charAt(i)) {
// increase the number of "hits" noted for that enum
attributes[b.ordinal()] = attributes[b.ordinal()] + 1;
}
}
}
}
int priorC = 0;
int rightC = 0;
// iterate through the "array" of enums to find the highest score
for (int j = 0; j < attributes.length; j++) {
if (attributes[j] > priorC) {
priorC = attributes[j];
rightC = j;
}
}
if (!s.equals("")) {
// assign to b the Enum corresponding to the "array" with highest score
BaseEnumAttributes b = BaseEnumAttributes.values()[rightC];
iController.updateInputElement1String(b.toString());
// THIS TRIGGERS EXCEPTION
jtfElement1.setText(b.toString());
}
}
});
You are probably better off using a document filter or a custom document.
What are other listeners expected to see if the document doesn't stay the same during event dispatch?
Use SwingUtilities.invokeLater() placing all the modifications there
Maybe you can delay the setText() with a Thread to run after caretUpdate() has terminated.
i'm found on the same problem but i found an easy solution:
lock the caretUpdate() by a boolean if(false) while u'r setting the text to the jTextField than unlock it after . . something like this:
boolean caret = true;
private void listValueChanged(javax.swing.event.ListSelectionEvent evt) {
caret = false;
name.setText((String)list.getSelectedValue());
caret = true;
}
private void nameCaretUpdate(javax.swing.event.CaretEvent evt) {
if(caret){
model = new DefaultListModel();
this.fillList(name.getText());
list.setModel(model);
}
}
Create a custom Document and override insertString( )
filenameText = new JTextField(new FilenameDocument(), "", 0);
...
/**
* document which adds .xml extension if not specified
*
*/
private class FilenameDocument extends PlainDocument {
#Override
public void insertString(int offset, String insertedText, AttributeSet set)
throws BadLocationException {
if (offset == 0) {
insertedText = insertedText.trim( );
}
super.insertString(offset, insertedText, set);
if (filenameText != null) {
final int caretPos = filenameText.getCaretPosition();
String text = filenameText.getText().trim();
if (text.indexOf('.') == -1) {
filenameText.setText(text + ".xml");
filenameText.setCaretPosition(caretPos);
}
}
}
}
Note that calling setText will result in a recursive call to insertString( ), so make sure you have a stopping condition.
I'm surprised no one has answered this, but would'nt you have been better off implementing an editable JSpinner with a SpinnerListModel?

Categories