Java Alter Swing Element from Child Class - java

I'm having a problem with something I don't understand. I have a java class that is building up my program and another class full of functions called by action listeners.
I'm hoping to use the the child's class functions to alter the contents of a JLabel (just an example) using a setter function which doesn't seem to be doing anything and not crashing.
My main class has
public class Parent extends JFrame {
static JPanel dummyPanel = new JPanel();
static JLabel dummyLabel = new JLabel("label");
static JButton dummyButton = new JButton("button");
static Child child = new Child();
public Parent() {
// main setup goes here
// add elements goes here
ActionListener alterLabel = new ActionListener() {
public void actionPerformed(ActionEvent dummyButton) {
child.childFunc();
}
}
dummyButton.addActionListener(alterLabel);
}
// main function goes here
public void newText() {
dummyLabel.setText("altered");
System.out.println("new text function has been executed");
}
}
Then the child I am using to call the function to change the text contains
public class Child {
public void childFunc() {
Parent parent = new Parent();
parent.newText();
}
}
When I click the button it runs and I see it outputs the string which I expect but it does not seem to change the label.
Why is this and is there a way to fix it?

Related

Java - Cannot find the symbol of an inner class that implements an ActionListener

I'm going off of what I saw in a textbook to make an action listener for a button. To do it, I made an inner class. When I try to call the inner class, the error comes up: cannot find symbol.
Here's the code:
package GUI;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ATMGUI extends GUI
{
public ATMGUI()
{
this.makePane();
this.makeButton("Withdraw");
button.addActionListener(new WithdrawListener());
pane.add(button);
this.makeText("Enter amount to withdraw: ");
pane.add(text);
this.makeTextField("Enter amount here");
pane.add(field);
this.makeFrame();
frame.add(pane);
class WithdrawListener implements ActionListener
{
public void actionPerformed(ActionEvent click)
{
System.out.println("This is a test.");
}
}
}
//------------------------------------------------------------------
public void makeFrame()
{
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
}
public void makePane()
{
pane = new JPanel();
pane.setLayout(new GridLayout(3,3));
pane.setVisible(true);
}
public void makeButton(String buttonName)
{
button = new JButton(buttonName);
}
public void makeText(String addText)
{
text = new JLabel(addText);
}
public void makeTextField(String addText)
{
field = new JTextField(addText);
}
}
This is the particular bit that is giving me trouble
button.addActionListener(new WithdrawListener());
I saw somewhere else that it had to be instantiated in a certain way.
I tried something like:
ATMGUI a = new ATMGUI();
ATMGUI.WithdrawListener w = a.new WithdrawListener();
and then put w in for the argument, but that didn't really work for me either.
Not sure if it is because I'm working in a subclass. Also not really sure if things need to be done differently because I'm working with an interface.
Place the WithdrawListener outside of the constructor context
public class ATMGUI extends GUI {
public ATMGUI() {
//...
button.addActionListener(new WithdrawListener());
//...
}
class WithdrawListener implements ActionListener {
public void actionPerformed(ActionEvent click) {
System.out.println("This is a test.");
}
}
Add listener to button after local class declaration.
public void abc(){
PQR pqr = new PQR(); // incorrect
class PQR {
}
}
Correct way is
public void abc(){
class PQR {
}
PQR pqr = new PQR(); //correct
}
It seems like you must declare the local class before you use it. The follwing code snippets I tested:
This one showed no errors:
public void testFunc() {
class Test {
}
Test test = new Test();
}
But this one does:
public void testFunc() {
Test test = new Test();
class Test {
}
}
Edit: Sorry for posting nearly at the same time, next time I will check three times if someone already posted.
Use of anonymous type is recommended when you are not reusing a class.
Have a look at it (frequently used with listeners) - It's a great answer!!
quoted from above link
Using this method makes coding a little bit quicker, as I don't need
to make an extra class that implements ActionListener -- I can just
instantiate an anonymous inner class without actually making a
separate class.
I only use this technique for "quick and dirty" tasks where making an
entire class feels unnecessary. Having multiple anonymous inner
classes that do exactly the same thing should be refactored to an
actual class, be it an inner class or a separate class.
this.makePane();
this.makeButton("Withdraw");
button.addActionListener(new ActionListener() { //starts here
public void actionPerformed(ActionEvent click)
{
System.out.println("This is a test.");
}
});//ends
pane.add(button);
this.makeText("Enter amount to withdraw: ");
pane.add(text);
this.makeTextField("Enter amount here");
pane.add(field);
this.makeFrame();
frame.add(pane);

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

How to change jlabel text from another class

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.

JTree update nodes without collapsing

I have a Java SE 7 application that needs to have the JTree nodes updated. From the tutorial given by Oracle using this thread, there's no given hint on how I could update the label (displayed text of the node on the Tree) on code. Currently I am using DefaultTreeModel as the model of my JTree and DefaultMutableTreeNode as the nodes of the said Tree.
To further detail about the application I am working on, I am developing a chat facility having the contact(s) displayed with their availability status (whether Online, Offline, etc.) per account.
The question is, how can I update the displayed text of a particular node without (at most) removing it from it's parent and adding it on it's designated index. Like a DefaultMutableTreeNode.setText("<new label>")?
UPDATE : January 20, 2013
Redefined the question for clarifications.
Perhaps if you use 'nodeChanged()' instead of 'reload()' you will get the effect you desire.
There are a bunch of methods on the DefaultTreeModel class that cause various parts of the tree to be changed and redrawn. There are also other methods on DefaultTreeModel that only cause redrawing to take place.
You mentioned 'reload(node)' and commented that it causes the tree to collapse when you call it. 'reload' causes the entire sub-tree to be completely redrawn starting at that node. (But if that node isn't visible, it changes nothing.) That is called a 'structure change'.
'insertNodeInto()' and 'removeNodeFromParent()' modify the tree structure by adding or removing the node and then redrawing.
I think 'nodeChanged()' is the one you need since it just notifies the model that something changed in the node that will cause it to display differently. Perhaps the displayable text is now different than it was. Perhaps you changed the user object in the node. That's when you call 'nodeChanged()' on a node.
You should try 'nodeChanged()' in place of the 'reload()' call in your own code that was collapsing and in the example program vels4j provided. This might take care of the problem.
Note that there are also two other families of methods on the DefaultTreeModel that are used in other cases:
These methods work with the tree nodes and use the tree path to define where the change took place. They do not change the data structures underlying the tree but notify the model that something changed so it can notify the listeners that actually redraw things or otherwise respond to changes.
nodesWereInserted()
nodesWereRemovde()
nodesChanged()
nodeStructureChanged()
There are also a set of fire...() methods that are used internally to the DefaultTreeModel and any sub-classes you may create. They merely notify any listeners that something changed. Notice that they are protected.
May this simple and executable program help you to resolve your issue.
public class JTreeDemo extends JPanel
implements Runnable {
private JTree tree;
private DefaultTreeModel treeModel ;
private Random rnd = new Random();
private List<User> userList;
public JTreeDemo() {
super( );
//Create the nodes.
DefaultMutableTreeNode top =
new DefaultMutableTreeNode("Users");
treeModel = new DefaultTreeModel(top);
createNodes(top);
//Create a tree that allows one selection at a time.
tree = new JTree(treeModel);
tree.getSelectionModel().setSelectionMode
(TreeSelectionModel.SINGLE_TREE_SELECTION);
//Create the scroll pane and add the tree to it.
JScrollPane treeView = new JScrollPane(tree);
//Add the split pane to this panel.
add(treeView);
}
public String getRandomStatus() {
int nextInt = rnd.nextInt(100);
if( nextInt%2==0) {
return "Online";
} else {
return "Offline";
}
}
#Override
public void run() {
while(true) {
try {
Thread.sleep(1000);
int nextInt = rnd.nextInt(10);
User user = userList.get(nextInt);
user.setStatus(getRandomStatus());
treeModel.nodeChanged(user);
} catch (InterruptedException ex) {
// handle it if necessary
}
}
}
private class User extends DefaultMutableTreeNode {
public String userName;
public String status;
public User(String name) {
userName = name;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
#Override
public String toString() {
String color = status.equals("Online") ? "Green" : "Red";
return "<html><b color='"+color+"'>"+
userName +"-"+status +"</b></html>";
}
}
private void createNodes(DefaultMutableTreeNode top) {
userList = new ArrayList() ;
for(int i=0;i<10;i++) {
User u1 = new User("User " + (i+1));
u1.setStatus("Online");
top.add(u1);
userList.add(u1);
}
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("TreeDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add content to the window.
JTreeDemo jTreeDemo = new JTreeDemo();
frame.add(jTreeDemo);
frame.pack();
frame.setVisible(true);
// update status randomly
Thread thread = new Thread(jTreeDemo);
thread.start();
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
I've added a Thread to update Status randomly, hope you can modify base on your need.
Output :
Edit:
1. Based on suggestion I've removed reload(node) and added tree model reload.
It's easy if nodes contains objects which are unique in the tree and have implemented method equals and hashCode (for example you show strings or object with unique ID from database). First of all you iterate over all expanded nodes and save objects from the nodes in a set. Then you perform update of the model. After update you iterate over all nodes and if they are in the set you expand the node in the tree.
If nodes are not unique - you need to save in the set the complete tree path (for example as list) and check it after update to expand the nodes.
If objects has neither equals nor hashCode (both these methods must be implemented) - this variant cannot be used.
Just for the record (I voted for Lee Meador), DefaultTreeModel#nodeChanged(javax.swing.tree.TreeNode) is the way to go:
public class TestFrame extends JFrame {
public TestFrame() {
//create gui with simple jtree (and DefaultTreeModel)
JButton changeBtn = new JButton();
final JTree jTree = new JTree();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
changeBtn.setText("update selected node");
getContentPane().add(changeBtn, java.awt.BorderLayout.PAGE_END);
DefaultMutableTreeNode treeNode1 = new DefaultMutableTreeNode("root");
DefaultMutableTreeNode treeNode2 = new DefaultMutableTreeNode("blue");
treeNode1.add(treeNode2);
treeNode2 = new DefaultMutableTreeNode("violet");
DefaultMutableTreeNode treeNode3 = new DefaultMutableTreeNode("red");
treeNode2.add(treeNode3);
treeNode3 = new DefaultMutableTreeNode("yellow");
treeNode2.add(treeNode3);
treeNode1.add(treeNode2);
jTree.setModel(new DefaultTreeModel(treeNode1));
getContentPane().add(jTree, BorderLayout.CENTER);
pack();
//add listener to button, to change selected node on button click
changeBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
DefaultMutableTreeNode dmt = (DefaultMutableTreeNode)jTree.getSelectionPath().getLastPathComponent();
//update content/representation of selected node
dmt.setUserObject("My update: " + new Date());
//nodeChanged
((DefaultTreeModel) jTree.getModel()).nodeChanged(dmt);
}
});
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame().setVisible(true);
}
});
}
}

