I got a JLabel Scoresp1 which I want to change using Scoresp1.setText(mijnScore + "");. But the text on the JLabel stays the same.
I got a class Dobbelsteen which looks like this:
public class Dobbelsteen extends Spel {
...
public void aantalOgen(int aantalogen) {
oudepositie = huidigepositie;
nieuwepositie = (huidigepositie + aantalOgen);
if (nieuwepositie == eindronde) {
System.out.println("Speler Piet heeft de ronde gewonnen!");
updateUI();
}
}
}
Which calls updateUI which is in the class Spel
public class Spel {
...
public void updateUI() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ikWin = true;
while(ikWin){
mijnScore = mijnScore+1;
Scoresp1.setText(mijnScore + "");
System.out.println("mijnScore" + mijnScore);
ikWin = false;
positie = 0;
}
}
});
}
...
}
Scoresp1 is declared as public JLabel Scoresp1;. If I use String l = Scoresp1.getText(); I get the right value, but the JLabel doesn't get updated visually.
I've looked at some of you code, and my first concern (other than an over-use of static variables) is that you're using inheritance inappropriately and because of this are calling methods on the wrong reference.
Many classes inherit from Spel but don't appear that they should be doing this. For instance, your Dobbelsteen class inherits from Spel, and yet it also has a separate Spel instance -- why? What Spel object is currently visible at the time this code is run? I doubt it is the one that Dobbelsteen extends. Because of this, I think that you're trying to changing the JLabel that is held by the the Dobbelsteen class, but it is not the "Spel" object that is currently visualized. To properly change the visualized JLabel, you'll need a valid reference to the currently visualized Spel object that holds it, and call the appropriate public method on that class.
In all, you might want to re-write this project from the ground up, with a goal of separating out your model (the data) from the view (the GUI), and with an eye towards good OOP principles.
Edit 1:
This may only be a bandaid, but what if you got your Spel reference passed to you in Dobbelsteen's constructor, something like this (changes noted with !! comments: //!!):
//!! public class Dobbelsteen extends Spel {
public class Dobbelsteen { //!!
int dobbelsteen;
int nieuwepositie;
int nieuwepositie2;
public static String newPos;
public static String newPos2;
int oudepositie;
int oudepositie2;
int huidigepositie = Spel.positie;
// int huidigepositie2 = Spel.positie2;
int aantalOgen = Spel.aantalogen;
int aantalOgen2 = Spel.aantalogen2;
static boolean heeftgewonnen = false;
// !! Spel spiel = new Spel();
Spel spiel; // !!
// !!
public Dobbelsteen(Spel spiel) {
this.spiel = spiel;
}
public void aantalOgen(int aantalogen) {
oudepositie = huidigepositie;
nieuwepositie = (huidigepositie + aantalOgen);
if (nieuwepositie == Spel.eindronde) { //!!
System.out.println("Speler Piet heeft de ronde gewonnen!");
spiel.updateUI(); //!! ****** here in particular ******
} else if (nieuwepositie > Spel.eindronde) {
Spel.positie = huidigepositie; //!!
spiel.output.setText("Je hebt teveel gegooid"); //!!
spiel.output.setForeground(Color.red); //!!
} else {
Spel.oudpositie = oudepositie; //!!
Spel.positie = nieuwepositie; //!!
newPos = String.valueOf(nieuwepositie);
if (SpelHost.host) {
SpelHost.verstuurPositie("Positie" + newPos);
} else if (SpelClient.client) {
SpelClient.verstuurPositie("Positie" + newPos);
}
}
}
}
And call it like so:
class GooiDobbelsteen extends MouseAdapter {
#Override
public void mouseClicked(MouseEvent e) {
aanBeurt = false;
dobbelsteen = new Random();
aantalogen = dobbelsteen.nextInt(6) + 1;
aantalOog = String.valueOf(aantalogen);
Dobbelsteen dobbel = new Dobbelsteen(Spel.this); // !!
dobbel.aantalOgen(aantalogen);
use
public void updateUI() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ikWin = true;
while(ikWin){
mijnScore = mijnScore+1;
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
Scoresp1.setText(mijnScore + "");
}
});
System.out.println("mijnScore" + mijnScore);
ikWin = false;
positie = 0;
}
}
});
}
to have a test
Add a Scoresp1.repaint() to the end of your while loop.
Related
I cannot pass the parameters of the ActionListener interface, method actionPerformed().
I have been trying to use the Runnable interface to overcome this problem, however it's method run() does not have the e.getSource() function which is key in my program!
My program creates nine buttons simultaneously in one class, than using dependency injection and getters the second class gets the information and to uses it to make the buttons functional.
The problem comes from the fact that if I want to activate this functionality I need to use the method actionPerformed(). Which parameters actionPerformed( ActionEvent e ).
I need to pass it into the constructor and than pass it's parameter which is at least for me impossible.
The next thing that I that I tried using was the Runnable interface, however it's method run() does not have the e.Source() function, which I have tried to recreate without any luck.
Class where buttons are made:
public class MakeButtons {
private Parameters p;
...
//constructor
public MakeButtons(Parameters p){
this.p = p;
...
makeNineButtons();
}
//getter
public JButton[] getButtons() {
return buttons;
}
//making the nine buttons buttons.length = 9
private void makeNineButtons() {
for (int i = 0; i < buttons.length; i++) {
panel.getGamePanel().add(buttons[i] = new JButton());
buttons[i].setFont(font);
}
}
}
Class where buttons get functions:
public class ButtonsFunctionality implements ActionListener /* OR Runnable */{
private final MakeButtons makeButtons;
...
//constructor
public ButtonsFunctionality(MakeButtons makeButtons){
this.makeButtons = makeButtons;
...
/*
actionPerformed(???);
or
run()
*/
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("yes");
for (JButton n : makeButtons.getButtons()) {
if (e.getSource() == n) {
//Code
}
}
}
// OR
#Override
public void run() {
System.out.println("yes");
for (JButton n : makeButtons.getButtons()) {
if ( ??? == n) {
//Code
}
}
}
}
This is probably the nth time you've received a newbie question regarding calculators, but I just can't figure it out, been working on it for two to three days. The way I have built my calculator at the moment does not suffice and I know I have to start calculating at the time I press the '=' button, but I simply can't figure out how to do so. Due to this reason I have reverted back to my original calculator code, in which it calculates when I press an operation button (like '+') which didn't work, but I was hoping that that would allow me to properly build on it. Here's the code:
package rekenmachine;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.*;
public class Rekenmachine extends JFrame
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(300,500);
frame.setLocation(800,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Rekenmachine");
RekenPaneel rekenpaneel = new RekenPaneel();
frame.setContentPane(rekenpaneel);
frame.setVisible(true);
}
private static int getal, totaalGetal;
private boolean optellen, aftrekken, vermenigvuldigen, delen;
public int Optellen(int getal)
{
reset();
optellen = true;
totaalGetal += getal;
getal = 0;
return totaalGetal;
}
public int Aftrekken(int getal)
{
reset();
aftrekken = true;
totaalGetal -= getal;
getal = 0;
return totaalGetal;
}
public int Delen(int getal)
{
reset();
delen = true;
totaalGetal /= getal;
getal = 0;
return totaalGetal;
}
public int Vermenigvuldigen(int getal)
{
reset();
vermenigvuldigen = true;
totaalGetal *= getal;
getal = 0;
return totaalGetal;
}
public int getGetal()
{
return getal;
}
public int getTotaalGetal()
{
return totaalGetal;
}
public void reset()
{
optellen = false;
aftrekken = false;
delen = false;
vermenigvuldigen = false;
getal = 0;
totaalGetal = 0;
}
}
class RekenPaneel extends JPanel
{
JButton knop0, knop1, knop2, knop3, knop4, knop5, knop6, knop7, knop8, knop9,
knopOptel, knopAftrek, knopVermenigvuldigen, knopDelen, knopUitkomst,
knopWissen;
JTextField invoerVak;
JPanel textPaneel, knopPaneel, logoPaneel;
Rekenmachine rekenmachine;
public RekenPaneel()
{
rekenmachine = new Rekenmachine();
setLayout(new BorderLayout());
textPaneel = new JPanel();
knopPaneel = new JPanel();
logoPaneel = new JPanel();
textPaneel.setLayout(new FlowLayout());
knopPaneel.setLayout(new GridLayout(4,4));
logoPaneel.setLayout(new FlowLayout());
Border rand = BorderFactory.createEmptyBorder(10, 10, 10, 10);
knop0 = new JButton("0");
knop0.addActionListener(new knop0Handler());
knop1 = new JButton("1");
knop1.addActionListener(new knop1Handler());
knop2 = new JButton("2");
knop2.addActionListener(new knop2Handler());
knop3 = new JButton("3");
knop3.addActionListener(new knop3Handler());
knop4 = new JButton("4");
knop4.addActionListener(new knop4Handler());
knop5 = new JButton("5");
knop5.addActionListener(new knop5Handler());
knop6 = new JButton("6");
knop6.addActionListener(new knop6Handler());
knop7 = new JButton("7");
knop7.addActionListener(new knop7Handler());
knop8 = new JButton("8");
knop8.addActionListener(new knop8Handler());
knop9 = new JButton("9");
knop9.addActionListener(new knop9Handler());
knopOptel = new JButton("+");
knopOptel.addActionListener(new knopOptelHandler());
knopAftrek = new JButton("-");
knopAftrek.addActionListener(new knopAftrekHandler());
knopVermenigvuldigen = new JButton("*");
knopVermenigvuldigen.addActionListener(new knopVermenigvuldigenHandler());
knopDelen = new JButton("/");
knopDelen.addActionListener(new knopDelenHandler());
knopUitkomst = new JButton("=");
knopUitkomst.addActionListener(new knopUitkomstHandler());
knopWissen = new JButton("C");
knopWissen.addActionListener(new knopWissenHandler());
invoerVak = new JTextField(25);
invoerVak.setHorizontalAlignment(invoerVak.RIGHT);
invoerVak.setEditable(false);
invoerVak.setBackground(Color.WHITE);
textPaneel.add(invoerVak);
knopPaneel.add(knop7);
knopPaneel.add(knop8);
knopPaneel.add(knop9);
knopPaneel.add(knopDelen);
knopPaneel.add(knop4);
knopPaneel.add(knop5);
knopPaneel.add(knop6);
knopPaneel.add(knopVermenigvuldigen);
knopPaneel.add(knop1);
knopPaneel.add(knop2);
knopPaneel.add(knop3);
knopPaneel.add(knopOptel);
knopPaneel.add(knop0);
knopPaneel.add(knopWissen);
knopPaneel.add(knopUitkomst);
knopPaneel.add(knopAftrek);
add(textPaneel, BorderLayout.NORTH);
add(knopPaneel, BorderLayout.CENTER);
add(logoPaneel, BorderLayout.SOUTH);
}
class knop0Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "0");
}
}
class knop1Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "1");
}
}
class knop2Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "2");
}
}
class knop3Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "3");
}
}
class knop4Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "4");
}
}
class knop5Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "5");
}
}
class knop6Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "6");
}
}
class knop7Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "7");
}
}
class knop8Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "8");
}
}
class knop9Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "9");
}
}
class knopOptelHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Optellen(invoerGetal);
invoerVak.setText("");
}
}
class knopAftrekHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Aftrekken(invoerGetal);
invoerVak.setText("");
}
}
class knopVermenigvuldigenHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Vermenigvuldigen(invoerGetal);
invoerVak.setText("");
}
}
class knopDelenHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Delen(invoerGetal);
invoerVak.setText("");
}
}
class knopUitkomstHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText("" + rekenmachine.getTotaalGetal());
rekenmachine.reset();
}
}
class knopWissenHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
rekenmachine.reset();
invoerVak.setText("");
}
}
}
What it basically does is look like a calculator, all buttons work, yet the way it calculates is way off, if at all. I think what I need to do is save a number, when I press + it should add the next number, if I press - it should substract the next number, if I press * it should multiply by the next number and if I press / it should divide by the next number, then when I press = it should show the result, yet I have no idea how to do that.
Should it be done with an arraylist? If so, how could I properly save the result? I mean, using it with two numbers isn't that hard, you just save two numbers and do something with them, then show the result, but a person doesn't always use just two numbers.
To explain the problem I'm having more clearly: for example, when I enter '50' and then press '+' it SHOULD convert "50" to getal = 50 and start the Optellen method, then totaalGetal should become 50, it then empties the textfield. If I then add '3', it should say 53 when I press '=' yet it still shows 50 if I'm lucky. To solve that I assume I have to make the calculation WHEN I press '=' but I don't know how to save/calculate numbers before having done that.
Can anybody tell me what to do before I've lost all my hair? :P
When you click on the +, you're calling this:
knopOptel.addActionListener((ActionEvent e) ->
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.addition(invoerGetal);
invoerVak.setText("");
});
But when you click on +, you're not doing the calculation yet! What you should be doing is:
The user type a number
The user click on + (for example)
In your ActionListener, you read the number on the screen, you store it in getal, you clear the screen, and you set your boolean optel to true
The user types another number
The user click on equal
In your equal Listener, you read the number you read the number on the screen, and depending on the flag (optel in the example), you calculate the result
you display the result
So indeed, the calculation is done when you press equal.
A small code example:
knopOptel.addActionListener((ActionEvent e) ->
{
int invoerGetal = Integer.parseInt(invoerVak.getText()); // get the number
calculate(invoerGetal); //sets totalNumber to what it should be by looking at the flags
invoerVak.setText(totalNumber); // we write the temporary result
additionFlag = true; // next number must be added
});
And your calculate function should just be something like:
private void calculate(int aInvoerGetal) {
if (addition)
totalNumber += aInvoerGetal;
else if (substract)
totalNumber -= aInvoerGetal;
else if (divide)
totalNumber /= aInvoerGetal;
else if (multiply)
totalNumber *= aInvoerGetal;
resetFlags();
}
TO GO FURTHER:
Now, if you want to support multiple caculations (5+5+5+3), it's easy. When you click on +, -, *, /, you first call the equalActionListener.
This way, you get this kind of sequence:
5, + // ==> equal called ==> 5 (because the flags are all false) ==> flag + to true
10, + // ==> equal called ==> 15 because 5 in memory and + flag was on. + flag goes off, then on again (because you pressed + again)
4, = // ==> equal called ==> 19
When developing something, you have to think first how you want to solve a problem. Work from there by designing a solution. If you have a programmable solution, implement it. The UI may come later. That's a core skill that a developer should have.
1) You want to have a calculator that support +, -, / and *. The output should be shown if "=" is clicked.
2) Think with classes. That concept may be new for you, but you will discover later from. Your main class that does the calculations is Rekenmachine. (From a design perspective, it should be a stand alone class, but that's not important now). You need to separate it from your UI layer.
Your class supports the actions that you have implemented with the UI. That's good. But I also see things that shouldn't be there
public int Vermenigvuldigen(int getal)
{
reset(); // reset the calculator ?
vermenigvuldigen = true; // purpose ?
totaalGetal *= getal;
getal = 0; // resetting argument getal ?
return totaalGetal;
}
Here, I'm not sure why you're calling reset() because what it does is
public void reset()
{
optellen = false;
aftrekken = false;
delen = false;
vermenigvuldigen = false;
getal = 0;
totaalGetal = 0;
}
When reading the above method, you see that it resets the value that you tried to add on. Of course your calculation would go wrong because you're erasing previous data... resetting everything back to initial state. I also don't understand the setting to "true" or "false" on the actions. Perhaps for the UI? That is not required.
Make it simple:
When creating Rekenmachine, set the variable totaalGetal to 0 as default. That variable holds the value of your calculations performed so far. That's the start. When you have an addition, use
public void add(int getal) {
totaalGetal+= getal; // means totaalGetal = totaalGetal + getal.
}
Before calling add() you have to parse the string to an integer. This can be done in the button action:
class knop1Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
// get input
String input = invoerVak.getText();
// convert
int converted = convertToInt(input);
// instruct myRekenmachine to add the value
myRekenmachine.add(converted);
}
}
Important note ... use concise naming ... "knop1handler" is difficult to read. Use "addButtonHandler" to indicate that this class handles the add button.
convertToInt is a method that reads in a String and returns with an integer. You have to implement that yourself. myRekenmachine is an instance of your Rekenmachine class.
This above is for addition. Implement the same for other operands. If you want to adjust the UI, do that in the handler.
Now, when you press =, just return the totaalGetal value.
PS: Not sure, but ask if you are allowed to write names in English. My native language is Dutch, but during my CS courses, I am allowed to program completely in English. Please try to ask it because English is the main language in IT world if you're aiming for a career in IT.
Wesley, did you think about what you wanted the calculator to do before you started coding? e.g. would it support brackets, sin/cos, memory. Did you think about how logically these functions would work and then think of how they could be implemented in Java? A few flow charts and some pesudocode can go a long way when you're starting out in a new language if only to help you comprehend what it is you are trying to do.
BTW I know it's tempting to start with the GUI code and move into the logic of the application but it is usually better to start with the logic and then move onto the GUI. You can hard code the values for inputs and see if the functionaly behaves as expected and then introduce parameters with values passed in from else where.
EDIT
I think I know why your + key is not working. The reset() method is setting getal and totalGetal to 0 before adding them. 0 + 0 is 0.
knopOptel = new JButton("+");
knopOptel.addActionListener(new knopOptelHandler());
class knopOptelHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Optellen(invoerGetal);
invoerVak.setText("");
}
}
public int Optellen(int getal)
{
reset();
public void reset()
{
optellen = false;
aftrekken = false;
delen = false;
vermenigvuldigen = false;
getal = 0;
totaalGetal = 0;
}
optellen = true;
totaalGetal += getal;
getal = 0;
return totaalGetal;
}
I have two classes in same package. i have declared a static variable in one class and want to access that variable in another class.
Here is my code in which i have declared the static variable
public class wampusGUI extends javax.swing.JFrame {
static String userCommand;
public wampusGUI() {
initComponents();
}
public void setTextArea(String text) {
displayTextArea.append(text);
}
private void enterButtonActionPerformed(java.awt.event.ActionEvent evt) {
userCommand = commandText.getText();
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
wampusGUI w = new wampusGUI();
w.setVisible(true);
Game g = new Game(w);
g.play();
}
});
}
}
Here is the code in which i want to access variable
public class Game {
private wampusGUI gui;
public Game(wampusGUI w) {
world = new World();
world.start();
gui = w;
}
public void play() {
gui.setTextArea(welcome());
gui.setTextArea(describe());
for (;;) {
String s = userCommand; // here value should come should
System.out.println(userCommand);
Command c = Command.create(s);
String r = c.perform(world);
// is game over?
if (r == null) {
break;
}
System.out.println(r);
}
System.out.println("Game over");
}
}
However, i can pass the variable from first class as a argument. but the problem is that, when i will run program the value is going null first time, which i dont want. i want when i enter value in textfield then it should go to another class.
Thank you.
Looking at your code, it seems you want to show dialogs to your user with a certain text
gui.setTextArea(welcome());
gui.setTextArea(describe());
and sometimes, that dialog should capture user input which is handled afterwards.
Those setTextArea calls are not what you want to use. The user will never see the welcome message as it will immediately be replaced by the describe message.
Make sure you do not block the Event Dispatch Thread (EDT) or nothing will be shown at all. I do not know what your Command class will do, but I see an infinite loop on the Event Dispatch Thread which is never a good thing. Take a look at the Concurrency in Swing tutorial for more information
Thanks to that for loop, the user will simply not be capable to input any command as the EDT is busy handling your loop. What you need is a blocking call allowing the user to provide input (not blocking the EDT, but just blocking the execution of your code). The static methods in the JOptionPane class are perfectly suited for this (e.g. the JOptionPane#showInputDialog). These methods also have a mechanism to pass the user input back to the calling code without any static variables, which solves your problem.
I suggest that you use a listener of one sort or another to allow the Game object to listen for and respond to changes in the state of the GUI object. There are several ways to do this, but one of the most elegant and useful I've found is to use Swing's own innate PropertyChangeSupport to allow you to use PropertyChangeListeners. All Swing components will allow you to add a PropertyChangeListener to it. And so I suggest that you do this, that you have Game add one to your WampusGUI class (which should be capitalized) object like so:
public Game(WampusGUI w) {
gui = w;
gui.addPropertyChangeListener(new PropertyChangeListener() {
// ....
}
This will allow Game to listen for changes in the gui's state.
You'll then want to make the gui's userCommand String a "bound property" which means giving it a setter method that will fire the property change support notifying all listeners of change. I would do this like so:
public class WampusGUI extends JFrame {
public static final String USER_COMMAND = "user command";
// ....
private void setUserCommand(String userCommand) {
String oldValue = this.userCommand;
String newValue = userCommand;
this.userCommand = userCommand;
firePropertyChange(USER_COMMAND, oldValue, newValue);
}
Then you would only change this String's value via this setter method:
private void enterButtonActionPerformed(java.awt.event.ActionEvent evt) {
setUserCommand(commandText.getText());
}
The Game's property change listener would then respond like so:
gui.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
// is the property being changed the one we're interested in?
if (WampusGUI.USER_COMMAND.equals(pcEvt.getPropertyName())) {
// get user command:
String userCommand = pcEvt.getNewValue().toString();
// then we can do with it what we want
play(userCommand);
}
}
});
One of the beauties of this technique is that the observed class, the GUI, doesn't have to have any knowledge about the observer class (the Game). A small runnable example of this is like so:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
public class WampusGUI extends JFrame {
public static final String USER_COMMAND = "user command";
private String userCommand;
private JTextArea displayTextArea = new JTextArea(10, 30);
private JTextField commandText = new JTextField(10);
public WampusGUI() {
initComponents();
}
private void setUserCommand(String userCommand) {
String oldValue = this.userCommand;
String newValue = userCommand;
this.userCommand = userCommand;
firePropertyChange(USER_COMMAND, oldValue, newValue);
}
private void initComponents() {
displayTextArea.setEditable(false);
displayTextArea.setFocusable(false);
JButton enterButton = new JButton("Enter Command");
enterButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
enterButtonActionPerformed(evt);
}
});
JPanel commandPanel = new JPanel();
commandPanel.add(commandText);
commandPanel.add(Box.createHorizontalStrut(15));
commandPanel.add(enterButton);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainPanel.add(new JScrollPane(displayTextArea));
mainPanel.add(commandPanel, BorderLayout.SOUTH);
add(mainPanel);
}
public void setTextArea(String text) {
displayTextArea.append(text);
}
private void enterButtonActionPerformed(java.awt.event.ActionEvent evt) {
setUserCommand(commandText.getText());
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
WampusGUI w = new WampusGUI();
w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
w.pack();
w.setLocationRelativeTo(null);
w.setVisible(true);
Game g = new Game(w);
g.play();
}
});
}
}
class Game {
private WampusGUI gui;
public Game(WampusGUI w) {
gui = w;
gui.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
// is the property being changed the one we're interested in?
if (WampusGUI.USER_COMMAND.equals(pcEvt.getPropertyName())) {
// get user command:
String userCommand = pcEvt.getNewValue().toString();
// then we can do with it what we want
play(userCommand);
}
}
});
}
public void play() {
gui.setTextArea("Welcome!\n");
gui.setTextArea("Please enjoy the game!\n");
}
public void play(String userCommand) {
// here we can do what we want with the String. For instance we can display it in the gui:
gui.setTextArea("User entered: " + userCommand + "\n");
}
}
I agree with Jon Skeet that this is not a good solution...
But in case u want an dirty solution to ur problem then u can try this:
public class wampusGUI extends javax.swing.JFrame
{
private static wampusGUI myInstance;
public wampusGUI( )
{
myInstance = this;
initComponents();
}
public static void getUserCommand()
{
if(myInstance!=null)
{
return myInstance.commandText.getText();
}
else
{
return null;
}
}
......
......
}
in the other class use:
public void play()
{
.....
//String s = userCommand; // here value should come should
String s = wampusGUI.getUserCommand();
.....
}
This kind of code is there in some of our legacy projects... and I hate this.
When trying to save an arraylist of my class Click, I get this error: java.io.NotSerializableException:javax.swing.text.DefaultHighlighter$LayeredHighlightInfo
on this line of code: os.writeObject(saveList);. Even though I made my Click class implement serializable. Does anyone know the cause of this?
Here is my save Method:
public static void saveArray(ArrayList<Click> saveList) {
JFileChooser c = new JFileChooser();
c.showSaveDialog(new JFrame());
File f = c.getSelectedFile();
try {
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(
f.getAbsolutePath()));
os.writeObject(saveList);
} catch (IOException e1) {
e1.printStackTrace();
}
}
And here is my Click class:
public static class Click implements Serializable {
JTextField xClickField;
JTextField yClickField;
JTextField clickIntervalField;
JTextField repeatTimesField;
boolean isLeft;
Integer clickX;
Integer clickY;
Integer clickInterval;
Integer clickTimes;
public Click(boolean left){
xClickField = new JTextField();
yClickField = new JTextField();
clickIntervalField = new JTextField();
repeatTimesField = new JTextField();
clickX = 0;
clickY = 0;
clickInterval = 0;
clickTimes = 0;
isLeft = left;
addToJPanel();
}
public void addToJPanel() {
xClickField.setText(clickX.toString());
yClickField.setText(clickY.toString());
clickIntervalField.setText(clickInterval.toString());
repeatTimesField.setText(clickTimes.toString());
panel.add(xClickField);
panel.add(yClickField);
panel.add(clickIntervalField);
panel.add(repeatTimesField);
frame.setVisible(false);
frame.setVisible(true);
}
public void removeFromJPanel() {
panel.remove(xClickField);
panel.remove(yClickField);
panel.remove(clickIntervalField);
panel.remove(repeatTimesField);
frame.setVisible(false);
frame.setVisible(true);
}
}
By the way I took out a chunk of code from the Click class. So if you think that the error could be in that portion of the code, I will gladly add it in.
Thanks in advance!
Implementing Serializable is not sufficient to make an object serializable. For example, a Socket is not serializable: it doesn't make sense to serialize a socket. So, if you have a Foo class that has a field of type Socket and that implements Serializable, how do you intend to serialize a Foo instance. It won't work. All the fields of a serializable object msut also be serializable, recursively.
And, as Hovercraft says in his comment, you should serialize data, not swing components.
You're serializing JTextFields and other Swing components which is a waste of time and resources and is completely unnecessary. You should be serializing the state of your GUI, the data held by the class's fields. If you understand MVC, you should be serializing the model, not the view. If you don't understand MVC, Google it or read this article and learn the key concepts as they are key to creating GUI programs in any language.
Also, for my money, I'd use JAXB or some other XML-based tool to serialize your data as it is saved in text format and thus understandable when read.
Example of separating GUI from model and using a property change listener to listen and respond to property changes:
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
public class SimpleClickEg {
private static void createAndShowGui() {
SimpleClickPanel clickPanel = new SimpleClickPanel();
JFrame frame = new JFrame("SimpleClickEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(clickPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class SimpleClickPanel extends JPanel {
private static final int PREF_WIDTH = 800;
private static final int PREF_HIEGHT = 600;
private JTextField clickCountField = new JTextField(5);
private JTextField clickXField = new JTextField(5);
private JTextField clickYField = new JTextField(5);
private SimpleClick click = new SimpleClick();
public SimpleClickPanel() {
add(new JLabel("Click X:"));
add(clickXField);
add(new JLabel("Click Y:"));
add(clickYField);
add(new JLabel("Click Count:"));
add(clickCountField);
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
click.setClickPoint(e.getPoint());
}
});
click.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (SimpleClick.CLICK_COUNT.equals(evt.getPropertyName())) {
clickCountField.setText(String.valueOf(click.getClickCount()));
} else if (SimpleClick.CLICK_X.equals(evt.getPropertyName())) {
clickXField.setText(String.valueOf(click.getClickX()));
} else if (SimpleClick.CLICK_Y.equals(evt.getPropertyName())) {
clickYField.setText(String.valueOf(click.getClickY()));
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_WIDTH, PREF_HIEGHT);
}
public SimpleClick getClick() {
return click;
}
}
class SimpleClick implements Serializable {
private static final long serialVersionUID = 1L;
public static final String CLICK_COUNT = "click count";
public static final String CLICK_X = "click x";
public static final String CLICK_Y = "click y";
private int clickCount;
private int clickX;
private int clickY;
private transient SwingPropertyChangeSupport spcSupport = new SwingPropertyChangeSupport(
this);
public int getClickCount() {
return clickCount;
}
public void setClickCount(int clickCount) {
Integer oldValue = this.clickCount;
Integer newValue = clickCount;
this.clickCount = newValue;
spcSupport.firePropertyChange(CLICK_COUNT, oldValue, newValue);
}
public void incrementClickCount() {
setClickCount(getClickCount() + 1);
}
public void setClickPoint(Point p) {
setClickX(p.x);
setClickY(p.y);
incrementClickCount();
}
public int getClickX() {
return clickX;
}
public void setClickX(int clickX) {
Integer oldValue = this.clickX;
Integer newValue = clickX;
this.clickX = newValue;
spcSupport.firePropertyChange(CLICK_X, oldValue, newValue);
}
public int getClickY() {
return clickY;
}
public void setClickY(int clickY) {
Integer oldValue = this.clickY;
Integer newValue = clickY;
this.clickY = newValue;
spcSupport.firePropertyChange(CLICK_Y, oldValue, newValue);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
spcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
spcSupport.removePropertyChangeListener(listener);
}
}
As you can see the error clearly states that javax.swing.text.DefaultHighlighter is not serializable.
Now this class is used by composition inside the JTextField, which is a GUI component and it is not meant to be serialized. From your code it seems that you don't need to serialize the fields themselves, so just mark them as transient and you are done.
As a side note: it is always good to split what is your data from what is your GUI so that you can easily serialize just data and foget about anything concerning the GUI. This helps in general, not just in serialization, to preserve encapsulation and use OOP as it is meant to be used.
The problem is that your Click class has references to JTextField instances, and these (presumably) have references to some Swing class called DefaultHighlighter.LayeredHighlightInfo ... and that is not serializable.
You probably need to declare the 4 JTextField variables as transient. As a general rule, Java GUI classes such as Swing components are not effectively serializable.
First of all i am brand new to Java : /
I have been trying to solve this problem on my own for about 2 days now but cant get around it the problem is i am trying to implement a variable change listener. I have tried without successes to implement Observer and Observable to my project but whit no successes at best i came up by wrapping some elements of the code in to while loops but that well fails.
Any how this is my class and if you look at it i have some global variables defined after the constructor i need to listen for a change in all of those global variables if one changes i would like to execute a method.
I have been told JavaFX has methods that can listen to variables can someone confirm this.
Anyhow thanks for help in advance.
public class Tower_Controller {
public Tower_Controller() {
}
//Global variables
String isSelected = null;
int hasModules = 0;
int cap_s = 0;
int cpu_s = 0;
int cap = 0;
int cpu = 0;
int shield = 0;
int armor = 0;
double em = 00.00;
double th = 00.00;
double ki = 00.00;
double ex = 00.00;
public void invoke() {
Invoke_GUI runnable = new Invoke_GUI();
final JLabel tower_name = runnable.tower_name;
final JComboBox tower_select = runnable.tower_select;
final JTree module_browser = runnable.module_browser;
final JTree selected_modules = runnable.selected_modules;
final JProgressBar cap_bar = runnable.cap_bar;
final JProgressBar cpu_bar = runnable.cpu_bar;
final JLabel em_res = runnable.em;
final JLabel th_res = runnable.thermic;
final JLabel ki_res = runnable.kinetic;
final JLabel ex_res = runnable.explosive;
tower_select.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (isSelected != null) {
Events evt = new Events();
evt.towerSelected(isSelected);
} else {
tower_name.setText(tower_select.getSelectedItem().toString());
isSelected = tower_name.toString();
}
}
});
removeTower(tower_name);
runnable.setVisible(true);
}
public void updateValues(final JProgressBar cap_bar, final JProgressBar cpu_bar, final JLabel em_res,
final JLabel th_res, final JLabel ki_res, final JLabel ex_res){
cap_bar.setMaximum(cap);
cap_bar.setString(cap_s + " / " + cap);
cap_bar.setStringPainted(true);
cpu_bar.setMaximum(cpu);
cpu_bar.setString(cpu_s + " / " + cpu);
cpu_bar.setStringPainted(true);
String em_v = String.valueOf(em);
em_res.setText(em_v);
String th_v = String.valueOf(th);
th_res.setText(th_v);
String ki_v = String.valueOf(ki);
ki_res.setText(ki_v);
String ex_v = String.valueOf(ex);
ex_res.setText(ex_v);
}
public void updateList(final ArrayList<String> nodes, final JTree selected_modules) {
DefaultMutableTreeNode nod = new DefaultMutableTreeNode();
for (int i = 0; i < nodes.size(); i++) {
nod.add(new DefaultMutableTreeNode(nodes.get(i)));
}
selected_modules.setModel(new DefaultTreeModel(nod));
}
public void removeTower(final JLabel tower_name) {
tower_name.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
if (hasModules == 1 & isSelected != null) {
Events evt = new Events();
evt.towerHasModules();
} else if (isSelected == null) {
} else {
tower_name.setText("No Control Tower selected");
isSelected = null;
}
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
}
public JLabel setTowerName(JLabel a, String name) {
a.setText(name);
return a;
}
}
The general procedure to be notified of a change to a variable is as follows:
First, make the variables private.
Create two methods for each variable, one which sets its value to an argument (often called setX(), where X is the variable name), the other which retrieves its value (getX())
Everywhere you need to read or set the variable, call the methods instead.
In the setX() method, call notifyObserver() on your Observers, in a loop.
And there you go! Now every time the variable is changed, registered Observers are notified. The key part of this solution is that the variables have to be private, so that no code can set their values without going through the setX() methods.