Retrieving data from anonymous class - java

I was wondering how to retrieve the string textOperandValue,from this code :
final JTextField textOperand = new JTextField();
textOperand.setBounds(200,100,75,25);
//textOperand action Listener
textOperand.addActionListener( new ActionListener () {
public void actionPerformed(ActionEvent e) {
String textOperandValue = textOperand.getText();
}
});
So I can take it, and then parse it into a double to be used later in the program. I tried setting it equal to a another string
String Input = " "; but it said I had to initialize the string to a final String Input = " "; which I learned is something like a constant in C++.

Any variables you declare within an ActionListener won't be visible to the rest of your code. Either you need to set a variable (from within the listener) that has wider scope:
public class Listen
{
String usefulResult = null;
public Listen()
{
final JTextField textOperand = new JTextField();
textOperand.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Listen.this.usefulResult = textOperand.getText();
}
});
}
}
Here we use the "OuterClass.this" trick to access the surrounding scope without needing a final variable.
or you need to perform all the necessary work from within the listener itself (i.e. you don't "retrieve" the value, you just use the value):
public void doSomethingUseful(String usefulValue) { /* add code here */ }
textOperand.addActionListener( new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
doSomethingUseful(textOperand.getText());
}
});
Or you could use this second technique to call a setter method that changes the value of a variable, avoiding the problems of accessing final variables within event listeners:
public class Listen
{
String usefulResult = null;
public void setUseful(String usefulValue){
usefulResult = usefulValue;
}
public Listen()
{
final JTextField textOperand = new JTextField();
textOperand.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setUseful(textOperand.getText());
}
});
}
}
It depends what you want to do with the value from the TextField.

You can't access the members of anonymous classes. In this case it's even a local variable in a method, those are never accessible.
Either, you'll have to set the value of a member of the outer class, but beware of synchronization trouble.
class MyClass {
final JTextField textOperand = new JTextField();
public String textOperandValue;
public MyClass() {
textOperand.setBounds(200,100,75,25);
//textOperand action Listener
textOperand.addActionListener( new ActionListener () {
public void actionPerformed(ActionEvent e) {
textOperandValue = textOperand.getText();
}
});
}
public someOtherMethod() {
// textOperandValue available here
if (textOperandValue != null)
//is set
}
}
Or, you'll have to call a method somewhere else that can store the value.
class MyClass {
final JTextField textOperand = new JTextField();
public MyClass() {
textOperand.setBounds(200,100,75,25);
//textOperand action Listener
textOperand.addActionListener( new ActionListener () {
public void actionPerformed(ActionEvent e) {
someOtherMethod(textOperand.getText());
}
});
}
public someOtherMethod(String value) {
System.out.println(value);
}
}
Or, you create a (named) class that is an ActionListener and that can store the value in a retrievable form.
class MyClass {
final JTextField textOperand = new JTextField();
public String textOperandValue;
private class MyActionListener implements ActionListener {
String value;
public void actionPerformed(ActionEvent e) {
value =textOperand.getText();
}
}
MyActionListener l = new MyActionListener();
public MyClass() {
textOperand.setBounds(200,100,75,25);
//textOperand action Listener
textOperand.addActionListener(l);
}
public someOtherMethod() {
if (l.value != null)
//is set
}
}
Or, you just do what you need to do in the action method:
class MyClass {
final JTextField textOperand = new JTextField();
public MyClass() {
textOperand.setBounds(200,100,75,25);
//textOperand action Listener
textOperand.addActionListener( new ActionListener () {
public void actionPerformed(ActionEvent e) {
System.out.println(textOperand.getText());
}
});
}
}

it can work if textOperandValue is global(if it defined in class globally) variable.
not inside ActionListener, not inside method where you wrote this code.

Related

Change value of public variable in Java, used by multiple frames

