public static void main(String[] args) {
ControlledBall ball2 = new ControlledBall(12,2);
JFrame window = new JFrame("Controlled Ball");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JButton stop = new JButton("Stop");
stop.setSize(4,400);
stop.setVisible(true);
stop.setText("Stop");
stop.addActionListener(new Action());
i get an error on the last line that says 'controlledball.this cannot be referenced from a static context'
when i try the following technique instead of calling the stop() method i just change the values i need to change:
stop.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
x= 0;
y = 0;
}
});
i get the error non-static field 'x' cannot be referenced from a static context...
the question is, from the main method how can i change the values of x and y which are declared in another method?
There are may ways you can solve this problem. A good suggestion is to probably create a custom ActionListener that holds a reference to the Object you want to change. For example, you could have:
class StopListener implements ActionListener {
private ControlledBall ball;
public StopListener(ControlledBall ball) {
this.ball = ball;
}
#Override
public void actionPerformed(ActionEvent e) {
ball.stop(); // sets x and y to zero
}
}
Then you can just instantiate and use that class as an ActionListener:
stop.addActionListener(new MyListener(ball2));
This should help you organize your code and keep it clean and maintainable.
Related
I've got a problem with changing JPanels color from another class.
I'm trying to change it by clicking a button. I am creating an application where user can pick a colour theme what he wants.
First class:
public class First extends JFrame {
public JPanel contentPane = new JPanel();
public JPanel panel = new JPanel();
public First() {
JButton btnNewButton = new JButton("New button");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Second s = new Second();
s.startSecond();
}
});
}
}
Second class:
public class Second extends JFrame {
First f;
private JPanel contentPane;
public static void startSecond() {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Second sframe = new faijaso();
sframe.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Second() {
JButton btnNewButton = new JButton("New button");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
f.panel.setBackground(Color.red);
f.panel.repaint();
f.panel.revalidate();
}
});
}
}
You have several problems with this code, but most importantly is that your First f variable is never initialized leaving it null, and so if you try to call a method off of it, the program will throw a NullPointerException. You certainly don't want to create a new First() and assign that to f since that instance will not be the same as the visualized First that already exists. Instead change the Second's constructor to accept a First argument, and then pass in the current instance when you call the Second's constructor.
public Second(First f) {
this.f = f;
// ....
and in First:
public First() {
JButton btnNewButton = new JButton("New button");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Second s = new Second();
s.startSecond(First.this); // pass in the First instance
}
});
}
Other problems --
get rid of the static code in Second as there's no need for this. Instead set the Second visible within First's ActionListener.
You really don't want to use two JFrames, and this link will tell you why: The Use of Multiple JFrames: Good or Bad Practice?.
Instead have Second be a JDialog.
I am trying to do something similiar as cookie clicker, nevertheless it does not work. I have not managed to create a "counter" that shows the amount of clicks. This is what I got hitherto, any ideas?
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Stocks implements ActionListener {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Stocks().createGui();
}
});
}
public void createGui() {
JFrame frame = new JFrame("Clicker");
frame.setSize(175, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
frame.add(panel);
frame.getContentPane().add(panel, BorderLayout.WEST);
GridBagConstraints c = new GridBagConstraints();
JButton button1 = new JButton("Click this");
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(40, 40, 40, 40);
panel.add(button1, c);
button1.addActionListener(this);
}
You can have a variable int cnt = 0; inside your Stocks class and everytime someone clicks on the button you increase cnt by one in the actionPerformed method.
As you said, your actionPerformed method is empty, meaning you coded your application to do nothing when the button is clicked.
This answer is assuming you only have one component using that class as ActionListener:
In earlier versions of Java, it would be:
#Override
public void actionPerformed(ActionEvent e) {
counter++;
}
Java 8, however, provides us with Lambda expressions, and allows this to be a lot easier (with less code).
button1.addActionListener(event -> counter++);
You don't need to create an implementation of ActionListener, Java 'll take care of this for you. If you write your code like this, it is even easier if you have more components using that class as ActionListener, since you won't be able to mix them up.
If you need them to call shared parts of code, you can still call methods from within the Lambda expression
button1.addActionListener(event -> {callSharedMethod(); counter++;});
In this example, first the shared method will be called. After that, the counter will be augmented, which will/might only be done from clicking this button.
You should first add a counter as a attribute of your class `Stock``
public class Stocks {
private int counter;
Initialize counter variable with 0:
public static void main(String[] args) {
this.counter = 0;
And then add the action listener to increase the variable:
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
counter++;
}
});
I'm surprised nobody proposed resolving this by inheritance. The button you want is a JButton but slightly more specialized (it must count the number of clicks performed on itself).
public final class CountButton extends JButton {
private int counter = 0;
public CountButton(String text) {
super(text);
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
counter++;
}
});
}
public final int getCounter() {
return counter;
}
}
So I am trying to write a program using swing components so whenever the user clicks on a button, a different word shows up in the text box. I keep getting an error saying "non static method buttons() cannot be referenced from a static context" I checked other answers on how to fix it with the same error, but I still don't understand it. it appears here:
color.buttons();
And this is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class color {
private JFrame f;
private JLabel label;
private JPanel controlPanel;
private JButton button1;
private JButton button2;
private JButton button3;
private JTextField textbox;
public color() {
prepareGUI();
}
public static void main(String args[]) {
color c = new color();
color.buttons();
}
private void prepareGUI() {
f = new JFrame("Colors");
f.setSize(400, 400);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent) {
System.exit(0);
}
});
label = new JLabel("", JLabel.CENTER);
label.setBounds(20, 105, 200, 25);
textbox = new JTextField("", JTextField.CENTER);
textbox.setBounds(20, 75, 125, 50);
f.add(label);
f.add(textbox);
f.setVisible(true);
}
private void buttons() {
label.setText("Click a Button to Reveal Text");
textbox.setText("Which Color?");
JButton button1 = new JButton("Blue");
button1.setBounds(10, 305, 120, 75);
JButton button2 = new JButton("Red");
button2.setBounds(140, 305, 120, 75);
JButton button3 = new JButton("Yellow");
button3.setBounds(270, 305, 120, 75);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
textbox.setText("Blue");
}
});
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
textbox.setText("Red");
}
});
button3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
textbox.setText("Yellow");
}
});
controlPanel.add(button1);
controlPanel.add(button2);
controlPanel.add(button3);
f.setVisible(true);
}
}
You should try c.buttons(); instead of color.buttons();
As non static methods can not be directly referenced, you need an object to do that.
Where as if the method is static then you can use color.buttons();.
The static declaration is used when a field is associated with a class, rather than with any particular object. Now, let's consider your code:
public static void main(String args[]) {
color c = new color();
color.buttons();
}
Of course, the main method has to be static in order to initially run your code. By extension, everything within your static main method must also be static or in other words must be able to run without being directly associated with any object. Therefore, you cannot call color.buttons() since the method is not a static method.
You have two solutions:
Make the method static. Of course, it might not actually make sense to make it static in this case but sometimes in other cases it might be appropriate.
Call the method in the new, instantiated color object, c, as such: c.buttons(); OR call buttons() inside the constructor color().
For clarity, the second solution, in your code, would look like the following:
public color() {
prepareGUI();
buttons();
}
OR
public static void main(String args[]) {
color c = new color();
c.buttons();
}
Calling c.buttons() inside of the static main method is possible since the buttons() method is a method associated with the instantiated object, c.
Finally, some best practices and tips:
You should read the Java Naming Conventions and apply it to your code. For example, your class should be capitalized to be Color instead of color. Following naming conventions makes it easier for other people to read your code because naming conventions are a sort of contract that developers agree on.
You should not call Java Swing methods outside of the Event Dispatch Thread (EDT) as most Swing methods are not thread-safe. Calling Swing methods outside the EDT may result in hard-to-find problems later on.
You can't call a non-static method from a static method in java.
In your case, you are trying to call method buttons() which is a non-static method, where as main method (where you are calling buttons method) is a static method.
Change your main method like this.
public static void main (String args[]){
color c = new color();
c.buttons();
}
In this way you are calling the member function of an object.
I have the following constructor which defines a board and checks if any of the three JButtons have been clicked:
Timer timer = new Timer(500, this);
private boolean[][] board;
private boolean isActive = true;
private int height;
private int width;
private int multiplier = 40;
JButton button1;
JButton button2;
JButton button3;
public Board(boolean[][] board) {
this.board = board;
height = board.length;
width = board[0].length;
setBackground(Color.black);
button1 = new JButton("Stop");
add(button1);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
isActive = !isActive;
button1.setText(isActive ? "Stop" : "Start");
}
});
button2 = new JButton("Random");
add(button2);
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
this.board = randomBoard();
}
});
button3 = new JButton("Clear");
add(button3);
button3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
this.board = clearBoard();
}
});
}
But it returns this error:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
board cannot be resolved or is not a field
board cannot be resolved or is not a field
Why is this? How do I access this.board in the constructor?
The problem is caused by you trying to access this.board inside the anonymous inner classes. Since there is no board field defined, that causes an error.
For example this:
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
this.board = randomBoard();
}
});
In order to be able to use the board variable inside your anonymous inner classes you either need to remove this or use something like Board.this.board (if you want to be more explicit).
This should work:
Board.this.board = randomBoard();
The problem is this related to the class ActionListener which did not have a board variable. However with Board.this you specify that you mean the board member of the Board class. This is the syntax you need to use for nested classes to access the variables of the outer class.
The problem is here
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
this.board = randomBoard();
}
});
your button2 is a JButton, and it doesn't have a board field. Don't access it with this.board. Find another way to access board.
The fast and dirty way to do it would be to make board static, but I'm sure that JButton has a way for you to specify a parent(your board class), and access the board field that way.
After a quick look at The documentation for JButton, I've found a getParent method. I'd start with that.
As others and the compiler said, you don't have a field (which is an instance member), but only a local variable board, which goes out of scope as soon as constructor exits.
I just joined, and am glad to be here~ So, this morning (at like 2am, but thats besides the point :P ) I was doing a little bit of Java tests with JFrame and other GUI stuff. This is my first time working with GUIs. I was trying to make a little java app that would act as a dream journaller. However, my progress was frozen when I encountered a problem i could not solve. My code is as follows.
import java.awt.*;
import javax.swing.*;
import java.applet.*;
public class Display extends Canvas
{
static final int WIDTH = 600;
static final int HEIGHT = 400;
public static String defaultEntry = "Dreams...";
public static final String TITLE = "Dream Journal Testing";
Button erase;
public static void main(String[] args)
{
Display d = new Display();
d.create();
}
public void create()
{
JFrame frame = new JFrame();
System.out.println("Running");
Panel cardOne = new Panel();
Panel p1 = new Panel();
Panel p2 = new Panel();
Panel p3 = new Panel();
Panel grid = new Panel();
cardOne.setLayout(new BorderLayout());
p1.setLayout(new GridLayout(2,1,3,6));
TextArea textArea1 = new TextArea(defaultEntry);
/*Font f1 = new Font("Courier", Font.PLAIN, 16);
setFont(f1);*/
Label l1 = new Label("Welcome to the Dream Journal! :)");
Label l2 = new Label("Type your dream below:");
p1.add(l1);
p1.add(l2);
p2.add(textArea1);
p3.setLayout(new FlowLayout(FlowLayout.CENTER));
Button ok = new Button("Save");
erase = new Button("Erase");
p3.add(erase);
p3.add(ok);
cardOne.add("North",p1);
cardOne.add("Center",p2);
cardOne.add("South",p3);
frame.add(cardOne);
//frame.add(cardOne);
//frame.setLocationRelativeTo(null);
frame.pack();
frame.setTitle(TITLE);
frame.setSize(WIDTH, HEIGHT);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
System.out.println(textArea1.getText());
}
/*public boolean handleEvent(Event evt)
{
if(evt.target == erase)
{
System.out.println("it works");
return true;
}
else return super.handleEvent(evt);
}
*/
public boolean action(Event evt, Object arg)
{
if("Erase".equals(arg))
{
System.out.println("hello");
//textArea1.setText("");
}
return true;
}
}
The problem i have is I am not able to figure out how to make it so if the "Erase" AWT button is pushed, the system will print a line (as a test). I have tried
public boolean action(Event evt, Object arg)
And
public boolean handleEvent, but neither worked. Anyone have any suggestions for the Java noob that is me? Thanks!! :)
One way is to add an action listener to the button (e.g. for Save). Another way is to create an Action (e.g. for Erase).
Don't mix Swing with AWT components unless it is necessary. It is not worth even learning how to use AWT components at this point in time, use Swing only for best results and best help.
Here is a version of the app. using all Swing components.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Display
{
static final int WIDTH = 600;
static final int HEIGHT = 400;
public static String defaultEntry = "Dreams...";
public static final String TITLE = "Dream Journal Testing";
JButton erase;
public static void main(String[] args)
{
Display d = new Display();
d.create();
}
public void create()
{
JFrame frame = new JFrame();
System.out.println("Running");
JPanel cardOne = new JPanel();
JPanel p1 = new JPanel();
JPanel p2 = new JPanel();
JPanel p3 = new JPanel();
cardOne.setLayout(new BorderLayout());
p1.setLayout(new GridLayout(2,1,3,6));
JTextArea textArea1 = new JTextArea(defaultEntry);
JLabel l1 = new JLabel("Welcome to the Dream Journal! :)");
JLabel l2 = new JLabel("Type your dream below:");
p1.add(l1);
p1.add(l2);
p2.add(textArea1);
p3.setLayout(new FlowLayout(FlowLayout.CENTER));
JButton ok = new JButton("Save");
ok.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Do " + ae.getActionCommand());
}
});
erase = new JButton(new EraseAction());
p3.add(erase);
p3.add(ok);
// Use the constants
cardOne.add(BorderLayout.PAGE_START,p1);
cardOne.add(BorderLayout.CENTER,p2);
cardOne.add(BorderLayout.PAGE_END,p3);
frame.add(cardOne);
frame.pack();
frame.setTitle(TITLE);
frame.setSize(WIDTH, HEIGHT);
frame.setResizable(false);
frame.setLocationByPlatform(true);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
System.out.println(textArea1.getText());
}
}
class EraseAction extends AbstractAction {
EraseAction() {
super("Erase");
}
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("Do " + arg0.getActionCommand());
}
}
First let me explain you the Funda of Event Handler....
- First of all there are Event Source, when any action take place on the Event Source, an Event Object is thrown to the call back method.
- Call Back method is the method inside the Listener (Interface) which is needed to be implemented by the Class that implements this Listener.
- The statements inside this call back method will dictate whats needed to be done, when the action is done on the Event Source.
Eg:
Assume
Event Source - Button
When Clicked - Event object is thrown at the call back method
Call back method - actionPerformed(ActionEvent e) inside ActionListener.
Now your case :
Now this can be done in 2 ways.....
1. Let you Display class implements the ActionListener, then Register the button with
the ActionListener, and finally implement the abstract method actionPerformed() of ActionListener.
Eg:
public class Display extends Canvas implements ActionListener{
public Display(){
// Your code....
setComponent(); // Initializing the state of Components
}
public void setComponent(){
// Your code.........
Button b = new Button("Click");
b.addActionListener(this); // Registering the button.
// Your code..........
}
public void actionPerformed(ActionEvent event) {
// Do here whatever you want on the Button Click
}
}
2. Use Anonymous class.
- Anonymous class are declared and initialized simultaneously.
- Anonymous class must implement or extend to only one interface or class resp.
Your Display class will NOT implement ActionListener here....
public class Display extends Canvas {
public Display(){
// Your code....
setComponent(); // Initializing the state of Components
}
public void setComponent(){
// Your code.........
Button b = new Button("Click");
// Registering the button and Implementing it
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event) {
// Do here whatever you want on the Button Click
}
});
// Your code..........
}
}
You need to implement ActionListner :
public class Display extends Canvas implements ActionListener
and add yourself to your button as such:
erase.addActionListener(this);
and then implement the required method:
public void actionPerformed(ActionEvent event) {
//do stuff
}
For more info, check out this tutorial on creating ActionListeners.
You'll find that this observable pattern is widely used the in Java GUI.
A couple high level critiques:
You are using many older AWT components (ie Button) when there are similar, but newer (read: more flexible) Swing components available (ie JButton). Take a look at this for a quick explanation on the difference.
The event model that you have implemented was revamped in 1997 to the observable pattern that I suggested above. If you would like to learn more, you can read this.