Hello while I was following a tutorial I have learnt a way to trigger response in the main class from a click of a button in another class.
So what I have done is that I have a ToolBar class with some code as below
private JButton helloButton;
private JButton goodbyeButton;
private StringListener textListener;
public Toolbar() {
setBorder(BorderFactory.createEtchedBorder());
helloButton = new JButton("Hello");
goodbyeButton = new JButton("Goodbye");
helloButton.addActionListener(this);
goodbyeButton.addActionListener(this);
setLayout(new FlowLayout(FlowLayout.LEFT));
add(helloButton);
add(goodbyeButton);
}
public void setStringListener(StringListener listener) {
this.textListener = listener;
}
#Override
public void actionPerformed(ActionEvent e) {
JButton clicked = (JButton) e.getSource();
if (clicked == helloButton) {
if (textListener != null){
textListener.textEmitted("Hello\n");
}
//textPanel.appendText("Hello\n");
} else {
if (textListener != null){
textListener.textEmitted("Goodbye\n");
//textPanel.appendText("Goodbye\n");
}
}
}
Then in StrinListener Interface I have
public interface StringListener {
public void textEmitted (String text);
}
Finally in main I get the two together by
toolbar.setStringListener(new StringListener (){
#Override
public void textEmitted(String text) {
textPanel.appendText(text);
}
});
what I am curious about is that why does clicking a button trigger response in main method "every time" I click?
so the click is being passed onto textemitted method in StringListener interface and that is received by toolbar.setStringListener in main method. But what is invoking it to work over and over whenever I click the button?
shouldn't the code be read only once unless there is while loop or another loop of some sort?
Thanks
my main class
public MainFrame() {
super("Hello World");
setLayout(new BorderLayout());
textPanel = new TextPanel();
btn = new JButton("Click Me!");
toolbar = new Toolbar();
formPanel = new FormPanel();
toolbar.setStringListener(new StringListener (){
#Override
public void textEmitted(String text) {
textPanel.appendText(text);
}
});
formPanel.setFormListener(new FormListener(){
public void formEventOccurred(FormEvent e){
String name = e.getName();
String occupation = e.getOccupation();
textPanel.appendText(name + ": " + occupation + "\n");
}
});
add(toolbar, BorderLayout.NORTH);
add(textPanel, BorderLayout.CENTER);
add(formPanel, BorderLayout.WEST);
setSize(600, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
It is behaving as expected.
Remember that when you set the textListener, the Toolbar class holds on to an instance variable (of the textListener), and therefore it is kept alive as long as your program is running or until the toolbar object is destroyed. Just because it is an anonymous inner class doesn't mean that the object is destroyed after the method textEmitted is ran once.
Related
I have set up some ActionListeners, however only 'Takeoff' works. The other buttons do not work when they are clicked. When they are clicked, nothing happens.
I have tried to create a new ButtonHandler, but that did not work.
ButtonListener l = new ButtonListener();
JButton takeoff = new JButton("Takeoff");
takeoff.addActionListener(new ButtonHandler());
takeoff.addActionListener();
grid[0][2].add(takeoff);
JButton land = new JButton("Land");
land.addActionListener(new ButtonHandler());
grid[1][2].add(land);
JButton forward = new JButton("Forward");
forward.addMouseListener(new MouseHandler(l));
forward.addActionListener();
grid[2][1].add(forward);
JButton left = new JButton("Left");
left.addMouseListener(new MouseHandler());
left.addActionListener(new ButtonHandler());
left.addActionListener();
grid[3][0].add(left);
takeoff.addActionListener(l);
land.addActionListener(l);
forward.addActionListener(l);
backward.addActionListener();
left.addActionListener(l);
right.addActionListener(l);
turnLeft.addActionListener(l);
turnRight.addActionListener(l);
up.addActionListener(l);
down.addActionListener(l);
stop.addActionListener(l);
What I want to do is move the robot drone in the correct direction, rather than just letting it sit still.
I am not sure if this part will help, but I have where my ButtonHandler implements ActionListener.
private class ButtonHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String button = e.getActionCommand();
if (button.equals("Takeoff")) {
RobotModel.takeoff();
}
else if (button.equals("Land")) {
RobotModel.land();
}
else if(button.equals("Left")) {
RobotModel.left();
}
}
}
You could use the actionCommand to invoke a method via reflection, e.g.
private void init() {
JButton left = new JButton("Go left");
// This
left.setActionCommand("left");
left.addActionListener(new MethodCallActionHandler());
// OR that
left.addActionListener(new MethodCallActionHandler("left"));
}
private void left() {
// go left...
}
private class MethodCallActionHandler implements ActionListener {
private String methodName;
private MethodCallActionHandler() {
super();
}
private MethodCallActionHandler(String methodName) {
this.methodName = methodName;
}
public void actionPerformed(ActionEvent e)
{
String button = methodName != null ? methodName : e.getActionCommand();
SurroundingClass.this.getClass().getMethod(button, new Class[] {}).invoke(SurroundingClass.this);
}
}
You could also pass the action command as String to the MethodCallActionHandler.
You can inherit the Action Listener class into your current class and then add the required methods. Then you can do takeoff.add(this)... etc.
Also nowhere are you setting the action command, that is done in the button settings.
When you are setting
String button = e.getActionCommand();
That is not what is being set when you do
JButton button = new JButton("Takeoff"); <-- This is the text associated with the button
button.setActionCommand("Takeoff");
and then it should work.
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);
}
}
This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 7 years ago.
Why this code do not stop when the while loop is empty. If I add an instruction the code work fine. Normally after the the user clicked an button the test variable will be changed so the loop will ends. Is there another way to test that the JDialog was disposed.
public class FenetreAjoutClass extends JDialog {
private JPanel pan = new JPanel();
private JPanel buttPan = new JPanel();
private JTextField schoolLevl = new JTextField();
private JButton valide = new JButton("OK");
private static String infos = null;
private static boolean test = false;
private JButton cancel = new JButton("CANCEL");
FenetreAjoutClass(JFrame parent, Boolean modal) {
valide.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
infos = schoolLevl.getText();
test = true;
dispose();
}
});
cancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
test = true;
dispose();
}
});
this.setLocationRelativeTo(null);
this.setResizable(true);
this.setLayout(new BorderLayout());
pan.setLayout(new GridLayout(1, 1));
pan.add(schoolLevl);
this.add(pan, BorderLayout.NORTH);
buttPan.add(valide);
buttPan.add(cancel);
this.add(buttPan, BorderLayout.SOUTH);
pack();
setVisible(true);
}
public static void main(String[] args) {
System.out.println(get());
}
public static String get() {
new FenetreAjoutClass(null, false);
while (!test) {
//System.out.println(test);
}
return infos;
}
}
The dispose will free up your memory. All data for the dialog are gone. If you want to show the window later again you have to work with visibility. This can be checked with isVisible().
You can replace the dispose() in your code with this.setVisible(false)
public static String get() {
FenetreAjoutClass dialog = new FenetreAjoutClass(null, false);
while (dialog.isVisible()) {
System.out.println("is Visible");
}
System.out.println("is not Visible");
return infos;
}
Mind that the console will still print "is Visible" over a short time after the dialog is closed. But this is because the console can does not print as quick as the while loop restarts.
Everytime I press cancel or save on the UI it always executes both of the buttons. I've tried countless ways to make it listen to the if statements in the actionperformed block, but it seems to ignore it. I need it so that if I click save it only executes onSave() and cancel for onCancel(). Thanks for your time
public class EditTagPanel extends AbstractTagPanel implements ActionListener {
TagPanelEventListener tagPanelEventListener;
JButton save;
JButton cancel;
public EditTagPanel(ID3v1 id3v1Tag) {
super(id3v1Tag);
}
#Override
protected void configureActionFields() {
JPanel editOptionsPanel = new JPanel(new FlowLayout());
save = new JButton("Save");
save.addActionListener(this);
editOptionsPanel.add(save);
cancel = new JButton("Cancel");
cancel.addActionListener(this);
editOptionsPanel.add(cancel);
this.add(editOptionsPanel, BorderLayout.PAGE_END);
}
public void addTagPanelEventListener(TagPanelEventListener tagPanelEvent) {
this.tagPanelEventListener = tagPanelEvent;
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(save));
{
tagPanelEventListener.onSave(getId3v1Tag());
}
if(e.getSource().equals(cancel));
{
tagPanelEventListener.onCancel();
}
}
Just remove:
;
after each if-statment in your actionPerformed() method, like next:
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(save)) {
tagPanelEventListener.onSave(getId3v1Tag());
}
if (e.getSource().equals(cancel)) {
tagPanelEventListener.onCancel();
}
}
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.