I have two frames in NetBeans 9.0 as frame1.java, frame2.javaand the main class as main.java.
If I declare a public variable in frame1.java as
public String stringName;
and a function fn() which gives the value of stringName in frame1as say "abcd".
When I write this in frame2,
frame1 fm = new frame1();
String str = frame1.stringName;
System.out.print(str);
I get the output as null. But what I require is "abcd".
What am I doing wrong, and what should it be?
Thanks for help!
Edit:
I have linked frame1 and frame2 such that the GUI from frame1 leads to frame2, and so does the value.
Edit 2
The process goes like this:
GUI of frame1 is visible >> based on user's input, function fn() stores the value, say "abcd" in stringName >> a button click in frame1 leads to frame2>> variable str gets the value from stringName >> System.out.print(str) outputs the value as null .
CODE
frame1:
public class frame1 extends javax.swing.JFrame {
public String stringName;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt){
stringName = jTextField1.getText(); // gets a not null value
}
}}
frame2:
public class frame2 extends javax.swing.JFrame {
frame1 fm = new frame1();
String str = frame1.stringName;
System.out.print(str); //outputs a null value
}
The point ist that you are crating a new Instance (frame1, fm) in your class frame2. So the value from the string in this new Instance is null. You need a reference to your old Instance which you maybe have initialised in your main method?
Something like that:
String str = myOldInstance.stringName;
But you should create getter an setter and make your var private.
But to help you exactly we need more Code.
in this case the best is Listener pattern.
Create interface of listener, which will inform about change text. In class - target of this information - create instance of this listener and return that. In class - source of information - set listener and put on field.
When you want inform of change text, you fire method of listener, and on seconde frame will execute implementation of method.
Below example - I fire on button click.
Any way, field should be private, and add getter and setter. Public fields are bad.
Main class
public class App {
public static void main(String[] args) {
Frame1 f1=new Frame1();
Frame2 f2=new Frame2();
TextListener textListener = f2.getListener();
f1.setListener(textListener);
}
}
Listener
public interface TextListener {
public void onTextPropagate(String text);
}
Frame classes
public class Frame1 extends JFrame{
private TextListener listener;
JButton button;
public Frame1() {
super("Frame1");
setBounds(200, 200, 400, 600);
button=new JButton("Action");
button.setBounds(100, 200, 200, 100);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(listener!=null) {
String text = UUID.randomUUID().toString();
System.out.println("On Frame1:\t"+text);
listener.onTextPropagate(text);
}
}
});
this.add(button);
setVisible(true);
}
public void setListener(TextListener listener) {
this.listener=listener;
}
}
public class Frame2 extends JFrame{
public Frame2() {
super("Frame2");
setBounds(100, 100, 200, 400);
setVisible(true);
}
public TextListener getListener() {
return new TextListener() {
#Override
public void onTextPropagate(String text) {
reactOnChangeText(text);
}
};
}
private void reactOnChangeText(String text) {
System.out.println("On Frame2:\t"+text);
}
}

Rewriting the code so that its readability is improved without changing its behaviour

public class A2 {
public class B implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Fing");
}
}
public class C implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Fang");
}
}
public class D implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Foom");
}
}
public A2(){
JButton a = new JButton("Fing");
JButton b = new JButton("Fang");
JButton c = new JButton("Foom");
a.addActionListener(new B());
b.addActionListener(new C());
c.addActionListener(new D());
}
public static void main(String[] args) {
A2 a2 = new A2();
}
The problem I encountered is quite simple, but complex. I want it to shorten the code without retouching its functionality. For example, the code is showing to many actionlisteners and actionperformed, and I was trying to make it one class pulling out System.out.println(); and putting in String value on it. However, the coding does not work in this simple ways. Please help me out to curtail this code as simple and increase the readability. Thanks.
It's impossible to know what things you could do, I'm personally a fan of self documenting code, so sometimes, you need to be careful when trying to optimise solutions.
My first thought might be to start with the Action's API, which allows you to design a self contained unit of work
public class CommonAction extends AbstractAction {
public CommonAction(String name) {
putValue(NAME, name);
putValue(SHORT_DESCRIPTION, "This is a tool tip for " + name);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(getValue(NAME));
}
}
You could extend it further to provide more customisation if you needed, overriding the actionPerformed method, but, that's up to you.
Then you just need to apply to your buttons...
public class A2 {
public A2() {
JButton a = new JButton(new CommonAction("Fing"));
JButton b = new JButton(new CommonAction("Fang"));
JButton c = new JButton(new CommonAction("Foom"));
}
}
Or your menu's or your key bindings, Action is a rather flexible API supported by a number of other components
You can define single class MyActionListener which implements ActionListener as shown below:
public class MyActionListener implements ActionListener {
private String input;
public MyActionListener(String input) {
this.input = input;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(input);
}
}
public A2(){
String[] inputs = {"Fing","Fang","Foom"};//Array of JButton inputs
for(int i=0;i<inputs.length;i++) {
JButton jButton = new JButton(inputs[i]);//create JButton instance
jButton.addActionListener(new MyActionListener(inputs[i]));
}
}

Java: I can't put my actionlistener outside the constructor

public Server(){
start.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
try{
port = Integer.parseInt(portInput.getText());
}
catch(NumberFormatException e){
text.append("");
}
}
});
}
Having the actionlistener inside the constructor, I can't use the append method becacuse it tells me to add a Server cast to text.append("");
When I do this it tells me I "Cannot cast from JTextArea to Server"
When I move the action listener outside of the constructor it gives me an error and basically forces me to put the action listener inside the constructor. So what I want is to be able to have the action listener outside the constructor so I can call the append method inside the actionlistener.
At this point I'm not sure what to do. I'm sure its something minor, but I just can't figure it out. Any help please?
I'm going to first present working code based for the addActionListener in constructor case, I took the liberty of introducing missing fields.
public class ServerGUI {
private final JButton startServer = new JButton("Start server");
int port;
private JTextField portInput = new JTextField();
private JTextArea eventsLog = new JTextArea();
public ServerGUI(){
startServer.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
try{
port = Integer.parseInt(portInput.getText());
}
catch(NumberFormatException nfe){
appendEventsLog("");
}
}
});
}
private void appendEventsLog(String msg) {
String text = eventsLog.getText();
eventsLog.setText(text + "\n" + msg);
}
}
The problem here was that appendEventsLog is not a member of JTextArea but a member of ServerGUI.
For the second case assigning ActionListener to JButton outside the constructor you have to use static code block or what I prefer initialise method
public class ServerGUI {
private final JButton startServer = new JButton("Start server");
int port;
private JTextField portInput = new JTextField();
private JTextArea eventsLog = new JTextArea();
public ServerGUI(){
initalise();
}
private void initalise() {
startServer.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
try{
port = Integer.parseInt(portInput.getText());
}
catch(NumberFormatException nfe){
appendEventsLog("");
}
}
});
}
private void appendEventsLog(String msg) {
String text = eventsLog.getText();
eventsLog.setText(text + "\n" + msg);
}
}
You are actually not handing over any string at
eventsLog.appendEventsLog("");
I´m not shure if it has to do with your problem or if you just forgot to type it.

