Java program not running correctly on MAC - java

I have recently started using a mac to develop on and i am having a strange problem.
Take the Program below:
public class Driver {
public static void main(String [ ] args) {
SolarSystem SSpanel = new SolarSystem(600, 600);
SSpanel.drawSolarObject(0, 0, 30, "YELLOW");
}
}
the SolarSystem class extends JFrame and basically when the new SolarSystem is created it makes a panel of that size.
the drawSolarObjects basically draws a circle of a certain colour and size. finishedDrawing actually makes the object appear on the panel.
The example above does work but I have more complex requirements which involve putting this into a while loop.
this is where it gets weird, if i run the below program with cmd on a windows computer it works fine and prints the yellow circle to the screen. On my mac, adding this while loop causes it to just create the panel but not paint the yellow circle.
public class Driver{
public static void main(String [ ] args) {
boolean oMove = true;
SolarSystem SSpanel = new SolarSystem(600, 600);
while(oMove){
SSpanel.drawSolarObject(0, 0, 30, "YELLOW");
SSpanel.finishedDrawing();
}
}
}
I put a print into my loop to check it was running through it and that showed that it was definitely running through the loop.
Does anyone know what could be causing this?
Ive am adding the functions so you can get a better picture
SolarSystem Constructer:
public SolarSystem(int width, int height)
{
this.width = width;
this.height = height;
this.setTitle("The Solar System");
this.setSize(width, height);
this.setBackground(Color.BLACK);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
drawSolarObject Function:
public void drawSolarObject(double distance, double angle, double diameter, String col)
{
Color colour = this.getColourFromString(col);
double centreOfRotationX = ((double) width) / 2.0;
double centreOfRotationY = ((double) height) / 2.0;
double rads = Math.toRadians(angle);
double x = (int) (centreOfRotationX + distance * Math.sin(rads)) - diameter / 2;
double y = (int) (centreOfRotationY + distance * Math.cos(rads)) - diameter / 2;
synchronized (this)
{
if (things.size() > 1000)
{
System.out.println("\n\n");
System.out.println(" ********************************************************* ");
System.out.println(" ***** Only 1000 Entities Supported per Solar System ***** ");
System.out.println(" ********************************************************* ");
System.out.println("\n\n");
this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
}
else
{
SolarObject t = new SolarObject((int)x, (int)y, (int)diameter, colour);
things.add(t);
}
}
}
finishedDrawing function:
public void finishedDrawing()
{
try
{
this.repaint();
Thread.sleep(30);
}
catch (Exception e) { }
synchronized (this)
{
things.clear();
}
}
This all works fine on a windows PC

Your code risks tying up the Swing event thread preventing it from drawing on your GUI, and effectively freezing your program. Instead use a Swing Timer, not a while loop to achieve your goal.
e.g.,
final SolarSystem SSpanel = new SolarSystem(600, 600);
int timerDelay = 100;
new Timer(timerDelay, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do repeated action in here
}
}).start();
As an aside, I was going to place,
SSpanel.drawSolarObject(0, 0, 30, "YELLOW");
SSpanel.finishedDrawing();
inside my timer code, but it wouldn't make sense because this code isn't "dynamic" and doesn't change anything or do any animation.

Related

Java JFrame not displaying desired graphics

I had glitching in speech marks because I am farily sure it is not a glitch.
I have just recently started to code using JFrames, in fact I started Java at school couple months ago, but recently I have tried to push my understanding using these handy frames.
I made a program which would bounce a ball around the frame, and I wanted to make it so there would be 2 (for now they would not collide) however whenever I try to add another it simply shows one.
Here is the code:
public static void main(String[] args) throws InterruptedException{
JFrame frame = new JFrame("Hello There");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
frame.setLayout(new FlowLayout());
Main ball = new Main();
Main ball2 = new Main();
ball2.SetValues(200, 200, Color.BLUE);
frame.add(ball2);
frame.add(ball);
while (true) {
ball.move();
ball.repaint();
ball2.move();
ball2.repaint();
Thread.sleep(5);
}
}
public void move() {
x = x + xDirection;
y = y + yDirection;
if (x < 0) { //If Ball has gone off the screen on x direction
xDirection = 1; //Start moving to the right
} else if (x > getWidth() - 50) { //If x has gone off the screen to the right
xDirection = -1;//Start moving to the left
}
if (y < 0) { //If Ball has gone off the screen on x direction
yDirection = 1; //Start moving to the right
} else if (y > getHeight() - 50) { //If x has gone off the screen to the right
yDirection = -1;//Start moving to the left
}
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(color);
g.fillOval(x, y, 50, 50);
}
I recently added the line "frame.setLayout(new FlowLayout()" and it appears to show the 2 balls but they are in a glitched state.
Could anyone help me out?
You should not sleep or do any long process on Swing thread, nor should you update the gui from other threads. See Concurrency in Swing
One alternative is to use javax.swing.Timer :
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ball.move();
ball.repaint();
ball2.move();
ball2.repaint();
}
});
timer.start();
Another alternative is to use a separate thread
It is also recommended to read Performing Custom Painting

