How to change jlabel text from another class - java

Hi I'm making an app but, I found a problem. I'm using netbeans gui builder to build my gui.
So, the first gui class has a lot of button(every button does the same function) that have an actionlistener that looks like this:
public class Guipanel extends JPanel {
private void jbtTTActionPerformed(java.awt.event.ActionEvent evt) {
if(mb.getlevel() > 16){
if(ttp != 20 && mb.getpoints() != 0){
point();
ttp++;
jbtTT.setText(""+ttp);
}
}
}
private void point(){
mb.reducepoints();
}
int ttp;
Base mb = new Base();
JButton jbtTT = new JButton();
}
The Base Class has a lot of method but the one that is related to this problem looks like this:
public class Base extends JFrame {
//point decrement method
public void reducepoints(){
points--;
jlbPoints.setText("Points Available: "+points);
}
//return point value
public int getpoints(){
return this.points;
}
//return level value
public int getlevel(){
return this.level;
}
private static int level = 1;
private static int points = 20;
private JLabel jlbPoints = new JLabel("Points Available: "+points);
}
So the problem is this, when I pressed the jbtTT the points variable will decrement so the value will change from 20 to 19. I used System.out.println to verify that. As you can see, the reducepoints() method should update the jlbPoints text which it doesnt. I have tried making the Base mb = new Base() to static Base mb = new Base() but it still doesn't work. Am I doing this wrong? Anyone have a suggestion?
EDIT: I've tried to do System.out.println(jlbPoints.getText()); and the text did changed. The only one that didn't change is the text that the user can see. Even repaint() and revalidate didn't work.
EDIT2: I finally found the answer to this question. I have to pass the 'Base' class object to the 'Guipanel' class since I created the 'Base' class object in a main class(I don't want to use this class as a main class). I passed it with the following method:
public void passObj(Base mb){
this.mb = mb;
}
and changing the constructor of 'Guipanel' class like this:
public Guipanel(Base mb) {
initComponents();
this.mb = mb;
}
also changing this Base mb = new Base(); to Base mb;
I wanted to thank everyone that have tried to answer this question.

Try using SwingUtilities.invokeLater() to ensure you are changing the text on the event dispatch thread, as you are supposed to. All we can do is guess given the current information.

Related

Java- How to ask "if a JButton is disabled then ___"

so I'm a 6th grader who's trying to program a TicTacToe program using netbeans 8.1 and java.
This is my code so far (for the sake of simplicity i've only included the code of one button):
public class TicTacToe extends JFrame{
static Random computerGenerate = new Random();
static int rounds = 0;
static JPanel panel = new JPanel();
static JButton s1 = new JButton();
public static void main(String[] args) {
Gui();
}
public static void Gui() {
JFrame Gui = new JFrame("TicTacToe");
Gui.setVisible(true);
Gui.setResizable(false);
Gui.setSize(320, 340);
Gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setLayout(null);
Gui.add(panel);
s1.setBounds(0, 0, 100, 100);
s1.setFont(new Font("Times New Roman", Font.PLAIN, 50));
s1.addActionListener(new Response());
panel.add(s1);
}
private static class Response extends TicTacToe implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == tictactoe.TicTacToe.s1) {
s1.setText("X");
s1.setEnabled(false);
rounds += 1;
}
}
}
public static void Moves() {
if (rounds == 1) {
int computerStartPos = 1 + computerGenerate.nextInt(8);
switch (computerStartPos) {
case 1:
if (button"s1" is disabled)) {
computer will generate a new starting position for the AI
} else {
button s1 will be disabled and it will show a "O" to show the computer has selected the square
}
break;
}
}
}
}
The section which I have a problem with is the very last method, method Moves().
What I'm trying to do is, after the player has selected their starting square, the computer will generate a number, 1-9 which will determine its own starting position.
The problem I have is if the player has already selected that button before the computer, I need the computer to re-generate a new number as its starting point.
My idea to solve this is "if s1.setEnabled() is equal to false, then the computer will re-generate a new number which corresponds to its new starting position".
Is this posible to write? This is only a small time project but I would appreciate the help.
Oh, and I have been told I'm incorrectly using static in java, however if I don't include "static" in the code netbeans gives me errors for days until all of my code is like RED ERROR!!!! If anyone knows why or can explain how to properly use it please do as well :D
I sincerely appreciate any help I receive.
There is a method for checking whether a button is enabled or not...
if (button.isEnabled()) {
}else {}
and
if I don't include "static" in the code netbeans gives me errors for
days until all of my code is like RED ERROR!!
you Cannot make a static reference to the non-static field...
try dont using static things and create instances instead...
you can use as start point:
remove the static keyword from the fields, define a construtor and create an instance in the main method..
like this:
// YOU NEED A CONSTRUCTOR
public TicTacToe () {
computerGenerate = new Random();
panel = new JPanel();
s1 = new JButton();
}
public static void main(String[] args) {
TicTacToe demoExample = new TicTacToe ();
demoExample.Gui();
}
Static methods in java belong to the class (not an instance of it).
They use no instance variables and will usually take input from the
parameters, perform actions on it, then return some result
Secondly yes you can check that.
if(! s1.isEnabled())
{
...
}
Remember there is ! at the start of the condition which will check for enabled or not!