Access static variable from another class

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.

A simple question regarding ActionListener and 'enter' key

I am working on an assignment, and I need to enter an SQL Query in a textfield. The user can either press the custom 'execute query' button, or they can press the enter key. When either of these are used, it is to trigger an ActionListener (no other listener is allowed). Is it as simple as writing:
if (e.getSource()=='querybutton' || e.getSource=='enter')
Or is there more to it than this?
As I said, it is a simple question (I know).
edit:
I would write this bit in my ActionPerformed as:
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==gui.executeQueryButton || e.getSource()==gui.enter)
{
String query = gui.queryText.getText();
//more code to follow
}
}
e.getSource() actually returns the object responsible for firing the event (not the name of the variable you used when creating the control). In this case, your button. You could in principle compare e.getSource() with the actual button instances. However, are you actually adding this action listener to buttons other than those two? Presumably you'd only have to add this listener to the two buttons for which you want this behavior -- in which case you wouldn't have to have this if check.
" Is it as simple as writing:
if (e.getSource()=='querybutton' || e.getSource=='enter')"
It's not simple to write this, but rather it is wrong to write it.
For one you don't want to compare Strings with ==, for another, you don't declare Strings with single quotes, and for a third, the enter key is not obtained in this way, but rather by adding the appropriate ActionListener object to the JTextField itself, and finally there should be in a single ActionListener class that handles this action, so the if block is completely unnecessary. This can probably be best done with a small inner private ActionListener class. You'd then create one object of this class and add it as an ActionListener for the querybutton and for the JTextField.
edit 1:
A more complete example of what I mean is shown below, a demo class that has a private inner handler class:
import java.awt.event.*;
import javax.swing.*;
public class ActionListenerEg extends JPanel {
private JButton queryButton = new JButton("Query");
private JTextField textField = new JTextField("hello", 20);
public ActionListenerEg() {
QueryListener qListener = new QueryListener();
queryButton.addActionListener(qListener);
textField.addActionListener(qListener);
add(queryButton);
add(textField);
}
private class QueryListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
String textInField = textField.getText();
System.out.println("Use text in field, \"" + textInField + "\" to call SQL query in a background SwingWorker thread.");
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("ActionListenerEg");
frame.getContentPane().add(new ActionListenerEg());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
The ActionListener is fired either by pressing the button or by pressing enter from within the JTextField. I'd then have in my control class, code that is called inside of the actinoPerformed method.
edit 2: Having most handler or "control" code in its own Handler or Control class can be a good idea, but it doesn't have to implement ActionListener interface itself, but rather just have the code that will be called from within the ActionListener codes. For example, here I try to put all the handler code in its own class. It will have different methods that are called for various situations. e.g.,
import java.awt.Component;
import java.awt.event.*;
import javax.swing.*;
public class ActionListenerEg extends JPanel {
private ActionListenerHandler handler;
private JButton queryButton = new JButton("Query");
private JButton displayButton = new JButton("Display");
private JTextField textField = new JTextField("hello", 20);
// pass in handler or handler
public ActionListenerEg(final ActionListenerHandler handler) {
this.handler = handler;
QueryListener qListener = new QueryListener();
queryButton.addActionListener(qListener);
textField.addActionListener(qListener);
displayButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (handler != null) {
handler.displayActionPerformed(e);
}
}
});
add(queryButton);
add(textField);
add(displayButton);
}
private class QueryListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (handler != null) {
String textInField = textField.getText();
handler.doQueryAction(e, textInField);
}
}
}
private static void createAndShowUI() {
ActionListenerHandler handler = new ActionListenerHandler();
JFrame frame = new JFrame("ActionListenerEg");
frame.getContentPane().add(new ActionListenerEg(handler));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class ActionListenerHandler {
public void displayActionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog((Component) e.getSource(), "Display things!");
}
public void doQueryAction(ActionEvent e, String textInField) {
String text = "We will use \"" + textInField + "\" to help create and run the SQL Query";
JOptionPane.showMessageDialog((Component) e.getSource(), text);
}
}
Please ask questions if it's clear as mudd, or if anything is wrong.

Categories