Java: Graphics Disappear upon clicking JButton - java

For my algorithms class we have to sort an array using mergesort and at each step draw the array as a histogram to graphically see what is going on. I am running into a problem with the paintComponent method updating the array. When I run the program for the first time, it shows the jumbled array (as it should) and then when I click the mergesort button, I am expecting to see the sorted array but instead, I get nothing. Any help would be appreciated, thanks.
Note: I know I'm not using mergesort now, I am just trying to get the graphics working first.
package a2;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class GraphicalSort extends JFrame implements ActionListener {
static int[] data = new int[200];
JPanel panel = new JPanel(); //Panel to hold graphical display of array
JPanel buttonsPanel = new JPanel();
JButton mButton = new JButton("Mergesort");
int xPos = 0;
static int barWidth = 8;
static int barHeight = 1;
public GraphicalSort() {
setLayout(new BorderLayout());
mButton.addActionListener(this);
buttonsPanel.add(mButton);
for (int i = 0; i < data.length; i++) {
data[i] = (int) (500 * Math.random() + 1);
}
setSize(barWidth * data.length, barHeight * 500 + buttonsPanel.getHeight());
panel = new ArrayPanel();
add(buttonsPanel, BorderLayout.NORTH);
add(panel, BorderLayout.CENTER);
repaint();
validate();
}
public static void main(String[] args) {
GraphicalSort gs = new GraphicalSort();
gs.setTitle("Graphical Sort");
gs.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gs.setLocationRelativeTo(null);
gs.setResizable(false);
gs.setVisible(true);
}
#SuppressWarnings("serial")
class ArrayPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
for (int i = 0; i < data.length; i++) {
g.fillRect(xPos, (barHeight * 500) - (barHeight * data[i]), barWidth, barHeight * data[i]);
xPos += barWidth;
}
}
}
#Override
public void actionPerformed(ActionEvent e) {
remove(panel);
if (e.getSource() == mButton) {
Arrays.sort(data);
panel = new ArrayPanel();
}
add(panel, BorderLayout.CENTER);
repaint();
validate();
}
}

You aren't reseting the xPos instance variable which really should not be an instance variable because you only need it in the paintComponent. So get rid of it and move it to the paintComponent() method.
You also don't need to remove and re-add the panel. So here is what I did (note the removal of the statics! Those should be instance variables):
int[] data = new int[200];
JPanel panel;
JPanel buttonsPanel = new JPanel();
JButton mButton = new JButton("Mergesort");
int barWidth = 8;
int barHeight = 1;
class ArrayPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
int xPos = 0;
for (int i = 0; i < data.length; i++) {
System.out.println("Drawing " + i);
g.fillRect(xPos, (barHeight * 500) - (barHeight * data[i]), barWidth, barHeight * data[i]);
xPos += barWidth;
}
}
}
public void actionPerformed(ActionEvent e) {
Arrays.sort(data);
panel.repaint();
}

You need to reset your xPos variable, otherwise the x co-ordinate will appear off-screen:
int xPos = 0;
Aside: creating a new ArrayPanel is unnecessary — just resetting the variables and calling repaint will work by making xPos a class member variable of ArrayPanel.

Related

I cannot pull values from an array in a different class