Setting JLabel Text at Runtime

I am pretty new to Java(about 2 weeks in), and I am trying to set the text of a JLabel. The only problem is I am doing calculations in another class and I don't know how to reference the Jlabel I have already created. Here are the two classes in question.
package fightsim;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class FightSimPane extends JPanel {
FightManager FightManager = new FightManager();
/**
* Create the panel.
*/
public FightSimPane() {
setLayout(new MigLayout("", "[][][][][][][][][][]", "[][][][]"));
JLabel lblChampionleft = new JLabel("ChampionLeft");
add(lblChampionleft, "cell 1 3");
JButton btnGo = new JButton("Go");
btnGo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
FightManager.startFight();
FightManager.runTheFight();
}
});
add(btnGo, "cell 5 3");
JLabel lblChampionright = new JLabel("ChampionRight");
add(lblChampionright, "cell 9 3");
}
public void setLeftChampionLabel(String s){
//not able to reference Jlabel lblChampionLeft here???
System.out.println("Setting Left Champion text to"+s);
}
public void setRightChampionLabel(String s){
//not able to reference Jlabel lblChampionRight here???
System.out.println("Setting Right Champion text to"+s);
}
}
And the class that is trying to set the Label.
package fightsim;
public class FightManager {
Champion LeftChamp = new Champion();
Champion RightChamp = new Champion();
public FightManager() {
}
Thread LeftChampThread = new Thread(LeftChamp);
Thread RightChampThread = new Thread(RightChamp);
;
public void startFight() {
LeftChamp.setHealth(200);
RightChamp.setHealth(300);
LeftChamp.setATKsp(1000);
RightChamp.setATKsp(1000);
LeftChamp.setAD(20);
RightChamp.setAD(20);
}
public void runTheFight() {
System.out.println("Starting Threads");
LeftChampThread.start();
RightChampThread.start();
while ((LeftChamp.getHealth() > 0) && (RightChamp.getHealth() > 0)) {
if (RightChamp.isReadyToAttack()) {
LeftChamp.setHealth(LeftChamp.getHealth() - RightChamp.getAD());
RightChamp.setNotReady();
System.out.println("Setting Left Champion test to"
+ Integer.toString(LeftChamp.getHealth()));
// This is where I'd like to update the left Jlabel in
// FightSimPane
}
if (LeftChamp.isReadyToAttack()) {
RightChamp
.setHealth(RightChamp.getHealth() - LeftChamp.getAD());
LeftChamp.setNotReady();
System.out.println("Setting Right Champion test to"
+ Integer.toString(RightChamp.getHealth()));
// This is where I'd like to update the right Jlabel in
// FightSimPane
}
}
}
}
So, the question...How do I let my FightManager Class access and change the JLabel in my FightSimPane Class/Gui. Thanks in advance, and sorry if this is a stupid question. I am terribly new to programming and I'm still trying to take it all in. With that said, any other advice would be great. Thanks!
Pass references around so that classes can communicate with each other, and not only that but with the correct active instance of the class of the other type. For instance, you could give FlightManager a FlightSimPane field:
class FightManager {
private FightSimPane fightSimPane;
// and fill it in the constructor:
public FightManager(FightSimPane fightSimPane) {
this.fightSimPane = fightSimPane;
}
Then you'll be dealing with the actual visualized FightSimPane GUI object.
Note that you'll have to take care to pass in the correct instance:
public class FightSimPane extends JPanel {
FightManager FightManager = new FightManager(this);
Then you can call the public methods of FightSimPane in the FightManager class:
public void runTheFight() {
System.out.println("Starting Threads");
LeftChampThread.start();
RightChampThread.start();
while ((LeftChamp.getHealth() > 0) && (RightChamp.getHealth() > 0)) {
if (RightChamp.isReadyToAttack()) {
LeftChamp.setHealth(LeftChamp.getHealth() - RightChamp.getAD());
RightChamp.setNotReady();
System.out.println("Setting Left Champion test to"
+ Integer.toString(LeftChamp.getHealth()));
// !!! **** added this *************
fightSimPane.setRightChampionLabel("Setting Left Champion test to"
+ Integer.toString(LeftChamp.getHealth()));
}
EDIT 1
I see another potentially serious and unrelated problem here:
while ((LeftChamp.getHealth() > 0) && (RightChamp.getHealth() > 0)) {
//.........
}
This code appears to be called on the main Swing thread, the EDT and it's nature (while (true)) suggests that it has a very good chance of locking up the EDT bringing your Swing GUI's graphics processing and updating and all user interactions to a screeching halt. You may need to use a Swing Timer for this or a background thread so as to leave the EDT free to do its necessary work.
Declare the reference variable of FightSimPane class in FightManager class and pass the reference of FightSimPane object via the constructor of FightManager.
In FightManager class,
public class FightManager {
Champion LeftChamp = new Champion();
Champion RightChamp = new Champion();
private FightSimPane pane;
public FightManager(FightSimPane pane) { this.pane=pane;}
public FightManager() {
}
....
Using "pane" reference variable you can access accessible elements of FightSimPane class.
Modify the FightSimPane code,
public class FightSimPane extends JPanel {
FightManager fightManager;
public FightSimPane() {
fightManager= new FightManager(this);
...
}

Categories