"Change modifier of 'frame' to 'static'" in Java - java

I'm being told by Eclipse to change the modifier of my string variable to static. I don't understand why. I think I'm declaring everything right but I'm not sure.
Here's my code. The problem is happening on both lines 12 and 13.
import java.awt.*;
import javax.swing.*;
public class MainClass {
Rectangle dot1 = new Rectangle(1,1), dot2 = new Rectangle(1,1);
JFrame frame = new JFrame("Pythagorean Theorem");
public static void main (String[] args){
frame.setVisible(true);
frame.setSize(500, 500);
}
}

frame is an instance variable of MainClass which means you need an instance of MainClass in order to access it. A static variable belongs to the class and does not require an instance. Generally speaking, you should be avoiding storing things statically as they are hard to modify and test.
Rather create an instance of MainClass in your main method and then access your frame inside an instance method.
public class MainClass {
Rectangle dot1 = new Rectangle(1,1), dot2 = new Rectangle(1,1);
JFrame frame = new JFrame("Pythagorean Theorem");
public void buildUI() {
frame.setVisible(true);
frame.setSize(500, 500);
}
public static void main (String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new MainClass().buildUI();
}
});
}
}
EDIT Notice that when working with Swing, when you create/touch UI components, you need to do that on the Event Dispatch Thread (EDT) which is what the invokeLater does.

You are defining frame as an instance variable, but using it as a static variable. There are two solutions to this:
1) You can change the modifier of frame to static
2) Create an instance of your class, like this:
public static void main (String[] args){
MainClass mc = new MainClass();
mc.frame.setVisible(true);
mc.frame.setSize(500, 500);
}

Related

invalid method declaration, return type required, on a GUI