Passing variable set in one Jframe from one to another

I have one JFrame called User where I declare a variable called id and set it to a certain value depending on some conditions.
I need to use this variable in a second JFrame called output.
This is the code I have
class InputScreen extends javax.swing.JFrame {
public int id = 0;
private void submitButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (condition){
id = 1;
System.out.println(id);
}
elseif (condition){
id = 2;
System.out.println(id);
}
elseif (condition){
id = 3;
System.out.println(id);
}
else{
System.exit(0);
}
I used a constructor in the frame Output but it doesn't seem to work.
public class Output extends javax.swing.JFrame {
int rule;
public Output(int Id){
rule = Id;
initComponents();
}
public Output() {
initComponents();
conn = MySqlConnect.ConnectDB();
}
Updated Code
Frame - Input
class InputScreen extends javax.swing.JFrame {
public int id = 0;
public int getID(){
return input_rule_id;
}
private void submitButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (condition){
id = 1;
System.out.println(id);
}
elseif (condition){
id = 2;
System.out.println(id);
}
elseif (condition){
id = 3;
System.out.println(id);
}
Form - Output
private void formWindowActivated(java.awt.event.WindowEvent evt) {
Input InSc = new Input();
InSc.getId();
}
All primitive data-types will be passed by the value. Use an object wrapper to pass the value by the reference. For example AtomicInteger
class InputScreen extends javax.swing.JFrame {
private AtomicInteger id = new AtomicInteger(0);
private void submitButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (condition){
id.set(1);
System.out.println(id);
}
else if (condition){
id.set(2);
System.out.println(id);
}
else if (condition){
id.set(3);
System.out.println(id);
}
else{
System.exit(0);
}
}
public class Output extends javax.swing.JFrame {
AtomicInteger rule;
public Output(AtomicInteger Id){
rule = Id;
initComponents();
}
public Output() {
initComponents();
conn = MySqlConnect.ConnectDB();
}
}
Parameter passing
The most simple way would be passing Output as a parameter to InputScreen. Then you might just call a method Output.setId(id) within your InputScreen.submitButtonActionPerformed() logic. This way however is a bit problematic, when the application grows.
Observer Pattern
A better way would be realizing a IdChangedListener as part of an Observer pattern as a proxy to the ActionListener you already have implemented. When your ActionListener fires, you call all IdChangeListeners that have registered as Observers to InputScreen. In Output you provide a method setId(id) to provide access. In the place you instantiate the two JFrames you implement an IdChangeListener, add it to InputScreen and when it fires you call Output.setId().
Anyway, you see a lot of work (and code) for just one event. Also this approach has its limitations concerning application size and dynamic.
In Memory EventBus
The up-to-date approach would be using a in memory EventBus. This eliminates the hard-wiring of the components within your UI and reduces the code size. However, it limits the reuse of components because they will be automatically react to some events. What if you have them more than once? Listening to different Events?
You need to think about where you want to use which approach. I would suggest using an EventBus for event propagation between the concrete components of your application. Use Observer pattern on medium size components while use parameter passing for small size or very static ones.
You can use getters and setter. Define a getter method in your Frame from where you want to pass the id variable. eg
public int getID(){
return id;
}
In your other frame you can just use this method to return the result. int id = getID();
Another work around for this problem is making the variable globe and static so it can be imported in the other frame and be used.

java Passing variables from one class to another

I have an error for the code below. Sorry if this is too basic as I am new to java.
Basically, I cannot retrieve the String "44418" from the class CityChange.
I know the reason is because I created a new instance cc in the class MainPanel.
However I do not know any other way of doing it.
public class CityChange extends JPanel {
public CityChange() {
JButton btn1 = new JButton("London")
this.add(btn1);
btn1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
//London Yahoo Weather Code 44418
setCitySelected("44418");
}
});
}
public void setCitySelected(String citySelected) {
this.citySelected = citySelected;
}
public String getCitySelected() {
return citySelected;
}
private String citySelected;
}
public class MainPanel extends JPanel {
public MainPanel() {
CityChange cc = new CityChange();
System.out.println(cc.getCitySelected()); //returns null instead of 44418
}
}
Please give some advice. Thank you.
For timing reasons, the value has no choice but to be null.
What happens here "immediately" (at init time) is that a new CityChange object is created and its citySelected is gotten and printed. As nobody set it otherwise, it is null.
Only after firing the event (clicking the button), it gets a value, and if you print the value then, you'll see the new value.
The code setCitySelected("44418"); is only executed when you call the method public void actionPerformed(ActionEvent evt) which is not happening at the moment. This Method is only called via a Button in a GUI so you first need at least a simple Window with a Button. Here is a good example http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html

Accessing an instance of a class in an arraylist loop

