im trying to make simple calculator in java GUI. I got to the point where I can clearly see that code is just ugly because of repeating functions like:
number0 = new JButton("0");
number0.setBounds(130, 280, 50, 50);
add(number0);
number0.addActionListener(new GetNumber0());
public class GetNumber0 implements ActionListener {
public void actionPerformed(ActionEvent e) {
String text =number0.getText();
int num = Integer.parseInt(text);
result=(result*10)+num; // +num if else than 0
lResult.setText("Result: "+result);
}
}
Which I'm doing for every button, so is there a way to make this code look better? I'm hoping for something that can get a variable from each button individually and use it in only one fucntion named GetNumber().
You don't need to create a separate listener, and you really shouldn't. It's not useful to write String text = number0.getText(); because you already know it's going to be 0.
Share the ActionListener between the buttons.
public class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton) e.getSource();
int num = Integer.parseInt(btn.getText());
result=(result*10)+num;
lResult.setText("Result: "+result);
}
}
Related
What the program is supposed to do is to mimic the "spin" button with the enter key. The program works and it doesn't crashes but eclipse console is giving me a "Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.JTextField cannot be cast to javax.swing.JButton" error.
//.. gui code
spin = new JButton("Spin");
bet = new JTextField("");
play p = new play();
spin.addActionListener(p);
keys k = new keys();
bet.addKeyListener(k);
}
private class play implements ActionListener{
public void actionPerformed(ActionEvent e) {
JButton src = (JButton) e.getSource();
if(src.equals(spin)) {
//do something
}
}
private class keys implements KeyListener{
#Override
public void keyTyped(KeyEvent e) {
char c= e.getKeyChar();
if(c == KeyEvent.VK_ENTER) {
spin.doClick();
}
}
//.. the other override methods
}
EDIT
there are 2 more buttons, I just didn't include them since they worked fine and functioned differently.
JTextField has a KeyListener because I was filtering out numbers from letters so I would consume the event. Can't have a user bet with letters right?
I would guess that your ActionListener is receiving events from multiple objects, one of which is a JTextField. The exception occurs when you try to cast this object to JButton:
(JButton) e.getSource();
There may be a better solution but from what you've shown us the easiest way to prevent the exception is to check that the object generating is an event is an instance of JButton before casting:
private class play implements ActionListener{
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
// Check type before casting
if (src instanceof JButton) {
JButton bsrc = (JButton)src;
if(bsrc.equals(spin)) {
//do something
}
}
}
}
First, don't use KeyListener for this task, JTextField already supports ActionListener and you could make use of JRootPane's "default button" support as well, so a number of better solutions are available.
You should also take advantage of the actionComamnd support of the ActionEvent (and ActionListener), which will mean you don't have to cast the source, which is safer and makes the solution more re-usable (as it's decoupled).
For example...
Play p = new Play();
spin = new JButton("Spin");
spin.setActionCommand(Play.COMMAND);
bet = new JTextField("");
bet.setActionCommand(Play.COMMAND);
spin.addActionListener(p);
bet.addActionListener(p);
//...
private static class Play implements ActionListener {
public static String COMMAND = "Spin";
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals(COMMAND)) {
//do something
}
}
}
Alternatively, you could make use of the existing Actions API. This allows you to design a self contained unit of work that can be applied directly to a number of Swing components (which already support the ActionListener API), but which are also self configurable, neat...
private class SpinAction extends AbstractAction {
public SpinAction() {
putValue(NAME, "Spin");
}
#Override
public void actionPerformed(ActionEvent event) {
// Spin me baby
}
}
And then simply apply it...
SpinAction action = new SpinAction();
spin = new JButton(action);
bet = new JTextField("");
bet.setAction(action);
See How to use actions for more details
I am making a text based game, and I am experimenting with different ways of making the storyline of the game progress. (Im sorry if this is semi-hard to follow, I am new to this website, and still fairly new to Java, I'm making this for a class project)
One of the ways I am trying is by increasing a value (In this case LevelNum) by one, and whenever a number not equal to zero is displayed it will set the text of jLabel1 to whatever the text is.
I am trying to do this by using an if statement as shown here:
if(LevelNum == 0) {
jLabel1.setText(StoryData.LevelOne);
}
The increase of LevelNum is done like this:
public void actionPerformed(ActionEvent e) {
LevelNum += 1;
System.out.println(LevelNum);
}
(The System.out was just to check to see if it was increasing the number)
The problem I am running into is that no matter what the value of jLabel1 is, the text never changes, and I dont know why.
The whole code can be found here: https://pastebin.com/JSX6urFT
The StoryData is a seperate class within in my text document, and the individual strings look like this: static String LevelOne = "Level one test";
Here is all the code related to LevelNum:
public class DemoGUI extends javax.swing.JFrame {
private static int LevelNumBackUp = 0;
private static int LevelNum = 0;
public JTextArea jLabel1;
public JTextField jText1;
public JButton jButton1;
public JButton jButton2;
public JButton jButton3;
public JButton jButton4;
public JButton jButtonStart;
public JTextArea jTextAreaStart;
public JButton jButtonCredits;
public JButton jButtonReturn;
public static void main(String[] args) {
int LevelNum = 0;
int LevelNumBackUp = 0;
Keep level changing code in actionPerformed.
Try this:
public void actionPerformed(ActionEvent e) {
LevelNum += 1;
System.out.println(LevelNum);
// Introduction
if (LevelNum == 1) {
jLabel1.setText("level1");
}
if (LevelNum == 2) {
jLabel1.setText("level2");
}
if (LevelNum == 3) {
jLabel1.setText("level3");
}
}
After the value of the label changed, try to call revalidate() and repaint() to update your Userinterface
Looking at the full code, the part which increments LevelNum is in the following block:
jButton3.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
LevelNum += 1;
System.out.println(LevelNum);
}
});
Then, down below, you have this code:
if(LevelNum == 1) {
jLabel1.setText(StoryData.LevelOne);
}
Let's walk through the code the way a computer would. When we get to that first block, we add a new ActionListener. However, we do not execute the actionPerformed method immediately, so LevelNum is still what it was previously. Later on, we get to the if statement, but LevelNum has not been incremented.
When the ActionListener is triggered, and the actionPerformed method executes, it increments LevelNum and then prints the new LevelNum, but it does NOT change jLabel1 because there is no code telling it to do so.
It looks like what you want to do is update jLabel1 inside the actionPerformed method.
I am trying to do a simple Minesweeper game using JFrame, however I am having troubles with the creation of objects. I am creating 96 buttons, some of which get the property of being wrong ("F") and right ("R"):
public class GUIBase extends JFrame {
private JButton button;
private JButton fButton;
public GUIBase() {
super("Minesweeper");
setLayout(new FlowLayout());
//Fields
int position;
for (int i = 0; i < 96; i++) {
position = (int) (Math.random() * 100);
if (position < 80) {
button = new JButton("R");
button.setToolTipText("Is this the correct one?");
add(button);
} else {
fButton = new JButton("F");
fButton.setToolTipText("Is this the correct one?");
add(fButton);
}
}
I then use ActionListener in order to check whether or not the button is correct. If the button is correct, it will get .setEnabled(false), otherwise the game ends:
//Action
Action action = new Action();
button.addActionListener(action);
fButton.addActionListener(action);
}
private class Action implements ActionListener {
public void actionPerformed(ActionEvent event) {
System.out.println("Somethin");
if (event.getSource() == button) {
button.setEnabled(false);
} else if (event.getSource() == fButton) {
JOptionPane.showMessageDialog(null, "You lost!");
System.exit(0);
} else {
JOptionPane.showMessageDialog(null, "An error ocurred");
System.exit(0);
}
}
}
Everything in the game turns out as planned, however only the last correct button ("R") and last wrong one ("F") are connected to the ActionListener. The rest of the buttons do not do anything when pressed.
How can I fix this?
The problem is that you only have two variables (attributes of the class GUIBase, specifically), and your are assigning to it each time you create a new button. Hence, you only have a reference to the last buttons.
You need an array of buttons. Let's see:
public class GUIBase extends JFrame {
public final int MAX_BUTTONS = 96;
private JButton[] buttons;
// ...
}
The next step is to create the array itself at the beginning:
public GUIBase() {
super("Minesweeper");
setLayout(new FlowLayout());
this.buttons = new JButton[MAX_BUTTONS];
//Fields
int position;
for (int i = 0; i < buttons.length; i++) {
position = (int) (Math.random() * 100);
this.buttons[ i ] = new JButton("R");
this.buttons[ i ].setToolTipText("Is this the correct one?");
this.add(this.buttons[ i ]);
Action action = new Action();
this.buttons[ i ].addActionListener(action);
}
}
You'll probably need more depth in arrays in order to completely understand the code. Basically, an array is a continuous collection of variables, which you can index by its position, from 0 to n-1, being n the number of positions.
Then you'll probably be able to fill the gaps yourself.
Hope this helps.
One part of your problems is coming from your action listener.
Of course, one part is that your code probably needs a list/array to keep track of all created buttons; but at least right now, you can rework your code without using arrays/list:
private class Action implements ActionListener {
public void actionPerformed(ActionEvent event) {
System.out.println("Somethin");
if (event.getSource() instanceofJButton) {
JBUtton clickedButton = (JButton) event.getSource();
String buttonText = clickedButton.getText();
if (buttonText.equals("R") ...
else if (buttonText.equals("F")
You see, the whole point here is: as of now, you just need to know what kind of button was created. And your ActionListener knows which button it was clicked on ...
I created a JComboBox and JButton to submit information. I need the information to be sent to a different class to sort it out with a switch method. But it looks like the string created inside the ActionListener is not recognized by a different class.
public Main() {
final JComboBox comboB = new JComboBox(b); //add int b in here for array
comboB.setBounds(50, 30, 123, 20);
contentPane.add(comboB);
JButton btnTest = new JButton("Test");
btnTest.setBounds(300, 350, 89, 23);
contentPane.add(btnTest);
btnTest.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String s = (String)comboB.getSelectedItem();
}
});
}
How do I make it so that String s can be recognized by other classes? I have a separate class that will change action depending on what is selected from ComboBox, but I just can't seem to get this information out. Thank you.
Firstly, other objects need some way to register an ActionListener to the combo box. I would suggest providing a addActionListener method to your class, this would act as a proxy method and simple pass the call onto comboB
Secondly, this means comboB is going to need to be a class instance variable
Thirdly, the other classes are going to need to determine if the action originiated from the combo box or not, for example.
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JComboBox) {
JComboBox cb = (JComboBox)e.getSource();
String s = (String)cb.getSelectedItem();
}
}
Now, there's not a lot of context available to the question, but, personally, I would normally either use a model of some kind that your UI class would update and/or a PropertyChangeListener that other classes could register against and monitor for changes to the "properties" of the your main class.
You just need to create a private method and have the combo call that. Then you just navigate to your component/class, and perform the action.
public Main() {
final JComboBox comboB = new JComboBox(b); //add int b in here for array
comboB.setBounds(50, 30, 123, 20);
contentPane.add(comboB);
JButton btnTest = new JButton("Test");
btnTest.setBounds(300, 350, 89, 23);
contentPane.add(btnTest);
btnTest.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String s = (String)comboB.getSelectedItem();
myMethodThatProcessesS(s);
}
});
}
private void myMethodThatProcessesS(String s) {
contentPane.getSomeOtherComponent().doSOmething(s);
}
Since java swing implements the MVC pattern you can pass the JComboBox's model reference to other objects.
Models implement the observer pattern and therefore the other objects can register themself if they need to get notified immediatly when the model changes.
public class Main {
public initializeComponent(OtherClass otherClass) {
...
JComboBox comboBox = ...;
ComboBoxModel comboBoxModel = comboBox.getModel();
otherClass.setComboBoxModel(comboBoxModel);
}
}
public class OtherClass {
private ComboBoxModel comboBoxModel;
public void setComboBoxModel(ComboBoxModel comboBoxModel) {
this.comboBoxModel = comboBoxModel;
ListDataListener listener = ...;
comboBoxModel.addListDataListener(listener);
}
public String getSelectedItem(){
Object selectedItem = comboBoxModel.getSelectedItem();
...
}
}
it is possible to have two class, and in one something like
arrayButtons[i][j].addActionListener(actionListner);
and in another
ActionListener actionListner = new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int j = 0; j < arrayButtons.length; j++) {
for (int i = 0; i < arrayButtons[j].length; i++) {
if (arrayButtons[j][i] == e.getSource()) {
if ((gameNumber == 2) && (playHand.getNumberOfCards() == 0)) {
if (player[j].getCard(i).getSuit() == Suit.HEARTS.toString() && player[j].hasSuitBesideHearts())
//second game
messageOnTable("xxx");
else{
arrayButtons[j][i].setVisible(false);
test[j].setIcon(player[j].getCard(i).getImage());
pnCardNumber[j].setText(Integer.toString(player[j].getCard(i).getNumber()));
pnCardName[j].setText(player[j].getCard(i).toString());
pnCardSuit[j].setText(player[j].getCard(i).getSuit());
playHand.addCard(player[j].getCard(i), j);
player[j].removeCard(i);
}
}
}
//and more
the reason of that is because i need to separate the button (swing) to the action listener
how i can do ?
thanks
Not only it is possible to separate these two, it's also recommended (see MVC pattern - it's very much about separating screen controls like buttons, and the logics of your program)
The easiest way that comes to my mind is to do write a named class that implements ActionListener interface, something like this:
public class SomeActionListener implements ActionListener{
private JTextField textField1;
private JComboBox combo1;
private JTextField textField2;
//...
public SomeActionListener(JTextField textField1, JComboBox combo1,
JTextField textField2){
this.textField1=textField1;
this.combo1=combo1;
this.textField2=textField2;
//...
}
public void actionPerformed(ActionEvent e) {
//cmd
}
}
And then add it to your buttons:
ActionListener actionListener = new SomeActionListener(textField1, combo1, textField2);
someButton.addActionListener(actionListener);
To answer: "my problem is that action listener have many variables of swing like buttons for example,so, when i change to another class, i have problems with that"
Your action listener class could have a constructor that takes a parameter of the type of the view class:
public class Listener implements ActionListener {
private final MyViewClass mView;
public Listener(MyViewClass pView) {
mView = pView;
}
public void actionPerformed(ActionEvent e) {
// can use mView to get access to your components.
mView.get...().doStuff...
}
}
Then in your view:
Listener l = new Listener(this);
button.addActionListener(l);
you can do it easily by using nested classes,
but i think the best way is pass the parent object as a parameter to the construct of object and using it as an action handler;
//**parent class - Calculator **//
public class Calculator extends JFrame implements ActionListener{
private DPanel dPanel;
private JTextField resultText;
public Calculator(){
// set calc layout
this.setLayout(new BorderLayout(1,1));
dPanel = new DPanel(this); // here is the trick ;)
}
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
resultText.setText(command);
// **** your code ****/
}
}
//**inner class - DPanel**//
public class DPanel extends JPanel{
private JButton digitsButton[];
private JButton dotButton,eqButton;
public DPanel(Calculator parent){
//layout
this.setLayout(new GridLayout(4,3,1,1));
// digits buttons
digitsButton = new JButton[10];
for (int i=9;i>=0;i--){
digitsButton[i] = new JButton(i+"");
digitsButton[i].addActionListener(parent); // using parent as action handler ;)
this.add(digitsButton[i]);
}
}
}
It's a bit off topic but you should definately not use the == operator to compare Strings as you appear to be doing on this line:
if (player[j].getCard(i).getSuit() == Suit.HEARTS.toString()
This is because Strings are pointers, not actual values, and you may get unexpected behaviour using the == operator. Use the someString.equals(otherString) method instead. And also
"String to compare".equals(stringVariable)
is alot better than the other way around
stringVariable.equals("String to compare to")
because in the first example you avoid getting a NullPointerException if stringVariable is null. It just returns false.
Yes, it can be done. It's very simple; in one class you have your buttons, in the other class you just need to implement an ActionListener and just make your //cmd
to separate that button's function. To do this, you need to use e.getActionCommand().equals(buttonActionCommand).
Sample code:
public class Click implements ActionListener{
public Click(
//input params if needed
){
}
public void actionPerformed(ActionEvent e) {
if( e.getActionCommand().equals(buttonActionCommand){
//cmd
}
}
}
To add that listener on your button just do:
buttonTest.addActionListener(new Click());