The printout of the array lifegrid2 just gives all zeros. I tested the lifegrid array in MyPanel and that is populating, but the values are pulling through as zeros. I checked by putting some values in lifegrid2 and they are being wiped, so it is pulling through from MyPanel, but only zeros. There are no errors being reported.
I have made a small test program with a 2d array which does pull values through.
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import java.awt.*;
import java.awt.event.*;
public class SwingPaintDemo3 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame f = new JFrame("Swing Paint Demo");
f.setPreferredSize(new Dimension(1280,800));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.pack();
f.setVisible(true);
JPanel subPanel = new JPanel();
JButton start = new JButton("START");
subPanel.add(start);
start.setPreferredSize(new Dimension(100,50));
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae1) {
System.out.println("START");
int [][][] lifegrid2 = new int [12][12][2];
int temp;
for (int i=0; i<12; i++) {
for (int j=0; j<12; j++) {
**MyPanel obj = new MyPanel();
temp = obj.lifegrid [i][j][0];
lifegrid2 [i][j][0] = temp;**
if (j<11)
{System.out.print(lifegrid2 [j] [i] [0]);}
else
{System.out.println(lifegrid2 [j] [i] [0]);}}}
}
});
f.add(subPanel, BorderLayout.EAST);
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
class MyPanel extends JPanel {
public int [][][] lifegrid = new int [12][12][2];
private int squareX = 1280;
private int squareY = 800;
private int gridX, gridY ;
public MyPanel() {
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
squareX = e.getX();
squareY = e.getY();
if ((squareX>50 & squareX <550) & (squareY>50 & squareY <550) ){
gridX =(squareX-50)/50+1;
gridY =(squareY-50)/50+1;
squareX = (squareX -50)/50 * 50 + 50;
squareY = (squareY -50)/50 * 50 + 50;
System.out.println(gridX + " " + gridY);
lifegrid [gridX] [gridY] [0] = 1;
repaint(squareX,squareY,50,50);}
else {
}
}
});
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("This is my custom Panel!",10,20);
g.setColor(Color.RED);
g.fillRect(squareX,squareY,48,48);
g.setColor(Color.BLACK);
g.drawRect(squareX,squareY,48,48);
}
}
I have made a small test program with a 2d array
int [][][] lifegrid2 = new int [12][12][2];
That is a 3D array.
A 2D array is defined as:
int [][] lifegrid2 = new int [12][12];
The logic to initialize the array belongs in the constructor of your class:
MyPanel()
{
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
lifegrid [i][j] = 0)
}
}
}
Then your paintComponent() method needs to iterate through the 2D grid and only paint the grids that have a value of 1.
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
if (lifegrid[i][j] = 1)
// paint the grid
}
}
}
}
Edit:
As best as I can tell you are trying to create a grid based game. When you click on a cell in the grid the cell turns red. The are two common ways to approach this:
Use components. In this approach you have a parent panel using a GridLayout and you add a child panel to each cell in the grid. You would also add your MouseListener to each child panel. When you click on the child panel you change the background of the panel to red.
Do custom painting. In this approach you have a single JPanel. This class keep a 2D Array for the "state" of each cell in the grid. You add a single MouseListener to the panel. When you click on the panel you determine which cell was clicked and then you update the state of that cell. In the paintComponent() method you iterate through the 2D Array and paint each cell where that state has changed.
Your approach seems to be some kind of hybrid between the two and is not working.

How to get result on second window multiple times instead of another open?

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);
}

Super paint component not showing up (I have tried everything)

Hello guys I am currently having problems with making anything show with my paint component. I have tried numerous things that I have seen online and tried a lot of different things myself but i Just can't get it to show anything. I am trying to get my paint component to show a series of bars that move as an array being sorted using swing but i can't even get it ti show anything. Any help would be appreciated.
package proj2;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
public class project2 extends JFrame
{
private JButton button1 = new JButton("Insertion");
private UpdateTextFieldThread currentThread;
private int[] array = new int[15];
private Display display;
private class ButtonHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Object src = e.getSource();
if (src == button1){
insertionSort(array);
(new UpdateTextFieldThread()).execute();
}
}
}
public project2()
{
setTitle("Sorting Charts");
setSize(400,250);
setDefaultCloseOperation(EXIT_ON_CLOSE);
for(int i=0; i<array.length;i++)
array[i]=(int) (Math.random()*100);
display=new Display();
ButtonHandler bh = new ButtonHandler();
button1.addActionListener(bh);
JPanel container = new JPanel();
container.setLayout(new GridLayout(2, 2));
container.add(button1);
JPanel masterPanel=new JPanel();
masterPanel.setLayout(new BorderLayout());
masterPanel.add(display, BorderLayout.SOUTH);
masterPanel.add(container, BorderLayout.NORTH);
setContentPane(container);
setVisible(true);
display.repaint();
}
private class Display extends JPanel {
private Color color = Color.RED;
//#Override
public void paintComponent(Graphics g) {
super.paintComponents(g);
g.setColor(Color.RED);
Dimension d = getSize();
int clientWidth = d.width;
int clientHeight = d.height;
int barWidth = clientWidth / array.length;
for(int i=0;i<array.length;i++){
int x=0;
int y=15;
int linethickness=5;
int linelength=10;
g.setColor(Color.red);
g.fillRect(x, clientHeight, linelength*array[i] , linethickness);
g.setColor(Color.black);
g.drawRect(x,clientHeight, linelength*array[i], linethickness);
x+=15;
}
}
}
private class UpdateTextFieldThread extends SwingWorker<Void, Integer>
{
protected Void doInBackground()
{
display.repaint();
return null;
//should have repaint method in here somewhere
/*for (int i = 0; i < 50; i++) {
publish(i);
try {
Thread.sleep(THREAD_DELAY);
} catch (InterruptedException e) { }
}
return null;*/
}
// The parameter here is a list of all published data
// since the last call to process. We are interested
// in displaying only the latest one on the GUI.
protected void process(java.util.List<Integer> list)
{
// textfield.setText("" + list.get(list.size() - 1));
}
}
public static <T extends Comparable<T>> void insertionSort(int[] hue2)
{
for (int i = 1; i < hue2.length; i++) {
int thingToInsert = hue2[i];
int j = i - 1;
while (j >= 0 && thingToInsert<hue2[j]) {
hue2[j+1] = hue2[j];
j--;
}
hue2[j+1] = thingToInsert;
}
}
public static void main(String[]args) {
new project2();
}
}
masterPanel.add(display, BorderLayout.SOUTH);
You are adding your Display panel to the SOUTH of a BorderLayout. The SOUTH constraint will respsect the preferred height of the component. Your component has a height of 0, to there is nothing to display.
Whenever you do custom painting you also need to override the getPreferredSize() method of the component to provide the appropriate size of the component so the layout managers can do there job.