So I have a class LayerCopper that holds a few textboxes and a few methods to set values in those textboxes:
public class LayerCopper extends javax.swing.JPanel {
public LayerCopper() {
initComponents();
}
private static javax.swing.JFormattedTextField CuWeightTextField;
private static javax.swing.JFormattedTextField LayerNumJFormattedTextField;
...
...
...
public void setLayerNumberText(int layerNumber) {
LayerNumJFormattedTextField.setText("" + layerNumber);
}
public void setLayerCuThickness(double CuThickness) {
CuWeightTextField.setValue(CuThickness);
}
}
I also have another class StackupCalculator with multiple instances of the LayerCopper panels in it. I have an arraylist that holds each instance of the LayerCopper panel:
static ArrayList<LayerCopper> layerSet_Copper = new ArrayList<>();
...
...
...
public void createLayerSetArray() {
layerSet_Copper.add(layerCopper1);
layerSet_Copper.add(layerCopper2);
layerSet_Copper.add(layerCopper3);
layerSet_Copper.add(layerCopper4);
layerSet_Copper.add(layerCopper5);
initializeLayerArrayValues();
}
When my initializeLayerArrayValues runs, It's supposed to populate a couple textfields with text:
private void initializeLayerArrayValues() {
for (int i = 0; i < layerSet_Copper.size(); i++) {
layerSet_Copper.get(i).setLayerNumberText(i + 1);
layerSet_Copper.get(i).setLayerCuThickness(0.750);
}
}
When I run the program though it doesn't update the fields. I'm guessing I am calling the main class LayerCopper and not the instanced version of it? How would I call the instanced version of the layer?
According to you, you haven't instantiated LayerCopper. You need to make a new instance of it, and make layerCopper1, layerCopper2, etc. Then use createLayerSetArray().
Like so:
LayerCopper lc = new LayerCopper();
// create values different layerCoppers to go in layerSet_Copper
lc.createLayerSetArray();
I don't quite understand the inner workings of your class, so I could be wrong.
Changing the textfields from static to non-static fixed it for me. /cheers

Java how and where to initialize variable with NullPointerException

I'm having a problem where I receive this error:
Exception in thread "main" java.lang.NullPointerException
at com.noxia.Main.startCombat(Main.java:101)
at com.noxia.Area1.createArea1Enemy(Area1.java:43)
at com.noxia.Main.main(Main.java:30)
I know that I need to initialize the variables because they are null, but I can't seem to figure out what I need to put where. I've minimized the code to show just the relevant parts as there are many other variables and methods left out, but this seems to pertain to the issue. Any help would be greatly appreciated =)
public class Main {
Player p;
Enemy e;
Area1 a1;
public static void main(String[] args) {
Main main = new Main();
main.a1 = new Area1();
main.p = new Player(100);
//the line directly below this is line 30 where the error occurs
main.a1.createArea1Enemy(10);
}
public void startCombat()
{
//the line directly below this is line 101 where the error occurs
while (p.getCurrentLife() > 0 & a1.e.getLife() > 0)
{
p.playerAttack();
if (p.getCurrentLife() > 0 & a1.e.getLife() > 0)
{
e.enemyAttack();
}
}
}
public class Player extends Main {
private int currentLife;
public int getCurrentLife()
{
return currentLife;
}
public void setCurrentLife(int cl)
{
currentLife = cl;
}
public Player(int cl)
{
currentLife = cl;
}
public class Enemy extends Main {
private int life;
public int getLife()
{
return life;
}
public void setLife(int lf)
{
life = lf;
}
public Enemy (inf lf)
{
life = lf;
}
public class Area1 extends Main {
public void createArea1Enemy(int enemyCounter)
{
while (enemyCounter > 0)
{
String[] enemyList = {"Enemy1", "Enemy2"} //code for Enemy2 left out below
int enemyListLength = enemyList.length;
int randomEnemy = (int) (Math.random() * enemyListLength);
if (enemyList[randomEnemy].equals("Enemy1"))
{
Enemy enemy1 = new Enemy("Enemy1", 100);
//the line directly below this is line 43 where the error occurs
startCombat();
}
enemyCounter--;
}
}
}
The simple answer is that you have to set e to an enemy before calling startCombat.
But a better way to do this would be to remove e, and pass the enemy object to startCombat using a method parameter. The e field is conceptually wrong. To understand the wrongness, try to come up with a coherent explanation of what it means in terms of the state of a Main object.
Clearly this is beginner code ... and there are a number of bad things about what you have written:
The fields of a class should be for object state, not for passing parameter values to methods.
You should avoid writing code that accesses the innards of a class ... like your main method does.
Best practice is to make fields private, and defined getter and / or setter methods (as required) for external classes to access / modify them.
You need to learn how to write constructors with parameters.
You need to design your code properly. Everything extending Main means that there is going to be no rational model of what the objects "mean". And there's the problem that each instance of Enemy and Area1 will have their own copies of the p, e, and a1 fields, and a whole bunch of inappropriate methods.
The main problem is that you never initialize Enemy e;. You create an enemy but never assign it to this.e.
Change this line:
Enemy enemy1 = new Enemy("Enemy1", 100);
To this:
this.e = new Enemy("Enemy1", 100);
There are also many other problems with your code.
Learn how to write a constructor properly. This code is wrong.
I see no reason at all why a Play, Area1, and Enemy should extend Main.

Categories