I have been trying very hard these past days to understand Graphics2d. I do understand the shapes an all, however I can not draw a simple Graph with it.
My Goal is to draw a Coordinate System, that you can change its length if you want to. Like you say the min x Value would be -5 and the max x Value would be 10 and it would scale it self to it and the function too. However I have a really big Problem just creating and scaling the axis correctly. I think this just comes from a high not understanding everything correctly. This is why I would be glad if someone could help me with this matter.
Here is the code I have been working on. It is absolutely not finished. However I would like to get the scaling and all right. But ever other correction is gladly welcomed, due to me being a newbie in java.
I also tried to make it that if like min x would be positive there would be no x axis. Which just does not work.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
public class GraphPlotter extends JFrame {
//f(x) = ax² + bx + c
//Knöpfe
private JButton _ploten = new JButton("Plot");
private JButton _limits = new JButton("Limits");
//Text
private JLabel _funk = new JLabel("f(x) =");
private JLabel _x2 = new JLabel("x² +");
private JLabel _x = new JLabel("x +");
private JLabel _xmin = new JLabel("X min");
private JLabel _ymin = new JLabel("Y min");
private JLabel _ymax = new JLabel("Y max");
private JLabel _xmax = new JLabel("X max");
private String _nummber = "0";
//Textfelder
private JTextField _a = new JTextField(_nummber, 3);
private JTextField _b = new JTextField(_nummber, 3);
private JTextField _c = new JTextField(_nummber, 3);
private JTextField _xMinField = new JTextField("-10");
private JTextField _xMaxField = new JTextField("10");
private JTextField _yMinField = new JTextField("-10");
private JTextField _yMaxField = new JTextField("10");
//Felder
private JPanel _top = new JPanel();
private JPanel _zoom = new JPanel();
private JPanel _graph = new Graph();
public GraphPlotter() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(500, 500);
setTitle("Graph Plotter");
//Alignment
_funk.setAlignmentX(Component.CENTER_ALIGNMENT);
_x2.setAlignmentX(Component.CENTER_ALIGNMENT);
_x.setAlignmentX(Component.CENTER_ALIGNMENT);
_ploten.setAlignmentX(Component.CENTER_ALIGNMENT);
_a.setAlignmentX(Component.CENTER_ALIGNMENT);
_b.setAlignmentX(Component.CENTER_ALIGNMENT);
_c.setAlignmentX(Component.CENTER_ALIGNMENT);
//So if you click on the TextField that it marks it
_a.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_a.setSelectionStart(0);
_a.setSelectionEnd(_a.getText().length());
}
});
_b.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_b.setSelectionStart(0);
_b.setSelectionEnd(_b.getText().length());
}
});
_c.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_c.setSelectionStart(0);
_c.setSelectionEnd(_c.getText().length());
}
});
_xMinField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_xMinField.setSelectionStart(0);
_xMinField.setSelectionEnd(_xMinField.getText().length());
}
});
_xMaxField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_xMaxField.setSelectionStart(0);
_xMaxField.setSelectionEnd(_xMaxField.getText().length());
}
});
_yMinField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_yMinField.setSelectionStart(0);
_yMinField.setSelectionEnd(_yMinField.getText().length());
}
});
_yMaxField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent fe) {
_yMaxField.setSelectionStart(0);
_yMaxField.setSelectionEnd(_yMaxField.getText().length());
}
});
//Aktions for the buttons
_ploten.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//draw a new function
}
});
_limits.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//reskale the Graph
}
});
//Layouts
//Main
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 20;
c.gridwidth = 3;
c.gridx = 0;
c.gridy = 0;
add(_top, c);
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.gridwidth = 2;
c.gridx = 0;
c.gridy = 1;
add(_graph, c);
c.anchor = GridBagConstraints.FIRST_LINE_END;
c.fill = GridBagConstraints.VERTICAL;
c.weightx = 0.0;
c.weighty = 0.5;
c.ipadx = 20;
c.gridwidth = 1;
c.gridx = 2;
c.gridy = 1;
add(_zoom, c);
//Skalling
_zoom.setLayout(new BoxLayout(_zoom, BoxLayout.PAGE_AXIS));
//Borders to better see the layout
_top.setBorder(BorderFactory.createStrokeBorder(new BasicStroke(5.0f)));
_graph.setBorder(BorderFactory.createStrokeBorder(new BasicStroke(5.0f)));
_zoom.setBorder(BorderFactory.createStrokeBorder(new BasicStroke(5.0f)));
_top.add(_funk);
_top.add(_a);
_top.add(_x2);
_top.add(_b);
_top.add(_x);
_top.add(_c);
_top.add(_ploten);
_zoom.add(_xmin);
_zoom.add(_xMinField);
_zoom.add(_xmax);
_zoom.add(_xMaxField);
_zoom.add(_ymin);
_zoom.add(_yMinField);
_zoom.add(_ymax);
_zoom.add(_yMaxField);
_zoom.add(_limits);
setVisible(true);
}
public class Graph extends JPanel {
Color[] _color = {Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.ORANGE, Color.PINK};
int c = 0;
int _width;
int _hight;
int _diffX;
int _diffY;
int _midx;
int _midy;
int xMAX;
int xMIN;
int yMAX;
int yMIN;
public void paintComponent(Graphics g) {
_width = getWidth();
_hight = getHeight();
//Max und Min
xMAX = Integer.parseInt(_xMaxField.getText());
xMIN = Integer.parseInt(_xMinField.getText());
yMAX = Integer.parseInt(_yMaxField.getText());
yMIN = Integer.parseInt(_yMinField.getText());
//Diff
_diffX = xMAX + xMIN;
_diffY = yMAX + yMIN;
if (!(xMIN > 0) && !(xMAX < 0)) {
_midx = (_width / 2) - _diffX;
} else {
_midx = 0;
}
if (!(yMIN > 0) && !(yMAX < 0)) {
_midy = (_hight /2) - _diffY;
} else {
_midy = 0;
}
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
drawAxis(g2D);
}
private void drawAxis(Graphics2D g2d) {
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(2));
//X-Achse
if (!(xMIN > 0) && !(xMAX < 0)) {
g2d.drawLine(0, _midy, _width, _midy);
}
//Y-Achse
if (!(yMIN > 0) && !(yMAX < 0)) {
g2d.drawLine(_midx, 0, _midx, _hight);
}
//Scales drawing
g2d.setStroke(new BasicStroke(1));
for (int n = 0; n < _width; n = n + 5) {
g2d.drawLine(n + _midx, _midy, n + _midx, _midy + 5);
g2d.drawLine(n - _midx, _midy, n - _midx, _midy + 5);
}
for (int n = 0; n < _hight; n = n +5) {
g2d.drawLine(_midx, n + _midy, _midx - 5, n + _midy);
g2d.drawLine(_midx, n - _midy, _midx - 5, n - _midy);
}
}
private void drawGraph(Graphics2D g2d) {
if (!(Integer.parseInt(_a.getText()) == 0) && !(Integer.parseInt(_b.getText()) == 0) && !(Integer.parseInt(_c.getText())== 0)) {
}
}
}
}
Introduction
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay particular attention to the Performing Custom Painting section.
I reworked your GUI. Here's what it looks like now.
I move the X and Y axis around so that the graph fits in the drawing area. The minimum and maximum V values are no less than -10 and 10, respectively. I show the calculated Y minimum and maximum values in the entry panel. The X axis and Y axis are not to the same scale.
Explanation
When I create a Swing GUI, I use the model-view-controller (MVC) pattern. This pattern helps me to separate my concerns and focus on one small part of the application at a time.
The application model for a Swing GUI consists of one or more plain Java getter/setter classes.
The view consists of one and only one JFrame and as many JPanels as I need to create the GUI. You can nest multiple simple JPanels to create a complex layout.
The controller consists of one or more Actions or Listeners. There's usually not one controller to "rule them all". Each Action or Listener is responsible for its part of the model and view.
I didn't write all the code at once. I wrote a little and tested a lot. I probably ran 150 - 200 tests of the GUI before I was satisfied.
Model
I created one plain Java getter/setter class, the GraphPlotterModel class. This class holds the X and Y minimum and maximum values, and a java.util.List of Point2D instances that make up the graph. I also define a starting Dimension in pixels for the drawing JPanel. The dimensions of the drawing JPanel can change. One way is to maximize the GUI.
The model also holds the calculation of the quadratic equation. I go from the X minimum to the X maximum, calculating the corresponding Y value. The X and Y values are in units.
View
I started the GUI with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.
I separated the creation of the JFrame from the creation of the JPanels. This allows me to separate my concerns and focus on one small part of the application at a time. The top JPanel is made up of two individual JPanels, one for the title and one for the entry fields. The center JPanel is a standard drawing panel.
Generally, you define Swing components on a JPanel in column, row order. This makes the code easier to read and understand.
The drawing panel has a method to convert units to pixels. This method probably took 1/3 of my total development time. The biggest hurdle is that a standard graph goes up from the Y minimum to the Y maximum and the Y pixels go from top to bottom. I basically use ratios to calculate the pixels.
Controller
There's only one JButton, so there's only one ActionListener. I made it a separate private class because it has a lot of code and I didn't want to have to pass 5 input fields to a separate class. I check to make sure all the inputs are valid double values, but I didn't display any error message.
Code
Here's the complete runnable code. I made all the additional public classes inner classes so I could post the code as one block.
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class GraphPlotter implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new GraphPlotter());
}
private final GraphPlotterModel model;
private final DrawingPanel drawingPanel;
private JTextField aField, bField, cField;
private JTextField xMinField, xMaxField, yMinField, yMaxField;
public GraphPlotter() {
this.model = new GraphPlotterModel();
this.drawingPanel = new DrawingPanel(model);
}
#Override
public void run() {
JFrame frame = new JFrame("Graph Plotter");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createEntryPanel(), BorderLayout.NORTH);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createEntryPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
Font font = panel.getFont().deriveFont(16f);
Font titleFont = panel.getFont().deriveFont(Font.BOLD, 24f);
JPanel titlePanel = new JPanel(new FlowLayout());
titlePanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
JLabel label = new JLabel(
"Plot the quadratic equation f(x) = ax² + bx + c");
label.setFont(titleFont);
titlePanel.add(label);
JPanel entryPanel = new JPanel(new FlowLayout());
entryPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
label = new JLabel("f(x) =");
label.setFont(font);
entryPanel.add(label);
aField = new JTextField(5);
aField.setFont(font);
entryPanel.add(aField);
label = new JLabel("x² +");
label.setFont(font);
entryPanel.add(label);
bField = new JTextField(5);
bField.setFont(font);
entryPanel.add(bField);
label = new JLabel("x +");
label.setFont(font);
entryPanel.add(label);
cField = new JTextField(5);
cField.setFont(font);
entryPanel.add(cField);
entryPanel.add(Box.createHorizontalStrut(30));
label = new JLabel("X min:");
label.setFont(font);
entryPanel.add(label);
xMinField = new JTextField(5);
xMinField.setFont(font);
entryPanel.add(xMinField);
label = new JLabel("X max:");
label.setFont(font);
entryPanel.add(label);
xMaxField = new JTextField(5);
xMaxField.setFont(font);
entryPanel.add(xMaxField);
label = new JLabel("Y min:");
label.setFont(font);
entryPanel.add(label);
yMinField = new JTextField(5);
yMinField.setEditable(false);
yMinField.setFont(font);
entryPanel.add(yMinField);
label = new JLabel("Y max:");
label.setFont(font);
entryPanel.add(label);
yMaxField = new JTextField(5);
yMaxField.setEditable(false);
yMaxField.setFont(font);
entryPanel.add(yMaxField);
entryPanel.add(Box.createHorizontalStrut(30));
JButton button = new JButton("Plot");
button.addActionListener(new PlotListener());
button.setFont(font);
entryPanel.add(button);
updateEntryPanel();
panel.add(titlePanel, BorderLayout.NORTH);
panel.add(entryPanel, BorderLayout.SOUTH);
return panel;
}
public void updateEntryPanel() {
String formatter = "%.2f";
aField.setText(String.format(formatter, model.getA()));
bField.setText(String.format(formatter, model.getB()));
cField.setText(String.format(formatter, model.getC()));
xMinField.setText(String.format(formatter, model.getxMin()));
xMaxField.setText(String.format(formatter, model.getxMax()));
yMinField.setText(String.format(formatter, model.getyMin()));
yMaxField.setText(String.format(formatter, model.getyMax()));
}
public void repaint() {
drawingPanel.repaint();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private final int margin;
private final GraphPlotterModel model;
public DrawingPanel(GraphPlotterModel model) {
this.model = model;
this.margin = 20;
this.setPreferredSize(model.getDrawingAreaDimension());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(3f));
int width = getWidth() - margin - margin;
int height = getHeight() - margin - margin;
double xMin = model.getxMin();
double xMax = model.getxMax();
double yMin = model.getyMin();
double yMax = model.getyMax();
// Draw X Axis
Point2D a = new Point2D.Double(xMin, 0.0);
Point2D b = new Point2D.Double(xMax, 0.0);
Point startPoint = toPixels(a, width, height);
Point endPoint = toPixels(b, width, height);
g2d.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
// Draw Y axis
a = new Point2D.Double(0.0, yMin);
b = new Point2D.Double(0.0, yMax);
startPoint = toPixels(a, width, height);
endPoint = toPixels(b, width, height);
g2d.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
// Draw graph
g2d.setColor(Color.BLUE);
Point previousPoint = null;
List<Point2D> points = model.getPoints();
for (Point2D point : points) {
Point drawPoint = toPixels(point, width, height);
// System.out.println(point + " " + drawPoint);
if (previousPoint != null) {
g2d.drawLine(previousPoint.x, previousPoint.y, drawPoint.x,
drawPoint.y);
}
previousPoint = (Point) drawPoint.clone();
}
}
private Point toPixels(Point2D point, int width, int height) {
double xMin = model.getxMin();
double xMax = model.getxMax();
double yMin = model.getyMin();
double yMax = model.getyMax();
// System.out.println(yMin + " " + yMax);
double xDelta = (xMax - xMin) / width;
double yDelta = (yMax - yMin) / height;
double xx = Math.round((point.getX() - xMin) / xDelta);
double yy = Math.round((point.getY() - yMin) / yDelta);
// X in pixels goes from left to right
int x = (int) xx + margin;
// Y in pixels goes from top to bottom
int y = height - (int) yy + margin;
return new Point(x, y);
}
}
private class PlotListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
String aString = aField.getText().trim();
String bString = bField.getText().trim();
String cString = cField.getText().trim();
String xMinString = xMinField.getText().trim();
String xMaxString = xMaxField.getText().trim();
double a = valueOf(aString);
if (a == Double.MIN_VALUE) {
return;
}
double b = valueOf(bString);
if (b == Double.MIN_VALUE) {
return;
}
double c = valueOf(cString);
if (c == Double.MIN_VALUE) {
return;
}
double xMin = valueOf(xMinString);
if (xMin == Double.MIN_VALUE) {
return;
}
double xMax = valueOf(xMaxString);
if (xMax == Double.MIN_VALUE) {
return;
}
model.setA(a);
model.setB(b);
model.setC(c);
model.setxMin(xMin);
model.setxMax(xMax);
model.calculatePlot();
updateEntryPanel();
repaint();
}
private double valueOf(String s) {
try {
return Double.valueOf(s);
} catch (NumberFormatException e) {
return Double.MIN_VALUE;
}
}
}
public class GraphPlotterModel {
/** f(x) = ax² + bx + c */
private double a, b, c, xMin, xMax, yMin, yMax;
private final List<Point2D> points;
private final Dimension drawingAreaDimension;
public GraphPlotterModel() {
this.drawingAreaDimension = new Dimension(500, 500);
this.points = new ArrayList<>();
this.xMin = -10.0;
this.xMax = 10.0;
this.yMin = -10.0;
this.yMax = 10.0;
}
public void calculatePlot() {
// steps should be an even number
int steps = 100;
double xDelta = (xMax - xMin) / steps;
double x = xMin;
double yMin = Double.MAX_VALUE;
double yMax = Double.MIN_VALUE;
points.clear();
for (int index = 0; index <= steps; index++) {
double y = a * x * x + b * x + c;
Point2D point = new Point2D.Double(x, y);
points.add(point);
x += xDelta;
yMax = Math.max(yMax, y);
yMin = Math.min(yMin, y);
}
// Make sure that Y goes from -10 to 10 at a minimum
this.yMax = Math.max(yMax, 10.0);
this.yMin = Math.min(yMin, -10.0);
}
public Dimension getDrawingAreaDimension() {
return drawingAreaDimension;
}
public double getA() {
return a;
}
public void setA(double a) {
this.a = a;
}
public double getB() {
return b;
}
public void setB(double b) {
this.b = b;
}
public double getC() {
return c;
}
public void setC(double c) {
this.c = c;
}
public double getxMin() {
return xMin;
}
public void setxMin(double xMin) {
this.xMin = xMin;
}
public double getxMax() {
return xMax;
}
public void setxMax(double xMax) {
this.xMax = xMax;
}
public List<Point2D> getPoints() {
return points;
}
public double getyMin() {
return yMin;
}
public double getyMax() {
return yMax;
}
}
}
Related
So I have this canvas, a BufferedImage, and I have two default calls where I make a line and a circle. My issue here is that I'm trying to call, lets say drawCircle(...) in when a user lets say put 1 into the textfield and sumbit it with enter like this:
if (input.equals("1")){
System.out.println("drawCircle");
DrawCanvas drawCanvas = new DrawCanvas();
drawCanvas.drawCircle(330,310,50);
}
But when I write 1 in the textfield and submit that, I only get the system output "drawCircle", but the circle is not shown?
I thought that my reprint() would update it, but it doesn't, so I'm a bit stuck..
Here is the code I use for making the circle and line and so on:
package DrawCanvas;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
public class DrawCanvas extends JPanel {
final private BufferedImage canvas;
final private Color def_c = Color.BLACK; final private Color def_bg = Color.LIGHT_GRAY;
public DrawCanvas() {
int width = 1280; int height = 720;
canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
fillCanvas(def_bg);
int x0 = 0;
int x1 = 100;
int y0 = 0;
int y1 = 100;
//drawRect(Color.RED, 0, 0, width/2, height/2);
drawLine(def_c, x0, y0, x1, y1);
//drawLineRecInit(Color.yellow, x0, y0+2, x1, y1+2);
drawCircle(300,300,100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(canvas.getWidth(), canvas.getHeight());
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(canvas, null, null);
}
public void fillCanvas(Color c) {
int color = c.getRGB();
for (int x = 0; x < canvas.getWidth(); x++) {
for (int y = 0; y < canvas.getHeight(); y++) {
canvas.setRGB(x, y, color);
}
}
repaint();
}
// Implementation from Wikipedia: https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#All_cases
public void drawLine(Color c, int x0, int y0, int x1, int y1)
{
int dx = Math.abs(x1-x0);
int sx = x0 < x1 ? 1 : -1;
int dy = -Math.abs(y1-y0);
int sy = y0 < y1 ? 1 : -1;
int err = dx + dy; /* error value e_xy */
while (true) /* loop */
{
canvas.setRGB(x0, y0, c.getRGB());
if (x0 == x1 && y0 == y1) break;
int e2 = 2*err;
if (e2 >= dy) /* e_xy+e_x > 0 */
{
err += dy;
x0 += sx;
}
if (e2 <= dx) /* e_xy+e_y < 0 */
{
err += dx;
y0 += sy;
}
}
repaint();
}
public void drawCircle(int x_center, int y_center, int r){
// inspiration : https://www.gatevidyalay.com/mid-point-circle-drawing-algorithm/
Color c = def_c;
int x=r, y=0, p = 1-r;
// checking for radius of circle
if(r==0){
drawPoint(x_center,y_center,c);
}
if(r<0)
return;
// initialising point p
while(x>y){
y++;
if (p < 0) {
p = p + 2 * y + 1;
} else {
x--;
p = p+2*y-2*x+1;
}
//print all octaves
drawPoint(x + x_center,y + y_center,c); // 1. (x,y)
drawPoint(y + x_center,x + y_center,c); // 1. (y,x)
drawPoint(y + x_center,-x + y_center,c); // 4. (y,-x)
drawPoint(x + x_center,-y + y_center,c); // 4. (x,-y)
drawPoint(-x + x_center,-y + y_center,c); // 3. (-x,-y)
drawPoint(-y + x_center,-x + y_center,c); // 3. (-y,-x)
drawPoint(-y + x_center,x + y_center,c); // 2. (-y,x)
drawPoint(-x + x_center,y + y_center,c); // 2. (-x,y)
}
//show
repaint();
}
void drawPoint(int x,int y,Color c){
canvas.setRGB(x,y, c.getRGB());
}
}
My User interface
import DrawCanvas.DrawCanvas;
import TextDemo.TextDemo;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Locale;
public class GUI extends JPanel{
public static void main(String[] args){
//Schedule a job for the event dispatch thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
int width = 1280; int height = 720;
//Create and set up the window.
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(width, height);
frame.setLayout(new BorderLayout(3,3));
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
JPanel panel3 = new JPanel();
panel1.setBackground(Color.red);
panel2.setBackground(Color.green);
panel3.setBackground(Color.yellow);
panel1.setPreferredSize(new Dimension(200, 100));
panel2.setSize(new Dimension(500, 500));
panel3.setPreferredSize(new Dimension(100, 100));
//Add contents to the window.
//frame.add(panel1,BorderLayout.WEST);
frame.add(new TextDemo(),BorderLayout.WEST);
frame.add(new DrawCanvas(),BorderLayout.CENTER);
frame.add(panel3,BorderLayout.SOUTH);
//Display the window.
frame.pack();
frame.setVisible(true);
}
}
This is where the user can ener a text
package TextDemo;
import DrawCanvas.DrawCanvas;
import java.awt.*;
import java.awt.event.*;
import java.util.Locale;
import javax.swing.*;
public class TextDemo extends JPanel implements ActionListener {
protected JTextField textField;
protected JTextArea textArea;
private final static String newline = "\n";
public static Boolean circle = false;
public TextDemo() {
super(new GridBagLayout());
textField = new JTextField(20);
textField.addActionListener(this);
textArea = new JTextArea(5, 20);
textArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(textArea);
//Add Components to this panel.
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.weighty = 1.0;
add(scrollPane, c);
c.weightx = 0;
c.weighty = 0;
c.fill = GridBagConstraints.HORIZONTAL;
add(textField, c);
}
public void actionPerformed(ActionEvent evt) {
String text = textField.getText();
textArea.append(text + newline);
//Make sure the new text is visible, even if there
//was a selection in the text area.
textArea.setCaretPosition(textArea.getDocument().getLength());
System.out.println("String is: " + textField.getText().toLowerCase(Locale.ROOT).replaceAll("\\s+",""));
String input = textField.getText().toLowerCase(Locale.ROOT).replaceAll("\\s+","");
if (input.equals("1")){
System.out.println("Here");
DrawCanvas drawCanvas = new DrawCanvas();
drawCanvas.drawCircle(330,310,50);
}
textField.setText("");
}
}
I'm new to gui java and I've been trying to recreate the game called" jump it" (http://www.crazygames.com/game/jump-it) and I'm currently on the process of making the randomized rectangles for my character to jump on. However I ran my code and I had no errors, but the rectangles that I made isn't showing up. I attached my code underneath, it's kinda long sorry about that.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.Random;
import java.util.TimerTask;
class GuiGame{
public static void main(String args[]) {
JFrame f = new JFrame("RUN - Christine & Esther"); //title of frame
Container cont = f.getContentPane(); // get container - top of the frame
cont.setLayout(new BorderLayout());
BtnActPanel bp = new BtnActPanel(); // create an object of our game panel
cont.add(bp, BorderLayout.CENTER );
f.setVisible(true);
f.setSize(975,613); //size of frame
}
}
class Rectangle{
static Random r = new Random();
static int upperX = 100;
static int lowerX = 20;
static int upperY = 550;
static int lowerY = 450;
static int minWidth = 200;
static int maxWidth = 600;
static int minHeight = 40;
static int maxHeight = 140;
static int x = 0, y = 0, w = 0, h = 0, check = 0;
public Rectangle(){
check++;
int x = 650 + 50*check;
int y = r.nextInt(upperY-lowerY + 1) + lowerY; // from 450 to 550
int w = r.nextInt(maxWidth-minWidth + 1) + minWidth; // from 200 to 600
int h = r.nextInt(maxHeight - minHeight + 1) + minHeight; // from 40 to 140
}
public int getx(){
return x;
}
public int gety(){
return y;
}
public int getw(){
return w;
}
public int geth(){
return h;
}
}
class BtnActPanel extends JPanel implements ActionListener{
//variables
private JButton b1, b2, b3;
private JPanel background;
private JPanel game;
private Timer t, timer;
private int x = 0, check1 = 0, index = 0, x1 = 650, count2 = 0,
y2 = (int)(Math.random()*100)+40, y1 = (int)(Math.random()*100)+450,
x2 = (int)(Math.random()*600)+200, xaxis = 0, yaxis = 0, w = 0, h = 0, count = 0;
private ImageIcon []arrImage;
private boolean check2;
private static ImageIcon icon, exitButton, startButton, questionButton, b, instruct, c ;
public BtnActPanel(){
c = new ImageIcon("character.png"); // constructor
t = new Timer (100,this);
arrImage = new ImageIcon[2];
arrImage[0] = new ImageIcon("character.png");
arrImage[1] = new ImageIcon("character2.png");
startButton = new ImageIcon("startButton.png");//start button image
questionButton = new ImageIcon("QuestionButton.png"); //question button image
exitButton = new ImageIcon("exitButton.png"); //exit button image
icon = new ImageIcon("Title.jpg");//title image
b1 = new JButton(questionButton); // creates first button
//only shows button image with borders
b1.setOpaque(false);
b1.setContentAreaFilled(false);
b1.setBorderPainted(false);
b1.setFocusPainted(false);
b2 = new JButton(startButton);// creates second button
//only shows button image with borders
b2.setOpaque(false);
b2.setContentAreaFilled(false);
b2.setBorderPainted(false);
b2.setFocusPainted(false);
b3 = new JButton(exitButton);// creates third button
//only shows button image with borders
b3.setOpaque(false);
b3.setContentAreaFilled(false);
b3.setBorderPainted(false);
b3.setFocusPainted(false);
//adds buttons to code
this.add(b1);
this.add(b2);
this.add(b3);
b1.addActionListener(this);
b2.addActionListener(this);
b3.addActionListener(this);
}// end of constructor
public void actionPerformed(ActionEvent e) { //checks which button the user presses and performs actions based off choice
if(e.getSource() == b1){
check1 = 2;
this.remove(b1);
this.remove(b3);
repaint();
instruct = new ImageIcon("Instructions.jpg");
}
else if (e.getSource() == b2){
t.start();
check1 = 1;
this.remove(b1);
this.remove(b2);
this.remove(b3);
repaint();
b = new ImageIcon("toskyline.png");
}
else if (e.getSource() == b3){
JOptionPane.showMessageDialog(null, "This is an exit button, hope you enjoyed the game! :)", "Exit message",JOptionPane.WARNING_MESSAGE ); //shows exit message
System.exit(0);//exits program
}
else if (e.getSource() == t){
if (index == 0){
index = 1;
c = arrImage[1];
}
else{
index = 0;
c = arrImage[0];
}
if(count%50 == 0 && count >= 50){
Rectangle obstacle = new Rectangle();
int xaxis = obstacle.getx();
int yaxis = obstacle.gety();
int w = obstacle.getw();
int h = obstacle.geth();
xaxis = xaxis - 10;
count2 = 1;
}
x = x - 10;
x1 = x1 - 10;
repaint();
}
}
public void paintComponent(Graphics g){//this method draws and paints images and icons based on the user decisions
super.paintComponent(g);
if(check1 == 0)[enter image description here][1]
g.drawImage(icon.getImage(),0,0,null);
if(check1 == 1){
g.drawImage(b.getImage(),0,0,null);
g.setColor(Color.black);
g.fillRect(x,495, 500, 35);
g.fillRect(x1, y1, x2, y2);
count++;
System.out.println(count);
if(count2 == 1){
g.fillRect(xaxis, yaxis, w, h);
count2 = 0;
}
g.drawImage(c.getImage(), 100, 460, null);
}
if(check1 == 2)
g.drawImage(instruct.getImage(),0,0,null);
b1.setBounds(320, 350, 100, 100);
b2.setBounds(420, 350, 100, 100);
b3.setBounds(520, 350, 100, 100);
}
}//end of class
Using your ranges I made a demo.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Demo extends JPanel implements ActionListener {
final static int height = 800;
final static int width = 800;
final static String title = "title";
JFrame frame = new JFrame("default title");
Timer timer;
static Random r = new Random();
static int upperX = 100;
static int lowerX = 20;
static int upperY = 550;
static int lowerY = 450;
static int minWidth = 200;
static int maxWidth = 600;
static int minHeight = 40;
static int maxHeight = 140;
List<MyRectangle> rectangles = new ArrayList<>();
public static void main(String[] args) {
SwingUtilities
.invokeLater(() -> new Demo().start());
}
public Demo() {
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.setPreferredSize(
new Dimension(width, height));
setBackground(Color.WHITE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void start() {
timer = new Timer(0, this);
timer.setDelay(1000);
timer.start();
}
public void actionPerformed(ActionEvent ae) {
rectangles.add(createRectangle());
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (MyRectangle r : rectangles) {
g2d.setColor(Color.black);
g2d.drawRect(r.x, r.y, r.width, r.height);
g2d.setColor(r.color);
g2d.fillRect(r.x+1, r.y+1, r.width-1,r.height-1);
}
g2d.dispose();
}
Color[] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.ORANGE, Color.GRAY};
int color = 0;
public MyRectangle createRectangle() {
int y = r.nextInt(upperY - lowerY + 1) + lowerY; // from 450 to 550
int w = r.nextInt(maxWidth - minWidth + 1)
+ minWidth; // from 200 to 600
int h = r.nextInt(maxHeight - minHeight + 1)
+ minHeight; // from 40 to 140
int x = r.nextInt(upperX - lowerX + 1) + lowerX;
Color c = colors[color++ % colors.length];
return new MyRectangle(c, x, y, w, h);
}
class MyRectangle extends Rectangle {
Color color;
MyRectangle(Color c, int x, int y, int w, int h) {
super(x, y, w, h);
this.color = c;
}
}
}
This extends the JDK class Rectangle and adds a color field to the subclass. It displays a new rectangle very second.
I want to make a simple addition program. In it I want to pass variables from Main_Window to Second_Window for addition and I want to get result on Second_Window multiple times. Means If I pass variables multiple times from Main_Window for addition then result should be on Second_Window not third and fourth Window.
Here I want All changes should be show on Second_Window not another on open.
These lines are written for passing variables from Main_Window.
Second_Window s = new Second_Window(a,b);
s.setVisible(true);
I'm going to take my code from my previous answer to one of your questions as my base code and add some functionality to it:
First of all, you need to create one and only one instance of your second window and have a method that can update the angles sent to it.
How do you do that you might be asking yourself, well it's easy, in your action listener you create the instance if the second frame was not created yet and updated it otherwise.
private ActionListener listener = e -> {
if (e.getSource().equals(submitButton)) {
if (!frame.isVisible()) {
circle = new MyCircle((Integer) box1.getSelectedItem(), (Integer) box2.getSelectedItem());
frame.add(circle);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
} else {
circle.updateAngles((Integer) box1.getSelectedItem(), (Integer) box2.getSelectedItem());
}
}
};
Note:
If you close the second window all previous data will be lost, if you want to save that state, then play with the frame visibility and initialize the MyCircle instance in the createAndShowGui() method in the code below.
Next thing is you need to keep track of all the angles you've added, for that you might need a List and iterate over it, or paint that to a BufferedImage and then paint that image on the JPanel. For this example we'll be using the List option.
However, for this example, if the data is too much, it might not display, to correct that, use a JScrollPane as well, however I'm leaving that up to you.
This example as well, makes the whole program to terminate only when you close the main window, but not if you close the second window.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class RadiusDrawer {
private JFrame frame;
private JFrame mainFrame;
private int centerX = 50;
private int centerY = 50;
private int x1 = 0;
private int y1 = 0;
private int x2 = 0;
private int y2 = 0;
private int r = 100;
private JComboBox<Integer> box1;
private JComboBox<Integer> box2;
private JLabel label1;
private JLabel label2;
private JButton submitButton;
MyCircle circle;
private static final Integer[] ANGLES = new Integer[]{15, 30, 45, 60, 75, 90};
public static void main(String[] args) {
SwingUtilities.invokeLater(new RadiusDrawer()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
mainFrame = new JFrame("Main Frame");
mainFrame.add(createMainWindow());
mainFrame.pack();
mainFrame.setVisible(true);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private ActionListener listener = e -> {
if (e.getSource().equals(submitButton)) {
if (!frame.isVisible()) {
circle = new MyCircle((Integer) box1.getSelectedItem(), (Integer) box2.getSelectedItem());
frame.add(circle);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
} else {
circle.updateAngles((Integer) box1.getSelectedItem(), (Integer) box2.getSelectedItem());
}
}
};
private JPanel createMainWindow() {
JPanel pane = new JPanel();
box1 = new JComboBox<>(ANGLES);
box2 = new JComboBox<>(ANGLES);
label1 = new JLabel("Angle 1");
label2 = new JLabel("Angle 2");
submitButton = new JButton("Submit");
submitButton.addActionListener(listener);
pane.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(20, 30, 20, 30);
pane.add(box1, gbc);
gbc.gridx = 1;
pane.add(box2, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
pane.add(label1, gbc);
gbc.gridx = 1;
pane.add(label2, gbc);
gbc.gridy = 2;
pane.add(submitButton, gbc);
return pane;
}
#SuppressWarnings("serial")
class MyCircle extends JPanel {
int cx = 0;
int cy = 0;
double lineX = 0;
double lineY = 0;
double roundedX = 0;
double roundedY = 0;
int angle1 = 0;
int angle2 = 0;
int angle1HistoryX = 15;
int angle2HistoryX = 150;
int angleHistoryY = 300;
int angleHistoryYGap = 20;
Color angle1Color = Color.BLUE;
Color angle2Color = Color.RED;
List <Integer> angle1History;
List <Integer> angle2History;
public MyCircle(int angle1, int angle2) {
this.angle1 = angle1;
this.angle2 = angle2;
angle1History = new ArrayList<>();
angle2History = new ArrayList<>();
angle1History.add(angle1);
angle2History.add(angle2);
calculateCoords();
calculateCenter();
}
private void updateAngles(int angle1, int angle2) {
this.angle1 = angle1;
this.angle2 = angle2;
angle1History.add(angle1);
angle2History.add(angle2);
calculateCoords();
this.revalidate();
this.repaint();
}
private void calculateCoords() {
x1 = (int) (r * Math.cos(Math.toRadians(angle1)));
y1 = (int) (r * Math.sin(Math.toRadians(angle1))) * -1;
x2 = (int) (r * Math.cos(Math.toRadians(angle2)));
y2 = (int) (r * Math.sin(Math.toRadians(angle2))) * -1;
}
private void calculateCenter() {
cx = centerX + r;
cy = centerY + r;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
drawCircle(g2d, centerX, centerY, r);
drawRadius(g2d);
drawHistory(g2d);
}
private void drawCircle(Graphics2D g2d, int x, int y, int r) {
g2d.setColor(Color.BLACK);
g2d.draw(new Ellipse2D.Double(x, y, r * 2, r * 2));
}
private void drawRadius(Graphics2D g2d) {
g2d.setColor(angle1Color);
g2d.draw(new Line2D.Double(cx, cy, cx + x1, cy + y1));
g2d.setColor(angle2Color);
g2d.draw(new Line2D.Double(cx, cy, cx + x2, cy + y2));
}
private void drawHistory(Graphics2D g2d) {
g2d.setColor(angle1Color);
g2d.drawString("Angle1", angle1HistoryX, angleHistoryY);
for (int i = 0; i < angle1History.size(); i++) {
g2d.drawString(angle1History.get(i).toString(), angle1HistoryX, angleHistoryY + (angleHistoryYGap * (i + 1)));
}
g2d.setColor(angle2Color);
g2d.drawString("Angle2", angle2HistoryX, angleHistoryY);
for (int i = 0; i < angle2History.size(); i++) {
g2d.drawString(angle2History.get(i).toString(), angle2HistoryX, angleHistoryY + (angleHistoryYGap * (i + 1)));
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 600);
}
}
}
That's it!
So basically you want to keep the second window to maximum one instance (or zero if the button in main window is never clicked), to do this you need to keep a static reference to the second window, if this reference already exists, you don't create a new one, but ask the existing one to display the calculation result.
A possible approach:
For the submit button in main window, you gather the values of the required parameters, and call the static method of the second window class. A static method is a method that belongs to a class, not an object.
btnSubmit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent aE) {
int azimuth = ...;
int elevation = ...;
SecondWindow.showResult(azimuth, elevation);
}
});
In the second window class, it keeps a static instance of this class, it is null initially. When showResult() is called, it checks if the instance isn't yet exists, then create a new second window and assign to the static reference. And it asks the instance to calculate and display the result in UI.
public class SecondWindow extends JFrame {
private static SecondWindow instance = null;
public static void showResult(int azimuth, int elevation) {
if (instance == null) {
instance = new SecondWindow();
}
instance.performShowResult(azimuth, elevation);
}
private void performShowResult(int azimuth, int elevation) {
// Display the result in UI.
}
}
The last thing to consider is whether you want to set the instance to null when it has been closed? If yes, add this code to the second window constructor:
public SecondWindow() {
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent aE) {
instance = null;
}
});
}
So when showResult() is called again, a new second window will be created.
If you think the creation of second window is somewhat "heavy", then you can just keep the second window closed (thus not set the instance to null), but ensure it is shown when showResult() is called. Like this:
public static void showResult(int azimuth, int elevation) {
if (instance == null) {
instance = new SecondWindow();
} else if (instance.isShowing() == false) {
instance.setVisible(true);
}
instance.performShowResult(azimuth, elevation);
}
My program creates randomly colored and sized worms that expand on a JFrame/JPanel. As time progresses the worms are constantly expanding in random directions. When new worm is clicked a new worm is born somewhere on the screen.
Where my issue arises:
I having trouble understanding how I would then kill worms. When I click the kill worm button I want the worm to disappear (OR stop growing) on screen and it to be removed from the arraylist. I have no idea how to even begin doing this. I personally think removing an instance of the arraylist would be the best way, but how would I go about actually removing the worm from the screen.
Below is my code:
Main Class:
package Main;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
ThreadFrame myFrame = new ThreadFrame();
myFrame.setSize(new Dimension(640, 480));
myFrame.setLocationRelativeTo(null);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setTitle("Worms! - Jonathan Perron");
myFrame.setVisible(true);
myFrame.setResizable(false);
}
}
ThreadFrame Class:
package Main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ThreadFrame extends JFrame implements ActionListener {
int index = 0;
JButton btnNewWorm, btnKillWorm;
JPanel myPanel2 = new JPanel();
ArrayList<DrawThread> worms = new ArrayList<DrawThread>();
public JPanel getMyPanel2(){
return this.myPanel2;
}
public ThreadFrame() {
JPanel myPanel = new JPanel();
btnNewWorm = new JButton("New Worm");
btnKillWorm = new JButton("Kill Worm");
myPanel.setBounds(0, 400, 640, 80);
myPanel.setLayout(new FlowLayout());
myPanel2.setSize(new Dimension(640, 400));
myPanel2.setLayout(null);
myPanel2.setBackground(Color.WHITE);
btnNewWorm.setBounds(100, 410, 200, 30);
btnKillWorm.setBounds(340, 410, 200, 30);
add(btnNewWorm);
add(btnKillWorm);
add(myPanel2);
add(myPanel);
btnNewWorm.addActionListener(this);
btnKillWorm.addActionListener(this);
}
public void actionPerformed(ActionEvent AE) {
if(AE.getSource() == btnNewWorm){
DrawThread dw = new DrawThread(myPanel2);
worms.add(dw);
System.out.println("New worm!");
}
if(AE.getSource() == btnKillWorm){
//stop worms from growing or complete disappear from JFrame
System.out.println("Kill worm!");
}
}
}
DrawThread Class:
package Main;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.util.Random;
import javax.swing.JPanel;
public class DrawThread extends Thread implements Runnable{
Random rand = new Random();
JPanel panel2 = new JPanel();
Graphics2D g, graph;
private int sleepTime, wormDiameter, hue, saturation, brightness, randomWidth, randomHeight;
public DrawThread(int sleepTime, int wormDiameter, int hue, int saturation, int brightness, int randomWidth, int randomHeight, JPanel myPanel2) {
this.sleepTime = sleepTime;
this.wormDiameter = wormDiameter;
this.brightness = brightness;
this.hue = hue;
this.saturation = saturation;
this.randomWidth = randomWidth;
this.randomHeight = randomHeight;
g = (Graphics2D) myPanel2.getGraphics();
}
public void setColor(int hue){
this.hue = hue;
}
public int getSleepTime(){
return sleepTime;
}
public void setSleepTime(int sleepTime){
this.sleepTime = sleepTime;
}
public DrawThread(JPanel myPanel2){
//get panel dimensions
int panelWidth = myPanel2.getWidth();
int panelHeight = myPanel2.getHeight();
//worm location
randomWidth = rand.nextInt(panelWidth);
randomHeight = rand.nextInt(panelHeight);
//worm size
wormDiameter = rand.nextInt(7)+3;
//worm color
hue = rand.nextInt(255);
saturation = rand.nextInt(255);
brightness = rand.nextInt(255);
Color color = new Color(hue, saturation, brightness);
//sleep
sleepTime = rand.nextInt(80) + 20;
//Graphics
g = (Graphics2D) myPanel2.getGraphics();
g.setColor(color);
Ellipse2D.Double ellipse2D = new Ellipse2D.Double(randomWidth, randomHeight, wormDiameter, wormDiameter);
g.fill(ellipse2D);
Thread thread1 = new Thread(new DrawThread(sleepTime, wormDiameter, hue, saturation, brightness, randomWidth, randomHeight, myPanel2));
thread1.start();
}
public void run(){
try {
while(true) {
Thread.sleep(sleepTime);
Color color = new Color(hue, saturation, brightness);
g.setColor(color);
int addedHeight = 0, addedWidth = 0;
int random = rand.nextInt(8);
//determining the worms next move location
if(random == 0){ addedWidth = 0; addedHeight = 1; } //North
if(random == 1){ addedWidth = 1; addedHeight = 1; } //North-East
if(random == 2){ addedWidth = 1; addedHeight = 0; } //East
if(random == 3){ addedWidth = 1; addedHeight = -1; } //South-East
if(random == 4){ addedWidth = 0; addedHeight = -1; } //South
if(random == 5){ addedWidth = -1; addedHeight = -1; } //South-West
if(random == 6){ addedWidth = -1; addedHeight = 0; } //West
if(random == 7){ addedWidth = -1; addedHeight = 1; } //North-West
//Prevent worms from getting off the screen
if(randomHeight >= 480){ addedHeight = -1; }
if(randomHeight <= 0){ addedHeight = 1; }
if(randomWidth >= 640){ addedWidth = -1; }
if(randomWidth <= 0){ addedWidth = 1; }
randomWidth += addedWidth;
randomHeight += addedHeight;
Ellipse2D.Double e = new Ellipse2D.Double(randomWidth, randomHeight, wormDiameter, wormDiameter);
g.fill(e);
}
}
catch (InterruptedException e) {
System.out.println("ERROR!");
}
}
public String toString() {
String result = "SleepTime: " + sleepTime + "\nWorm Diameter: " + wormDiameter
+ "\nHue: " + hue + "\nSaturation: " + saturation + "\nBrightness: "
+ brightness + "\nWidth: " + randomWidth + "\nHeight: " + randomHeight;
return result;
}
}
Any help is greatly appreciated! :)
EDIT: This is the assignment that my teacher has given to write this program.
===========================================================================
In this assignment, we’re going to write a program that draws images of “worms” in a window. The
worms will grow with time, moving in random directions. Each worm will be a different color and will
grow at a different rate. A separate Thread object will manage the drawing of each worm. Here’s an
example of what the window will look like after two worms have grown for a while.
Write a class called ThreadFrame that extends JFrame. This class should include a main method that
creates one instance of this class. This should produce a GUI with an appearance similar to what you see
above. Make the window 640 by 480 pixels, and do not allow the user to resize it. Add two JPanels to
the content pane, a white one in the center region on which the threads will be drawn, and a gray one in
the south region to hold the JButtons marked “New Worm” and “Kill Worm”.
Add an action listener to the “New Worm” button, so that when you click on it, it creates a new instance
of a class called DrawThread (to be described shortly), adds it to an ArrayList, and starts it. Add an action
listener to the “Kill Worm” button, so that when you click on it, it removes the first DrawThread from
the ArrayList and interrupts it.
The class DrawThread extends Thread, and does most of the work of the program. This class will draw
on the upper panel of the ThreadFrame, so a reference to this panel must be passed to the constructor
of DrawThread, when this constructor is called from ThreadFrame. The constructor should perform the
following tasks:
Assign the JPanel reference (received as an argument) to an instance variable of this object.
Get the graphics context for the JPanel (use the getGraphics method), cast it to type Graphics2D, and
assign it to an instance variable.
Determine the width and height of this JPanel, and save these values.
Create a Color object, with randomly-chosen values for the three arguments to set the red, green, and
blue intensities, and assign this object to an instance variable.
Randomly choose a sleep time for this thread, between 20 and 100 milliseconds. This will determine
how rapidly the image grows.
Regarding your instructions
Write a class called ThreadFrame that extends JFrame. This class should include a main method that creates one instance of this class. This should produce a GUI with an appearance similar to what you see above. Make the window 640 by 480 pixels, and do not allow the user to resize it. Add two JPanels to the content pane, a white one in the center region on which the threads will be drawn, and a gray one in the south region to hold the JButtons marked “New Worm” and “Kill Worm”.
OK, you've got this.
Add an action listener to the “New Worm” button, so that when you click on it, it creates a new instance of a class called DrawThread (to be described shortly), adds it to an ArrayList, and starts it.
Again, you've done this.
Add an action listener to the “Kill Worm” button, so that when you click on it, it removes the first DrawThread from the ArrayList and interrupts it.
Break it down:
Get the most recent worm from the ArrayList -- you would use two ArrayList methods, size() and get(...) to achieve this. Give it a try.
Then interrupt the thread. Once you get the object from the array list, you will need to call a Thread method on it, and I'm guessing that you'll be able figure out which method, right (read the instructions for this, i.e, "and interrupts it")? ;)
Edit
Note, that his recommendations are not good, and I would not hire your instructor or course director as a Swing programmer if I needed one.
Edit
Just for grins, here is another way to code this sort of thing. Note that it does not satisfy your assignment requirements (which is one reason I don't hesitate to post it), but it shows what I believe are better Swing behaviors:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
public class MyWormMain {
private static void createAndShowGui() {
MyWormDrawPanel drawPanel = new MyWormDrawPanel();
MyWormButtonPanel btnPanel = new MyWormButtonPanel(drawPanel);
JFrame frame = new JFrame("Worms");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawPanel, BorderLayout.CENTER);
frame.getContentPane().add(btnPanel.getMainPanel(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyWormDrawPanel extends JPanel {
private static final int PREF_W = 640;
private static final int PREF_H = 480;
private static final Color BACKGROUND = Color.WHITE;
private static final int TIMER_DELAY = 50;
private List<MyWorm> wormList = new ArrayList<>();
private Timer wormTimer;
private Random random = new Random();
public MyWormDrawPanel() {
setBackground(BACKGROUND);
wormTimer = new Timer(TIMER_DELAY, new WormTimerListener());
wormTimer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (MyWorm worm : wormList) {
worm.draw(g2);
}
}
public void addWorm() {
int r = random.nextInt(128) + 128;
int g = random.nextInt(128) + 128;
int b = random.nextInt(128) + 128;
int rand = random.nextInt(3);
switch (rand) {
case 0:
r /= 3;
break;
case 1:
g /= 3;
break;
case 2:
b /= 3;
default:
break;
}
Color color = new Color(r, g, b);
int x = random.nextInt(PREF_W);
int y = random.nextInt(PREF_H);
Point head = new Point(x, y);
wormList.add(new MyWorm(color, head, PREF_W, PREF_H));
}
public void killWorm() {
if (wormList.size() > 0) {
wormList.remove(wormList.size() - 1);
}
}
private class WormTimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
for (MyWorm worm : wormList) {
worm.grow();
}
repaint();
};
}
}
#SuppressWarnings("serial")
class MyWormButtonPanel {
private static final int GAP = 15;
private JPanel mainPanel = new JPanel();
private MyWormDrawPanel drawPanel;
public MyWormButtonPanel(MyWormDrawPanel drawPanel) {
this.drawPanel = drawPanel;
mainPanel.setLayout(new GridLayout(1, 0, GAP, GAP));
mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.add(new JButton(new AddWormAction("Add Worm", KeyEvent.VK_A)));
mainPanel.add(new JButton(new KillWormAction("Kill Worm", KeyEvent.VK_K)));
}
public JComponent getMainPanel() {
return mainPanel;
}
private class AddWormAction extends AbstractAction {
public AddWormAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
drawPanel.addWorm();
}
}
private class KillWormAction extends AbstractAction {
public KillWormAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
drawPanel.killWorm();
}
}
}
class MyWorm {
private static final int MAX_DIR = 360;
private static final int SEG_WIDTH = 20;
private static final int MAX_RAND_DIR = 60;
private Color color;
private List<Point> body = new ArrayList<>();
private Random random = new Random();
private int direction;
private int maxX;
private int maxY;
public MyWorm(Color color, Point head, int maxX, int maxY) {
this.color = color;
body.add(head);
direction = random.nextInt(MAX_DIR);
this.maxX = maxX;
this.maxY = maxY;
}
public void grow() {
Point lastPt = body.get(body.size() - 1);
int x = lastPt.x
+ (int) (SEG_WIDTH * 3 * Math.cos(Math.toRadians(direction)) / 4.0);
int y = lastPt.y
+ (int) (SEG_WIDTH * 3 * Math.sin(Math.toRadians(direction)) / 4.0);
if (x < 0) {
x = maxX - 1;
}
if (x > maxX) {
x = 0;
}
if (y < 0) {
y = maxY - 1;
}
if (y > maxY) {
y = 0;
}
Point nextPoint = new Point(x, y);
direction += random.nextInt(MAX_RAND_DIR) - MAX_RAND_DIR / 2;
body.add(nextPoint);
}
public void draw(Graphics2D g2) {
Graphics2D g2b = (Graphics2D) g2.create();
g2b.setColor(color);
for (Point p : body) {
int x = p.x - SEG_WIDTH / 2;
int y = p.y - SEG_WIDTH / 2;
int width = SEG_WIDTH;
int height = SEG_WIDTH;
g2b.fillOval(x, y, width, height);
}
g2b.dispose();
}
}
I have displayed an image(ball) inside the JApplet, now I want the image to move in a vertical way (up and down). The problem is I don't know how to do it.
Could someone has an idea about this matter?
You need to set the position of that image to some calculated value (means you caculate the vertical position using time, speed and maybe other restrictions).
How you'd set that position depends on how you draw the image.
Example, based on drawing in the applet's (or a nested component's) paint(Graphics g) method:
//first calculate the y-position
int yPos += timeSinceLastPaint * speed; //increment the position
if( (speed > 0 && yPos > someMaxY) || (speed < 0 && yPos <0 ) ) {
speed *= -1; //if the position has reached the bottom (max y) or the top invert the direction
}
//in your paint(Graphics g) method:
g.drawImage(image, yPos, x, null);
Then you'd have to constantly repaint the applet.
More information on animations in applets can be found here: http://download.oracle.com/javase/tutorial/uiswing/components/applet.html
another example for javax.swing.Timer with moving Ojbects created by paintComponent(Graphics g), and I have lots of Start, not some blurred Mikado :-)
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class AnimationBackground {
private Random random = new Random();
private JFrame frame = new JFrame("Animation Background");
private final MyJPanel panel = new MyJPanel();
private JLabel label = new JLabel("This is a Starry background.", JLabel.CENTER);
private JPanel stopPanel = new JPanel();
private JPanel startPanel = new JPanel();
public AnimationBackground() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
panel.setBackground(Color.BLACK);
for (int i = 0; i < 50; i++) {
Star star = new Star(new Point(random.nextInt(490), random.nextInt(490)));
star.setColor(new Color(100 + random.nextInt(155), 100 + random.nextInt(155), 100 + random.nextInt(155)));
star.setxIncr(-3 + random.nextInt(7));
star.setyIncr(-3 + random.nextInt(7));
panel.add(star);
}
panel.setLayout(new GridLayout(10, 1));
label.setForeground(Color.WHITE);
panel.add(label);
stopPanel.setOpaque(false);
stopPanel.add(new JButton(new AbstractAction("Stop this madness!!") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
panel.stopAnimation();
}
}));
panel.add(stopPanel);
startPanel.setOpaque(false);
startPanel.add(new JButton(new AbstractAction("Start moving...") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
panel.startAnimation();
}
}));
panel.add(startPanel);
frame.add(panel);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
AnimationBackground aBg = new AnimationBackground();
}
});
}
private class Star extends Polygon {
private static final long serialVersionUID = 1L;
private Point location = null;
private Color color = Color.YELLOW;
private int xIncr, yIncr;
static final int WIDTH = 500, HEIGHT = 500;
Star(Point location) {
int x = location.x;
int y = location.y;
this.location = location;
this.addPoint(x, y + 8);
this.addPoint(x + 8, y + 8);
this.addPoint(x + 11, y);
this.addPoint(x + 14, y + 8);
this.addPoint(x + 22, y + 8);
this.addPoint(x + 17, y + 12);
this.addPoint(x + 21, y + 20);
this.addPoint(x + 11, y + 14);
this.addPoint(x + 3, y + 20);
this.addPoint(x + 6, y + 12);
}
public void setColor(Color color) {
this.color = color;
}
public void move() {
if (location.x < 0 || location.x > WIDTH) {
xIncr = -xIncr;
}
if (location.y < 0 || location.y > WIDTH) {
yIncr = -yIncr;
}
translate(xIncr, yIncr);
location.setLocation(location.x + xIncr, location.y + yIncr);
}
public void setxIncr(int xIncr) {
this.xIncr = xIncr;
}
public void setyIncr(int yIncr) {
this.yIncr = yIncr;
}
public Color getColor() {
return color;
}
}
private class MyJPanel extends JPanel {
private static final long serialVersionUID = 1L;
private ArrayList<Star> stars = new ArrayList<Star>();
private Timer timer = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Star star : stars) {
star.move();
}
repaint();
}
});
public void stopAnimation() {
if (timer.isRunning()) {
timer.stop();
}
}
public void startAnimation() {
if (!timer.isRunning()) {
timer.start();
}
}
#Override
public void addNotify() {
super.addNotify();
timer.start();
}
#Override
public void removeNotify() {
super.removeNotify();
timer.stop();
}
MyJPanel() {
this.setPreferredSize(new Dimension(512, 512));
}
public void add(Star star) {
stars.add(star);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Star star : stars) {
g.setColor(star.getColor());
g.fillPolygon(star);
}
}
}
}
How to move the image inside the JApplet ..?
Pretty much exactly the same way you might do it in a JFrame, JComponent or JPanel or...
Or to put that another way, nothing to do with applets and everything to do with Graphics2D. For more details, see the 2D Graphics Trail of the Java Tutorial.
When you've figured how to move an image and paint it to a Graphics2D, implement that logic in a JComponent or JPanel's paintComponent(Graphics) method and drop the component with moving image into a JApplet or JFrame (or a JPanel etc.).
For the animation side of it, use a javax.swing.Timer as seen in this example. This example does not extend any component. Instead, it creates a BufferedImage and adds it to a JLabel that is displayed to the user. When the timer fires, the code grabs the Graphics object of the image, and proceeds from there to draw the bouncing lines.
import java.awt.image.BufferedImage;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.*;
import javax.swing.*;
import java.util.Random;
class LineAnimator {
public static void main(String[] args) {
final int w = 640;
final int h = 480;
final RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
hints.put(
RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY
);
final BufferedImage bi = new BufferedImage(w,h, BufferedImage.TYPE_INT_ARGB);
final JLabel l = new JLabel(new ImageIcon(bi));
final BouncingLine[] lines = new BouncingLine[100];
int factor = 1;
for (int ii=0; ii<lines.length; ii++) {
lines[ii] = new BouncingLine(w*factor,h*factor);
}
final Font font = new Font("Arial", Font.BOLD, 30);
ActionListener al = new ActionListener() {
int count = 0;
long lastTime;
String fps = "";
private final BasicStroke stroke = new BasicStroke(6);
public void actionPerformed(ActionEvent ae) {
count++;
Graphics2D g = bi.createGraphics();
g.setRenderingHints(hints);
g.setColor(new Color(55,12,59));
g.fillRect(0,0,w,h);
g.setStroke(stroke);
for (int ii=0; ii<lines.length; ii++) {
lines[ii].move();
lines[ii].paint(g);
}
if ( System.currentTimeMillis()-lastTime>1000 ) {
lastTime = System.currentTimeMillis();
fps = count + " FPS";
count = 0;
}
g.setColor(Color.YELLOW);
g.setFont(font);
g.drawString(fps,5,h-5);
l.repaint();
g.dispose();
}
};
Timer timer = new Timer(25,al);
timer.start();
JOptionPane.showMessageDialog(null, l);
//System.exit(0);
timer.stop();
}
}
class BouncingLine {
private final Color color;
private static final Random random = new Random();
Line2D line;
int w;
int h;
int x1;
int y1;
int x2;
int y2;
BouncingLine(int w, int h) {
line = new Line2D.Double(random.nextInt(w),random.nextInt(h),random.nextInt(w),random.nextInt(h));
this.w = w;
this.h = h;
this.color = new Color(
random.nextInt(255)
,random.nextInt(255)
,random.nextInt(255)
,64+random.nextInt(128)
);
x1 = (random.nextBoolean() ? 1 : -1);
y1 = (random.nextBoolean() ? 1 : -1);
x2 = -x1;
y2 = -y1;
}
public void move() {
int tx1 = 0;
if (line.getX1()+x1>0 && line.getX1()+x1<w) {
tx1 = (int)line.getX1()+x1;
} else {
x1 = -x1;
tx1 = (int)line.getX1()+x1;
}
int ty1 = 0;
if (line.getY1()+y1>0 && line.getY1()+y1<h) {
ty1 = (int)line.getY1()+y1;
} else {
y1 = -y1;
ty1 = (int)line.getY1()+y1;
}
int tx2 = 0;
if (line.getX2()+x2>0 && line.getX2()+x2<w) {
tx2 = (int)line.getX2()+x2;
} else {
x2 = -x2;
tx2 = (int)line.getX2()+x2;
}
int ty2 = 0;
if (line.getY2()+y2>0 && line.getY2()+y2<h) {
ty2 = (int)line.getY2()+y2;
} else {
y2 = -y2;
ty2 = (int)line.getY2()+y2;
}
line.setLine(tx1,ty1,tx2,ty2);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setColor(color);
//line.set
g2.draw(line);
}
}
Update 1
I want to do it in JApplet(1) using the image(2), is it possible(3)?
The examples by mKorbel and myself feature either an image in a JLabel or custom rendering in a JPanel. In our case, we added the components to a JOptionPane & a JFrame. Either example could be just as easily added to a JApplet, or a JDialog, or as part of another panel, or.. See the Laying Out Components Within a Container lesson & Using Top-Level Containers in the Java Tutorial for more details.
Instead of the stars or lines in our examples, ..paint your image. My example goes so far as to demonstrate how to get the position to bounce around within the bounds of the container.
Sure it is possible, but "Batteries not included". Our intention is to give you some ideas that you can then adapt to your bouncing ball applet. I doubt anyone is going to create an example for you, using balls, in an applet. Though if you post an SSCCE that shows your intent and what you tried, I (and others) would often run with that source. If you want more specific answers, ask a more specific SSCCE. ;)
I want to do it in JApplet.
Why not both? You can have a hybrid application/applet as shown in this animation.