In my online Java class, I need to write a program that counts the number of mouse clicks on a button within a frame. Here is my code:
import java.awt.*;
import java.awt.event.*;
public class option1 extends Frame {
option1() {
setTitle("Final Project Option 1");
setSize(300,300);
show();
}
public static void main(String[] args) {
option1 test = new option1();
int a = 0;
String s1 = "" + a;
Frame objFrame;
Button objButton1;
Label objLabel1;
objFrame = new option1();
objButton1 = new Button("Button");
objLabel1 = new Label();
objLabel1.setBounds(150,220,50,30);
objButton1.setBounds(40,35,50,50);
objLabel1.setText(s1);
objButton1.addMouseListener(new MyMouseListener()); //line 29
objFrame.add(objLabel1);
objFrame.add(objButton1);
}
public class MyMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent me) {
a++; //line 36
}
}
}
When compiling, I get two errors. One error is on line 29, which is "non-static variable this cannot be referenced from a static context", and the other is on line 36, which is "cannot find symbol".
So, what exactly am I doing wrong? I would appreciate responders telling exactly what I need to do to fix the problem, and avoiding using technical terms since I'm rather new to programming.
I see two issues, namely your inner class should be static (to use it without an instance of option1 which should probably be Option1 to fit with Java naming conventions) and you need to define and initialize a. Something like
public static class MyMouseListener extends MouseAdapter {
int a = 0; //<-- add this.
public void mouseClicked(MouseEvent me) {
a++;
}
}
Also, I suggest you consider using the more modern JFrame instead of the older Frame.
Edit
You'll need to save a reference to your MouseListener like
MyMouseListener mml = new MyMouseListener();
objButton1.addMouseListener(mml);
Then you can get it the a like
System.out.println(mml.a);
Finally, your original approach of "" + a would be "0".
Generally, as soon as you possibly can, get out of the main method into a non-static context...
public class option1 extends Frame {
private int a = 0;
private Label objLabel1;
option1() {
setTitle("Final Project Option 1");
setSize(300,300);
Button objButton1;
objButton1 = new Button("Button");
objLabel1 = new Label();
objLabel1.setBounds(150,220,50,30);
objButton1.setBounds(40,35,50,50);
objLabel1.setText(Integer.toString(a));
objButton1.addMouseListener(new MyMouseListener()); //line 29
add(objLabel1);
add(objButton1);
show();
}
public static void main(String[] args) {
option1 test = new option1();
}
public class MyMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent me) {
a++; //line 36
objLabel1.setText(Integer.toString(a));
}
}
}
Generally speaking, AWT is out-of-date (by some 15 years) and you really should be trying to use Swing or JavaFX instead.
Buttons should use ActionListener, as a mouse is not the only way a button might be triggered
You might like to have a read through Code Conventions for the Java TM Programming Language, it will make it easier for people to read your code and for you to read others
I just tried to make your code working. But there is some issues regarding the standard Java coding. But you should consider previous answers concerning the coding style.
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
public class Main {
public static void main(String[] args) {
final Frame mainFrame = new OptionOne();
Button button = new Button("Button");
final Label label = new Label();
label.setBounds(150, 220, 50, 30);
label.setText("0");
button.setBounds(40, 35, 50, 50);
label.addPropertyChangeListener(label.getText(), new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
mainFrame.addNotify();
}
});
button.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
int value = Integer.parseInt(label.getText());
label.setText(String.valueOf(value + 1));
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
mainFrame.add(label);
mainFrame.add(button);
}
}
class OptionOne extends Frame {
OptionOne() {
setTitle("Final Project Option 1");
setSize(300, 300);
show();
}
}
Related
all
What I'm trying to do is to create a bouncing balls java program. Which I did. Each time the user presses start balls will populate the screen. the only problem I'm having is that I don't know how to pause it. Any help would be appreciated. I tried adding something similar to how I did the addball function but don't know how to apply that to pause the ball. I have tried to do the puase function by adding the button pause but don't know how to get it working
BounceFrame:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BounceFrame extends JFrame {
private static final long serialVersionUID = 1L;
private BallComponent ballComponent;
public BounceFrame() {
setTitle("Bounce");
ballComponent = new BallComponent();
add(ballComponent, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
// Adds more balls.
addButton(buttonPanel, "Start", new ActionListener() {
public void actionPerformed(ActionEvent ae) {
addBall();
}
});
addButton(buttonPanel, "Pause", new ActionListener() {
public void actionPerformed(ActionEvent ae) {
}
});
// Closes the panel.
addButton(buttonPanel, "Close", new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.exit(0);
}
});
add(buttonPanel, BorderLayout.SOUTH);
pack();
}
public void addButton(Container c, String title, ActionListener listener) {
JButton b = new JButton(title);
c.add(b);
b.addActionListener(listener);
}
public void addBall() {
Ball b = new Ball(ballComponent.getBounds());
RunnableBall rB = new RunnableBall(b, ballComponent);
Thread t = new Thread(rB);
t.start();
}
}
RunnableBall:
import java.util.logging.Level;
import java.util.logging.Logger;
public class RunnableBall implements Runnable {
private Ball b;
private BallComponent comp;
private static final int DELAY = 3; //Controls speed of the balls.
public RunnableBall(Ball b, BallComponent comp)
{
this.b = b;
this.comp = comp;
}
#Override
public void run() {
comp.add(b);
while (true)
{
b.move(comp.getBounds());
comp.repaint();
try
{
Thread.sleep(DELAY);
}
catch (InterruptedException ex) {
Logger.getLogger(RunnableBall.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
When you add the ball you need to store the RunnableBall object you are creating in some collection variable, such as a variable of type ArrayList<RunnableBall>, for example. Then in your Pause button's ActionListener you can loop through the ArrayList and call a pause method on each of your RunnableBalls.
So you'll need to then define a pause method inside RunnableBall, which sets a boolean variable "isPaused" to true. So then you'll need to create that variable, isPaused, inside the RunnableBall class, and make it change the behaviour of the run method. You should be able to figure that bit out.
One thing you'll need to take care with is the fact that because you're using multiple threads, you'll need the communication between those threads (i.e. the process of setting the isPaused variable to true or false) to be thread-safe. I think you could achieve that by declaring the isPaused variable to be volatile, but there are other ways to do it.
I want to know how to be able to change a JLabel in java Swing to the button I press but I don't know what I'm missing something. Please help.
What it should end up looking like is on the top of the screen it will show the key being pressed and will update the JLabel as you press it. Don't worry about the Imports, I have them all in the actual code. Thanks :)
public class RandomFrame extends JFrame{
Dimension Size = new Dimension(800,800);
ListenForKeys LFK = new ListenForKeys();
JLabel JInput = new JLabel("");
JPanel P1 = new JPanel();
public static void main(String[] args) {
new RandomFrame();
}
public RandomFrame() {
super("RandomFrame");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(Size);
P1.add(JInput);
this.add(P1);
this.setVisible(true);
}
private class ListenForKeys implements KeyListener {
#Override
public void keyPressed(KeyEvent e) {
String Key = String.valueOf(e.getKeyChar());
JInput.setText(Key);
}
#Override
public void keyReleased(KeyEvent e) {}
#Override
public void keyTyped(KeyEvent e) {}
}
}
Austin pointed out that LFK wasn't attached to anything and sure enough, I added it to the JFrame using the line this.addKeyListener(LFK) and sure enough it worked. Thank you :)
I want two textfields (from now A and B) sharing the same content as the user inputs on any of them. I can make one mirror the other (B mirrors A) or the opposite (A mirrors B). But when I keep both DocumentListeners the execution starts to throw Exceptions.
According to the Oracle's Docs I can't use a DocumentListener to mutate the content of a document from within the Listener itself. Which I find weird since I already did it in the first case (B mirrors A) or the opposite case. Anyway the code still "works" but with an Exception thrown every two events triggered.
KeyListeners are not reliable for this particular case and I refuse to use buttons because I like the real-time look DocumentListener gives.
Any suggestions?
Here's my code:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class Mirror {
private JTextField oriText;
private JTextField mirrorText;
private static int debugCounter; //Counts the times an Event is Triggered.
public static void main(String[] args) {
Mirror gui = new Mirror();
gui.build();
}
public void build(){
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
c.gridx = 0;
c.gridy = 0;
JLabel original = new JLabel("Original");
panel.add(original, c);
c.gridy = 1;
oriText = new JTextField(10);
panel.add(oriText,c);
c.gridy = 2;
JLabel mirror = new JLabel("Mirror");
panel.add(mirror, c);
c.gridy = 3;
mirrorText = new JTextField(10);
panel.add(mirrorText, c);
mirrorText.getDocument().addDocumentListener(new MyDocumentListenerII()); // Comment this line to see only the 1st Case (B mirrors A)
oriText.getDocument().addDocumentListener(new MyDocumentListener()); // Comment this line to see only the 2nd Case (A mirrors B)
frame.pack();
frame.setVisible(true);
}
class MyDocumentListener implements DocumentListener{
#Override
public void changedUpdate(DocumentEvent e) {
//Does nothing.
}
#Override
public void insertUpdate(DocumentEvent e) {
mirror();
}
#Override
public void removeUpdate(DocumentEvent e) {
mirror();
}
}
class MyDocumentListenerII implements DocumentListener{
#Override
public void changedUpdate(DocumentEvent e) {
// Does nothing.
}
#Override
public void insertUpdate(DocumentEvent e) {
mirror1();
}
#Override
public void removeUpdate(DocumentEvent e) {
mirror1();
}
}
public void mirror(){
if (!oriText.getText().equals(mirrorText.getText())){ //Without this each Event trigger the other in some sort of Paradoxical cycle.
mirrorText.setText(oriText.getText());
debugCounter++;
System.out.println(debugCounter+" events triggered");
}
}
public void mirror1(){
if (!mirrorText.getText().equals(oriText.getText())){
oriText.setText(mirrorText.getText());
debugCounter++;
System.out.println(debugCounter+" events triggered");
}
}
}
The problem you're having is that since both JTextFields need to be sync, each field's DocumentListener needs to update the other field. However, that update causes the other DocumentListener to attempt to update the first field, causing the thrown IllegalStateException, since something is attempting to modify the field while a DocumentListener for it is executing.
The solution is to block calls to setText(String) when a DocumentListener is being executed for that field. This can be done with boolean variables. Below is the code for one of the DocumentListeners:
textFieldA.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void removeUpdate (DocumentEvent e) {
blockA = true;
if (!blockB) textFieldB.setText(textFieldA.getText());
blockA = false;
}
#Override
public void insertUpdate (DocumentEvent e) {
blockA = true;
if (!blockB) textFieldB.setText(textFieldA.getText());
blockA = false;
}
#Override
public void changedUpdate (DocumentEvent e) {
blockA = true;
if (!blockB) textFieldB.setText(textFieldA.getText());
blockA = false;
}
});
where blockA and blockB are boolean instance fields (or possibly final variables in the method). Now, when a method fires in textFieldA's DocumentListener, a flag is set to indicate not to use textFieldA.setText(String). We, also see how textFieldB.setText(String) is blocked when blockB is set. The DocumentListener for textFieldB looks about the same.
Now, textFieldA won't be set during a call inside its DocumentListener, same for the other field. Such a call would be redundant anyway: the text of each field would be same at that point.
I'm not entirely sure this is the 'correct' way to do it, but all I did was to attach the same Document to each JTextField.
Here's the relevant part from my initializer:
textFieldA = new JTextField();
textFieldA.setBounds(10, 11, 414, 20);
textFieldA.setColumns(10);
textFieldB = new JTextField();
textFieldB.setBounds(10, 42, 414, 20);
textFieldB.setColumns(10);
textFieldB.setDocument(textFieldA.getDocument());
Now the JTextFields both have the same document, so they can't be different.
I have 2 classes, the first class is where I am creating GUI and all of the components needed. Including the buttons. This is being done outside of the main method and in there own respective methods. I want to .addActionListener, but from another class outside of this one. I do not want to use inner classes.
Here is the classes containing Main and the Gui components and the button.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
public class PasswordGeneratorGui {
private JFrame interfaceFrame;
private JPanel interfacePanel;
private JMenuBar interfaceMenuBar;
private JMenu interfaceMenu;
private JMenuItem interfaceMenuItemFile;
private JButton interfaceButtonGenerate;
public static void main(String[] args) {
new PasswordGeneratorGui();
}
public PasswordGeneratorGui() {
createInterfacePanel();
createInterfaceFrame();
createInterfaceMenuBar();
createInterfaceMenu();
createInterfaceMenuItem();
createInterfaceButton();
PasswordGeneratorButtonHandler b = new PasswordGeneratorButtonHandler();
interfaceFrame.add(interfacePanel);
interfaceFrame.setVisible(true);
}
public void createInterfacePanel() {
interfacePanel = new JPanel();
interfacePanel.setLayout(null);
}
public void createInterfaceFrame() {
interfaceFrame = new JFrame();
interfaceFrame.setTitle("Password Generator");
interfaceFrame.setBounds(50, 50, 700, 400);
interfaceFrame.setResizable(false);
interfaceFrame.setJMenuBar(interfaceMenuBar);
}
public void createInterfaceMenuBar() {
interfaceMenuBar = new JMenuBar();
interfaceMenuBar.setBounds(0, 0, 700, 20);
interfaceMenuBar.setVisible(true);
interfacePanel.add(interfaceMenuBar);
}
public void createInterfaceMenu() {
interfaceMenu = new JMenu("File");
interfaceMenuBar.add(interfaceMenu);
}
public void createInterfaceMenuItem() {
interfaceMenuItemFile = new JMenuItem("Exit");
interfaceMenu.add(interfaceMenuItemFile);
}
**public void createInterfaceButton() {
interfaceButtonGenerate = new JButton("Generate");
interfaceButtonGenerate.setBounds(0, 358, 700, 20);
interfaceButtonGenerate.addActionListener();
interfacePanel.add(interfaceButtonGenerate);
}**
}
Here is the class for the ActionListener
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class PasswordGeneratorButtonHandler implements ActionListener {
PasswordGeneratorButtonHandler generate = new PasswordGeneratorButtonHandler();
public PasswordGeneratorButtonHandler() {
}
public void interfaceButtonGenerateHandler(ActionEvent event) {
System.exit(1);
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
I just want to be able to call the AcitonListener method from the second class. I have tried initiating a new instance of the class and calling it however I think I wasn't quite going in the correct direction.
I'm a little confused about what your asking. You said
I just want to be able to call the AcitonListener method from the second class
Taken literally this means that while you're inside of the PasswordGeneratorButtonHandler class, you want to call the actionPerformed() method. If so, just use this.actionPerformed(), where this is a special keyword in java, representing the current instance of your class.
If however you want to add your handler to the button you created in the first class, which seems like what you might want to do, then you just need to call the JButton#addActionListener() method.
public PasswordGeneratorGui() {
createInterfacePanel();
createInterfaceFrame();
createInterfaceMenuBar();
createInterfaceMenu();
createInterfaceMenuItem();
createInterfaceButton();
PasswordGeneratorButtonHandler b = new PasswordGeneratorButtonHandler();
interfaceButtonGenerate.addActionListener(b); // Add handler to button
interfaceFrame.add(interfacePanel);
interfaceFrame.setVisible(true);
}
Also, inside of the PasswordGeneratorButtonHandler class, you instantiate an instance of the class called generate. This is unnecessary.
I want to write a live search using Swing components. I am using a keyListener to keep track of the input. Basically i dont want the keyListener to take action every time a button is pressed but instead wait (for some period of time) for more incoming input. This period of time is refreshed every time a button is pressed and the input gets evaluated when it eventually times out (e.g. no button is being pressed within the period meaning that the input is complete). How do I implement that into my keyListener?
Code snippet of main method:
static JTextField nameTextField = new JTextField();
public static void main(String args[]) throws Exception {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(nameTextField, BorderLayout.NORTH);
nameTextField.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent keyEvent) {
//
}
#Override
public void keyPressed(KeyEvent e) {
//
}
#Override
public void keyReleased(KeyEvent e) {
if(waitForMoreInput(50)) {
doSomething(nameTextField.getText());
}
}
}
}
}
);
frame.setSize(250, 100);
frame.setVisible(true);
}
Thanks in advance
Much better is for you to use a DocumentListener or DocumentFilter, depending on if you want to listen before or after text has been fully registered with the text component.
The DocumentListener will register any time the text has changed, be it via a key press, via a copy and paste, via a deletion of text. The Timer will then wait however long you wish to do whatever action is required on the text. For example:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
public class DocListenerFoo extends JPanel {
private JTextField nameTextField = new JTextField(20);
public DocListenerFoo() {
add(new JLabel("Add Text:"));
add(nameTextField);
int timerDelay = 1000; // one second
nameTextField.getDocument().addDocumentListener(new MyDocListener(timerDelay));
}
private class MyDocListener implements DocumentListener {
private Timer docTimer;
private int timerDelay;
public MyDocListener(int timerDelay) {
this.timerDelay = timerDelay;
}
#Override
public void changedUpdate(DocumentEvent e) {
textChangedAction(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
textChangedAction(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
textChangedAction(e);
}
private void textChangedAction(DocumentEvent e) {
Document doc = e.getDocument();
try {
String text = doc.getText(0, doc.getLength());
if (docTimer != null && docTimer.isRunning()) {
docTimer.stop();
}
docTimer = new Timer(timerDelay, new TimerListener(text));
docTimer.setRepeats(false);
docTimer.start();
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
}
private class TimerListener implements ActionListener {
private String text;
public TimerListener(String text) {
this.text = text;
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO do check on text here
System.out.println("Checking text here: " + text);
}
}
private static void createAndShowGui() {
DocListenerFoo mainPanel = new DocListenerFoo();
JFrame frame = new JFrame("DocListenerFoo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Don't wait inside the key or document event, it just blocks the program from being processed further. Instead save the current time or (re)start a timer in the event and execute your action later somewhere else.
I'm guessing that you're trying to use a KeyListener with a Swing text component such as a JTextField (I have to guess since you don't tell or show us). If so, then the best solution is don't. Using a KeyListener with these components can mess up the functionality of the components. Much better is for you to use a DocumentListener or DocumentFilter, depending on if you want to listen before or after text has been fully registered with the text component.
For a better more complete answer, post a better more complete question, including your minimal code example and details about your problem.