Java - Removing my 'worm' from an arraylist and JFrame

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();
}
}

Java, Grid of Objects

I need help with drawing the grids to the GUI as well as the program later letting me change the colour of the boxes drawn. I know i will have to use paintComponent(Graphics g), but i have no idea how or where.
So here is a copy of the code i have got so far ( even though i have been told it can be quite daunting just being given code i think it is the best way for people to help and not just do it for me). From the top it sets values, creates the GUI, calls the GUI, fills a 2d array with boxes( i think). Then in the Boxes class setting values the boxes class will need, then the start of how to draw them (didn't know how to work it out), then some seta methods for the x and y coordinates.
what i would like you to do is show how to have the boxes be drawn to the Jpanel, to make a grid and then to show me how to change the colour to different shades of blue, depending on a external value.
import java.awt.*;
import java.awt.Graphics;
import java.util.*;
import javax.swing.*;
public class NewGrid {
Boxes[][] Boxs;
int BoxesX;
int BoxesY;
NewGrid() {
buildtheGUI();
}
JFrame frame = new JFrame();
JPanel panel = new JPanel();
public void buildtheGUI() {
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
}
public static void main(String[] args) {
new NewGrid();
}
public void addboxes() {
Boxs = new Boxes[panel.getWidth() / 10][panel.getHeight() / 10];
for (int i = 0; i < panel.getWidth() / 10; i++) {
for (int j = 0; j < panel.getHeight() / 10; j++) {
Boxs[i][j] = new Boxes();
Boxs[i][j].setx(i * (panel.getWidth() / 10));
Boxs[i][j].sety(j * (panel.getHeight() / 10));
Boxs[i][j].draw(null);
}
}
}
}
public class Boxes extends JPanel {
int x;
int y;
int width = 10;
int hieight = 10;
Color colour = Color.BLACK;
public void draw(Graphics g) {
g.setColor(colour);
g.fillRect(x, y, width, hieight);
}
public void setx(int i ){
x = i;
}
public void sety(int i ){
y = i;
}
}
I can't comment something, to try to make things easier,
I code there box.putClientProperty(unique_identifier, value_for_identifier), you can to multiple this method as you want
from every Swing Listener you can to get this and proper coordinated defined in putClientProperty
.
JComponent comp = event.getComponent();
String strRow = (String) comp.getClientProperty("row");
String strColumn = (String) comp.getClientProperty("column");
simple code
import java.awt.*;
import java.awt.Graphics;
import java.util.*;
import javax.swing.*;
public class NewGrid {
private int row = 10;
private int column = 10;
private JFrame frame = new JFrame();
private JPanel panel = new JPanel();
private NewGrid() {
addboxes();
panel.setLayout(new GridLayout(row, column));
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private void addboxes() {
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
Boxes box = new Boxes();
box.putClientProperty("row", row);
box.putClientProperty("column", column);
panel.add(box);
}
}
}
public static void main(String[] args) {
Runnable doRun = new Runnable() {
#Override
public void run() {
new NewGrid();
}
};
SwingUtilities.invokeLater(doRun);
}
}
class Boxes extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(20, 20);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(20, 20);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(20, 20);
}
#Override
public void paintComponent(Graphics g) {
int margin = 2;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2,
dim.height - margin * 2);
}
}

Categories

Resources