Processing Null Pointer Exception Multiple Classes [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
I'm working on a pong game with Processing. The game works just fine with a single class, however, I have to add multiple classes. Every time I get a Null Pointer Exception. This is part of the main class which extends PApplet
PApplet app = new PApplet();
void MAINMENU() {
// Start the Menu Song
if (musicStartMenu) {
MENUsong.loop();
musicStartMenu = false;
}
// Stop the Level song if needed
if (!musicStart) {
BGsong.stop();
musicStart = true;
}
// Resetting player scores
ScoreP1 = ScoreP2 = 0;
// Creating the Background for this scene
image(menuBG, 0, 0);
textFont(SC);
// Setting the title
text("PONG", width / 2 - 100, 150);
// Creating the buttons for this scene
Button Play= new Button(width / 2 - 150, height / 2 - 70, 300, 100, "PLAY", width / 2 - 100, height / 2 + 10, 1, 1,MAIN,app);
Button Exit= new Button(width / 2 - 150, height / 2 + 70, 300, 100, "EXIT", width / 2 - 100, height / 2 + 150, 3, 2,MAIN,app);
Play.Create();
Exit.Create();
}
and this is the button class:
import processing.core.PApplet;
public class Button {
int Bx,By, width, height;
String label;
int labelW, labelH, action, style, MAIN;
PApplet app;
public Button(int Bx, int By, int width, int height, String label, int labelW, int labelH, int action, int style, int MAIN, PApplet app) {
this.Bx = Bx;
this.By = By;
this.width = width;
this.height = height;
this.label = label;
this.labelW = labelW;
this.labelH = labelH;
this.action = action;
this.style = style;
this.MAIN = MAIN;
this.app = app;
}
void Create(){
// Check if we hover the mouse over and select a style
if (ButtonBorder(Bx, By, height, width)) {
if (style == 1)
// light green
app.fill(100, 155, 100);
else if (style == 2)
// light red
app.fill(255, 100, 100);
} else app.fill(0, 50); // black transparent
// Nobody likes borders
app.stroke(0, 0);
// Create the button box
app.rect(Bx, By, width, height);
// CHeck if the mouse is pressed and is hovering above the button
if (app.mousePressed && ButtonBorder(Bx, By, height, width)) {
// Select scene on click
MAIN = action;
}
// SET the fill of the label and create the label
app.fill(255);
app.text(label, labelW, labelH);
}
boolean ButtonBorder(int xB, int yB, int ButtonHeight, int ButtonWidth) {
// returns true if the mouse pointer is located inside the button
if (!(app.mouseX >= xB && app.mouseX <= xB + ButtonWidth))
return false;
if (!(app.mouseY >= yB && app.mouseY <= yB + ButtonHeight))
return false;
return true;
}
If anyone has any clue it would be of much help. I want to say that the code is working just fine in a method inside the main class but for some reason that I can't seem to find it doesn't work in another class.
Trace:
java.lang.NullPointerException
at processing.core.PApplet.fill(PApplet.java:14521)
at ButtonB.Create(ButtonB.java:41)
at Pong.MAINMENU(Pong.java:205)
at Pong.draw(Pong.java:161)
at processing.core.PApplet.handleDraw(PApplet.java:2429)
at processing.awt.PSurfaceAWT$12.callDraw(PSurfaceAWT.java:1557)
at processing.core.PSurfaceNone$AnimationThread.run(PSurfaceNone.java:313)
Your code has a few problems, because you aren't using Processing the way it was designed to be used.
First, it doesn't make sense to create an instance of PApplet directly like this:
PApplet app = new PApplet();
Instead, you want to extend the PApplet class to create your own sketch, like this:
import processing.core.PApplet;
public class MySketch extends PApplet{
public void settings(){
size(500, 500);
}
public void draw(){
ellipse(mouseX, mouseY, 50, 50);
}
public void mousePressed(){
background(64);
}
public static void main(String[] args){
String[] processingArgs = {"MySketch"};
MySketch mySketch = new MySketch();
PApplet.runSketch(processingArgs, mySketch);
}
}
Secondly, you have to make sure you don't call Processing's functions (like fill() and rect()) until after the setup() function of your sketch class has been called.
Also, some feedback: please try to use standard naming conventions in your code. Classes and constructors should start with an upper-case letter, and functions and variables should start with a lower-case letter. Following this convention will make your code much easier to read.
Shameless self-promotion: here is a tutorial on using Processing as a Java library.

Sierpinski Triangle: not displaying

nothing is showing up at all..
I have tried moving Random rand = new Random() to outside of the loop, but it still doesnt work at all.
Nor does the frame exit on close.
public class myMain {
public static void main(String args[]) {
Frame frame = new Frame();
}
}
public class Frame extends JFrame {
public Frame(){
super("Fancy Triangle");
setSize(1024, 768);
myPanel panel = new myPanel();
add(panel);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
}
public class myPanel extends JPanel {
int x1 = 512;
int y1 = 109;
int x2 = 146;
int y2 = 654;
int x3 = 876;
int y3 = 654;
int x = 512;
int y = 382;
int dx, dy;
Random rand;
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < 50000; i++) {
g.drawLine(x, y, x, y);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
rand = new Random();
int random = 1 + rand.nextInt(3);
if (random == 1) {
dx = x - x1;
dy = y - y1;
} else if (random == 2) {
dx = x - x2;
dy = y - y2;
} else {
dx = x - x3;
dy = y - y3;
}
x = x - (dx / 2);
y = y - (dy / 2);
}
}
}
This:
Thread.sleep(300);
is not doing what you intend it to do. I think that you're trying to draw with a delay, but that's not what this does. Instead you're calling sleep on the Swing event thread puts the whole application to sleep, since the thread cannot do what it needs to do, including drawing the application and interacting with the user. Even worse, you're doing this within a painting method, a method that is required to be extremely fast since often the perceived responsiveness of a Swing application is determined by painting speed.
Instead use a Swing Timer (Swing Timer tutorial) to change the state of fields of the class, and then call repaint. Have your paintComponent use those changed fields to decide what to draw and where. Since a Sierpinski triangle is composed of dots, consider creating an ArrayList<Point>, getting rid of the for loop inside your painting method, and using the Swing Timer to replace this for loop. Within the Timer's ActionListener, place the semi-random points into the ArrayList and call repaint. Then within paintComponent, iterate through the ArrayList, drawing each point that it contains.
Alternatively, you could draw the points onto a BufferedImage in your Swing Timer and then simply have your paintComponent display the BufferedImage via g.drawImage(...) method call. This would likely be more efficient.

Having Trouble calling a class at different times

First off apologies for not being able to word my question accurately!
The problem I face is I have an array list with 4 classes that do the exact same thing , only that they need to be called at different times (when the first one's coordinate exceeds a certain value) but Im having trouble getting it done , and Cant find it online (probably because I cant word my questions accurately :/) anyway I will post my code below and if anyone could shed some light I would be extremely grateful!
**What im making is a a tunnel effect by connecting the center of the screen with each corner with lines, and now im attempting to simulate moving by starting lines coming from the middle of the screen towards the edge (starting with bottom portion) **
speedLines sline1, sline2, sline3, sline4;
// holds speedLines classes
ArrayList<speedLines> gameObject;
void setup() {
background(0);
size(750, 750);
smooth();
gameObject = new ArrayList<speedLines>();
sline1 = new speedLines(height/2);
sline2 = new speedLines(height/8);
sline3 = new speedLines(height/4);
sline4 = new speedLines((height/2)*3);
gameObject.add(sline1);
gameObject.add(sline2);
gameObject.add(sline3);
gameObject.add(sline4);
}
void draw() {
background(0);
for(int i=0; i< gameObject.size(); i++){
// go through the different classes
// 2 added so far
gameObject.get(i).display();
}
Guidelines();
}
//GLOBAL VARIABLES
int line=0;
int linewidth=0;
void Guidelines() {
stroke(255);
//MAIN GUIDE
line(0, 0, width/2, height/2);//top left guide
line(width, 0, width/2, height/2);//top right guide
line(0, height, width/2, height/2);//bottom left guide
line(width, height, width/2, height/2);//bottom right guide
//SUB GUIDE
stroke(60, 60, 60);
line(width/3, height, width/2, height/2);//sub guide left
line((width/3)*2, height, width/2, height/2);//sub guide right
}
class speedLines {
//Global variables
int Y;
speedLines(int y) {
}
void display() {
stroke(60, 60, 60);
line((width/2)-linewidth, (height/2)+line, (width/2)+linewidth, (height/2)+line);
line++;
linewidth++;
if ((height/2)+line >= height)
{
line=0;
linewidth=0;
}
}
}
If I were you, I would try to narrow this down to a smaller example sketch. I'd also try to clean up your code a bit: is there a reason you have sketch-level sline variables when you put them in the ArrayList anyway?
That being said, I'll try to help. You're passing a parameter into the speedLines class (which should really be called SpeedLine since classes should start with an upper-case letter and each instance only represents one line) constructor, but you're never using that parameter. Try to get it working with just one instance, like this:
Line myLine;
void setup() {
size(100, 500);
myLine = new Line(height/2);
}
void draw() {
background(200);
myLine.move();
myLine.render();
}
class Line {
float lineY;
public Line(float lineY) {
this.lineY = lineY;
}
public void move() {
lineY++;
if (lineY > height) {
lineY = 0;
}
}
public void render() {
line(0, lineY, width, lineY);
}
}
Notice how I'm actually using the lineY variable that I'm passing into my Line constructor. Try to get something like this working in your code. Then it'll be easier to use an ArrayList to draw multiple lines:
ArrayList<Line> myLines = new ArrayList<Line>();
void setup() {
size(100, 500);
for (float lineY = 0; lineY < height; lineY += 100) {
myLines.add(new Line(lineY));
}
}
void draw() {
background(200);
for (Line myLine : myLines) {
myLine.move();
myLine.render();
}
}
class Line {
float lineY;
public Line(float lineY) {
this.lineY = lineY;
}
public void move() {
lineY++;
if (lineY > height) {
lineY = 0;
}
}
public void render() {
line(0, lineY, width, lineY);
}
}
Also note that you're only ever really using a single value in your class (in my example, the lineY variable). So you probably don't really need a class to do this. You could probably do this with just an array of float values that hold the lineY values instead:
float[] lineY = new float[10];
void setup() {
size(100, 500);
for (int i = 0; i < lineY.length; i++) {
lineY[i] = i * 10;
}
}
void draw() {
background(200);
for (int i = 0; i < lineY.length; i++) {
lineY[i]++;
if (lineY[i] > height) {
lineY[i] = 0;
}
line(0, lineY[i], width, lineY[i]);
}
}
Please note that all of these are just examples, and you'll have to take these examples and understand what they're doing, then do similar things in your code. Good luck.

Java Simple Grapher Applet

I'm trying to make a simple function drawer in Java.
I'm using the ScriptEngine API to parse the equation from a string, but it gets very slow while drawing.
Is there another way to do the same thing?
Here is the code:
private String v;
#Override
public void init(){
setSize(600,600);
v = JOptionPane.showInputDialog("Input function:");
}
#Override
public void paint(Graphics g){
drawQuadrants(g);
drawEquation(g);
}
private void drawEquation(Graphics g) {
g.setColor(Color.BLUE);
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
v = v.replace("sin", "Math.sin")
.replace("cos", "Math.cos")
.replace("sen", "Math.sin")
.replace("tan", "Math.tan")
.replace("tg", "Math.tan")
.replace("log", "Math.log")
.replace("Log(x)","(Math.log(x)/Math.LN10)");
for(double x0 = -10;x0<=10;x0+=0.001){
engine.put("x", x0);
try {
double y0 = (Double)engine.eval(v);
drawPoint(g,x0,-y0);
} catch (HeadlessException | ScriptException e) {
e.printStackTrace();
}
}
}
private void drawQuadrants(Graphics g) {
g.setColor(Color.BLACK);
g.drawLine(0, 300, 600, 300);
g.drawLine(300, 0, 300, 600);
g.setFont(new Font("Arial",Font.BOLD,15));
g.drawString("x", 580, 320);
g.drawString("y", 280, 20);
for(int l = 0;l<=600;l+=30){
g.drawLine(l, 297, l, 303);
}
for(int l = 0;l<=600;l+=30){
g.drawLine(297, l, 303, l);
}
}
private void drawPoint(Graphics g, double x0, double y0) {
int newx0 = (int)map((float)x0, (float)-10, (float)10, (float)0.0, (float)600.0);
int newy0 = (int)map((float)y0, (float)-10, (float)10, (float)0.0, (float)600.0);
g.drawOval(newx0, newy0, 1, 1);
}
public static final float map(float value, float start1, float stop1, float start2, float stop2)
{
return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
}
Well you could always try my code,it is simple fast and elegant.It can also plot any graph by using an external parser.
import javax.swing.*;
import java.awt.*;
import java.util.Scanner;
import net.objecthunter.exp4j.*;
class math extends JFrame
{
public static void main(String args[])
{
math m=new math();
m.setVisible(true);
m.setLocationRelativeTo(null);
}
public void paintallies(Graphics G1,double sf)
{int i;
Graphics2D g21=(Graphics2D) G1;
g21.setColor(Color.GREEN);
for(i=0;i<=600;i=(int) (i+sf))
{
g21.drawLine(i,0,i,600);
g21.drawLine(0,i,600,i);
}
}
public void paintaxes(Graphics G1)
{
Graphics2D g21=(Graphics2D) G1;
g21.setColor(Color.BLACK);
g21.drawLine(300,0,300,600);//y axis
g21.drawLine(0,300,600,300); //x axis
}
public void paint(Graphics G)
{
int i;
double j,k;
Scanner s=new Scanner(System.in);
System.out.println("Enter input");
String input=s.nextLine();
System.out.println("Enter scale factor");
double sf=s.nextDouble();
double sff=300/sf;
double kf=sff;
double count=0;
Graphics g2=(Graphics) G;
paintallies(G,sf);
paintaxes(G);
g2.translate(300,300);
do
{
kf=kf-(1/sf);
count++;
}while(kf>=0);
double counts=2*count;
Color c=Color.RED;
g2.setColor(c.darker());
double yarr[]=new double[(int)counts];
double xarr[]=new double[(int)counts];
Expression E=new ExpressionBuilder(input).variables("x").build();
j=-sff; k=-sff;
for(i=0;i<counts;i++)
{
xarr[i]=j;
j=j+(1/sf);
E.setVariable("x",k);
yarr[i]=E.evaluate();
k=k+(1/sf);
xarr[i]=sf*xarr[i];
yarr[i]=-sf*yarr[i];
}
for(i=0;i<counts;i++)
{
if(i==counts-1)
{
break;
}
else
{
g2.drawLine((int)xarr[i],(int)yarr[i],(int)xarr[i+1],(int)yarr[i+1]);
}
}
}
math()
{
super("Grapher");
setSize(600,600);
setResizable(true);
}
}
One low-hanging fruit may be to increase the value in the for-loop step in the drawEquation() method. When choosing this value, take into consideration that you have ~ 2K to 3K pixels max horizontally. Yet, you're iterating over 20K points on the X axis. Try x0+=0.01 first, then adjust as needed. This may cause your program to run in 1/10th the time.
It would be much faster if you
- make ScriptEngineManager mgr object as member variable and create it once (in constructor of your class)
invoke parsing and calcuations from drawEquation only when text in input dialog changes, not in every draw. You could save computed values in two arrays (one array for x, another one for y values).
As general rule (for every graphic engime I do know), onDraw method should be small and fast.
do not perform object cration and initalization in onDraw. That crates A LOT of work for garbage collector.
do not perform extensive computation in onDraw, if those computation may be performed before.
EDIT:
Calculate and draw only points you need to draw. You need to know width of your Graphic objects, compute increment value of the for loop and have only g.width() number of iterations. More iterations is just a waste- you are drawing many points in the same screen location.

Categories

Resources