So im trying to make a simple GUI that goes up by one when you click a button in it. I get this error, however, when i try and run the test GUI: Error. Here is the code
import javax.swing.JFrame;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class Main {
public GUI() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setBorder(borderFactory.createEmptyBorder(30, 30, 10, 30));
panel.setLayout(new GridLayout(0, 1));
frame.add(panel, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Clicks");
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new GUI();
}
}
public class Main {
public GUI() {
GUI seems intended as a constructor and the constructor must have the same name as the class. But neither GUI nor Main are good, descriptive names for a class / constructor. The name should be descriptive of that the class actually is. So here is something that might not only be better, but should work for this case.
public class ClicksGUI {
public ClicksGUI() {
Note that if changing the name of the class / constructor, the reference in the main method also needs to change to reflect that.
Add void as return type for your GUI method
public class Main {
public static void GUI() {
.....
}
}
and call it as a method from main() method.
public static void main(String[] args) {
GUI();
}
Java expects a return type for methods . If you don't want to specify return type , use a constructor instead.
If you want GUI to be a function you must specify a return type (I suppose you want void in your case), and call it like a regular function, not to create an object of it:
public class Main {
public static void GUI() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setBorder(borderFactory.createEmptyBorder(30, 30, 10, 30));
panel.setLayout(new GridLayout(0, 1));
frame.add(panel, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Clicks");
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
GUI();
}
}

Can I acces variables and/or methods of the class a JFrame was created in from the panel?

shortened code:
public class Test{
private JFrame frame;
private TestPanel panel;
Object obj;
public static void main(String args[]) {
Test test = new Test();
}
public Test() {
try {
// Setup GUI
frame = new JFrame("Test");
panel = new TestPanel();
frame.add(panel);
}
}
}
Is it possible to directly access obj from panel?
If yes: How?
Thank you in advance for your help. :)
No; Not without passing the reference to object to the panel.

Adding JPanel to JFrame works 50% of the time

Below are two images showing the problem I'm facing. Whenever I run the project there is 50/50 chance that my JPanels load properly, otherwise only 1 JPanel is loaded even though I'm simply looping through array and adding JPanels to the JFrame.
viewComponents.forEach(viewComponent -> this.add(viewComponent));
Working
Not working
DashboardView.java
public class DashboardView extends JFrame{
List<ViewComponent> viewComponents = new ArrayList();
ViewComponentFactory viewComponentFactory = new ViewComponentFactory();
JFrame dashboardInput = new JFrame();
public DashboardView(){
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new FlowLayout());
createGauges(); //Adding 2 JPanels
viewComponents.forEach(viewComponent -> this.add(viewComponent));
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
dashboardInput.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
dashboardInput.setLayout(new FlowLayout());
createInputs(); //Adding JPanels
dashboardInput.pack();
dashboardInput.setLocation(this.getX()+(this.getWidth()/2)-(dashboardInput.getWidth()/2), this.getY()+this.getHeight());
dashboardInput.setVisible(true);
}
private void createGauges(){
viewComponents.add(viewComponentFactory.getViewComponent(ViewComponentFactory.ViewComponentType.RadialCircleGauge,0,800, "Speedometer", "KM/H"));
viewComponents.add(viewComponentFactory.getViewComponent(ViewComponentFactory.ViewComponentType.LinearGauge, -100,100, "Temperature", "Celcius"));
}
Main.java
public class Main {
public static void main(String[] args) {
DashboardView dashboardView = new DashboardView();
dashboardView.setVisible(true);
}
}
The main problem seems to be, that your DashboadView isn't initialized within the EDT - Thread (Event Dispatching Thread). All GUI actions must be done within this thread. Otherwise strange things will happen (e.g. artifacts while updateing UI).
One should initialize its GUI this way, to ensure the start is wihtin the right Thread.
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}

Can the main method invokeLater be created differently than it normally is in a Java main method?

Can the invokeLater be coded so that you can create an instance of Runnable and then #Override the method run() and then send that Runnable variable into the method.
I am wanting to see if you can change how the code is generated and still get the same results because that is how I start figuring out how things really work in a programming language.
Code:
import javax.swing.*;
public class DDHSimpleProgram {
JFrame f = new JFrame("A simple Swing Program");
JLabel l = new JLabel("Swing powers the modern GUI!");
public DDHSimpleProgram() {
f.setLocation(300, 300);
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(l);
f.pack();
f.setVisible(true);
}
public void run() {
new DDHSimpleProgram();
}
public static void main(String[] args) {
Runnable r = null;
SwingUtilities.invokeLater(r);
}
}
This code works:
The code below works with the program implementing the Runnable interface and then creates the GUI in the zero argument constructor. The invokeLater creates a new instance of the object as an anonymous class. The Run method actually does not do anything other than write a message to the console. I still think that this is an interesting part of the object oriented design structure that seems odd to me sometimes still because you can actual have the method to anything you want it to do.
import javax.swing.*;
public class DDHSimpleProgram implements Runnable {
JFrame f = new JFrame("A simple Swing Program");
JLabel l = new JLabel("Swing powers the modern GUI!");
public DDHSimpleProgram() {
f.setLocation(300, 300);
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(l);
f.pack();
f.setVisible(true);
}
#Override
public void run() {
System.out.println("Run Method");
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new DDHSimpleProgram());
}
}
No you cannot do this.
This is because you set the Runnable to null, insert that into SwingUtilities but all SwingUtilities will know about is null. That is because Java objects are passed by value (pointer value), and therefore you can't change what you already set to null in SwingUtilities.
Also that code is likely to throw a NullPointerException.
The first example won't work, r is null. The reason it won't come is because your class does't implement Runnable, so run can never be called by invokeLater
The second example constructs the UI class outside of the EDT but calls run either the EDT via invokeLater
Preferrably, I would construct a Main class that implements Runnable. From its main method, I would construct an instance of Main and pass it as a reference to invokeLater. In the run method, I would go about constructing the UI, but I'm fussy this way
Can the invokeLater be coded so that you can create an instance of
Runnable and then #Override the method run() and then send that
Runnable variable into the method.
The answer to that is, yes. Any instance of an object that implements Runnable can be passed to invokeLater
Updated with example...
Based on the assumption of the main interface looking like...
public class DDHSimpleProgram {
JFrame f = new JFrame("A simple Swing Program");
JLabel l = new JLabel("Swing powers the modern GUI!");
public DDHSimpleProgram() {
f.setLocation(300, 300);
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(l);
f.pack();
f.setVisible(true);
}
}
I might use a Main class something like...
public class Main implements Runnable {
public static void main(String[] args) {
EventQueue.invokeLater(new Main());
}
#Override
public void run() {
DDHSimpleProgram prog = new DDHSimpleProgram();
}
}

Using an ActionListener in one class to start a timer in another class

I have a class (simulation) which creates an instance of another class (GUI). Inside the class GUI there is a button (start) which has an actionlistener attached to it.
I need this actionlistener to start a timer in simulation but I can't figure out how to do it.
Code in Class Simulation:
public class Simulation{
private static JFrame frame;
private static GUI control;
public static Integer xcontrol = 100, ycontrol = 100;
public Timer timer;
public int steps;
public static void main(String[] args) {
Simulation sim = new Simulation ();
}
public Simulation() {
frame = new JFrame("Action Listener Test");
frame.setLayout(new BorderLayout(1,0));
control = new GUI (xcontrol, ycontrol);
frame.getContentPane().add(control , BorderLayout.CENTER);
frame.setResizable(false);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void StartTimer() {
timer.start();
System.out.println("It worked!");
}
Code in Class GUI:
panel1.add(button1a);
button1a.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent event) {
Simulation.StartTimer();
}
} );
The error Eclipse tells me there is, is that for "Simulation.timer.start();" :
Cannot make a static reference to the non-static method StartTimer() from the type Simulation.
However the method StartTimer() cannot be static as this seems to break the timer...
Any help would be very appreciated.
Pass this as an argument to the GUI constructor.
In general it is best to avoid such cyclic references. Both the GUI and Simulator become dependent upon one another. The essence of the solution is to separate out the GUI from the interesting domain-specific behaviour.
(BTW: I would strongly avoid using static variables for anything other than constants. Also avoid non-private instance variables. But point for not extending JFrame!)
There is some hideous boilerplate that you should add to prevent multithreading.
public static void main(final String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
Simulation sim = new Simulation();
}});
}
What I would do is have your GUI class expose the button via a getButton() method, then after creating the GUI object, your Simulation class can add its own ActionListener to the button, e.g. control.getButton().addActionListener(new ActionListener()... etc.

Categories