public class RainfallStudy extends JFrame{
/**
* Declare global variables
*/
int x = 20, y = 567; //starting location for the title
int xSpeed = 20, ySpeed = 20; // the speed for x and y directions
int delay = 20; // to slow down my title
ImageIcon BackGnd, pic; // variables for the pictures
/**
* Constructor to build the frame
*/
public RainfallStudy() {
// this builds a window with a title
super("Weather Report");
setSize(1000,567);
//loading the picture files
BackGnd = new ImageIcon ("weatherBack.png");
pic = new ImageIcon ("weatherIcon.png");
setResizable(false);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
This is how I made my frame, I then did my animations in public void paint(Graphics g).
now after I call it in the main using new RainfallStudy();, the window stays open after the animation is done, how can I manually close it?
Does it work to call dispose or setVisible on the RainfallStudy instance? For example:
RainfallStudy rs = new RainfallStudy();
rs.setVisible(false);
Related
Mouse Hovering was Required for my Jbutton with pic to be visible, I didn't #Override my paint function anywhere.How to display all the buttons with images without the need of mouse hovering ?!
before Mouse hovering pic
After mouse hovering on all Jbuttons
public class JPicButton extends JButton {
int x, y, max;
/**
* #param path
* :"resources/graphics/index.jpg"
*/
public JPicButton(String fileName, int max) {
this.max = max;
try {
// ImageIcon mx = new ImageIcon(JPicButton.class.getResource("/graphics/" +
// fileName)); #works
Image img = ImageIO.read(JPicButton.class.getResource("/graphics/" + fileName));
img = img.getScaledInstance(10 * (40 / max), 10 * (45 / max), Image.SCALE_SMOOTH);
ImageIcon mc = new ImageIcon(img);
this.setIcon(mc);
} catch (Exception ex) {
System.out.println(ex);
ex.printStackTrace();
}
}
public JPicButton() {
}
public void setOrigin(int x, int y) {
this.x = x;
this.y = y;
}
public void setPath(String fileName) {
try {
Image img = ImageIO.read(JPicButton.class.getResource("/graphics/" + fileName));
img = img.getScaledInstance(10 * (40 / max), 10 * (45 / max), Image.SCALE_SMOOTH);
ImageIcon mc = new ImageIcon(img);
this.setIcon(mc);
} catch (Exception ex) {
System.out.println(ex);
ex.printStackTrace();
}
}
/**
* #return the x
*/
public synchronized int getX() {
return x;
}
/**
* #return the y
*/
public synchronized int getY() {
return y;
} }
this button is initialized in the constructor of the Jpanel too as
package Gui;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Font;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class GamePage extends JPanel {
JPicButton groundMatrix[][];
int xMax, yMax;
public GamePage() {
setBackground(Color.WHITE);
setVisible(false);
setLayout(null);
setSize(700, 500);
JLabel lblNewLabel = new JLabel("MineSweeper");
lblNewLabel.setBounds(48, 13, 250, 50);
add(lblNewLabel);
lblNewLabel.setBackground(Color.PINK);
lblNewLabel.setOpaque(true);
lblNewLabel.setFont(new Font("Comic Sans MS", Font.PLAIN, 18));
lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
JPanel game = new JPanel();
game.setBounds(50, 80, 600, 400);
add(game);
game.setLayout(null);
JLabel lblNewLabel_1 = new JLabel("");
lblNewLabel_1.setBounds(342, 15, 66, 50);
add(lblNewLabel_1);
JLabel label = new JLabel("");
label.setBounds(584, 13, 66, 50);
add(label);
JButton btnNewButton = new JButton("Reset");
btnNewButton.setBounds(446, 15, 97, 50);
add(btnNewButton);
xMax = 15;
yMax = 10;
int Width = 40;
groundMatrix = new JPicButton[xMax][yMax];
for (int y = 0; y < yMax; y++) {
for (int x = 0; x < xMax; x++) {
groundMatrix[x][y] = new JPicButton("Layout1d.jpg", 10);
groundMatrix[x][y].setLocation(Width * x, Width * y);
groundMatrix[x][y].setSize(Width, Width);
game.add(groundMatrix[x][y]);
groundMatrix[x][y].setOrigin(x, y);
}
}
// GridBagConstraints mineGround = new GridBagConstraints();
// mineGround.gridheight = 45;
// mineGround.gridwidth = 40;
}
/**
* #return the groundMatrix
*/
public synchronized JPicButton[][] getGroundMatrix() {
return groundMatrix;
}
/**
* #param groundMatrix
* the groundMatrix to set
*/
public synchronized void setGroundMatrix(JPicButton[][] groundMatrix) {
this.groundMatrix = groundMatrix;
}
/**
* #return the xMax
*/
public synchronized int getxMax() {
return xMax;
}
/**
* #return the yMax
*/
public synchronized int getyMax() {
return yMax;
}
public static void main(String args[]) {
JFrame js = new JFrame();
GamePage gd = new GamePage();
gd.setVisible(true);
js.add(gd);
js.pack();
js.setSize(700, 500);
js.setVisible(true);
}
}
for full code visit
https://bitbucket.org/sarjuns/minesweeper/src
Observations (tl;dr)
Having walked through your code, there are a number of issues which are likely compounding together to cause all sorts of issues, if not immediately, then into the future (and as the solution becomes more complex).
Reliance of null layouts
Every where I look in your code I see setLayout(null);. This is going to haunt you, especially as you try and run the code on different platforms
Swing, like most decent UI frameworks, has an inbuilt concept of how components should be laid out in a platform independent manner.
I'd highly recommend taking some time to look over Laying Out Components Within a Container
Looking through your code I can find good places to use BorderLayout, GridBagLayout, GridLayout and CardLayout, all of which would greatly reduce the complexity of the code and make it easier to change (should you have to) and maintain, as well as support different platforms and rendering pipelines.
Using the JLayeredPane of JFrame
getLayeredPane().add(gamepage); ... I'm not sure what benefit you thought this was going to provide, but it's a very uncommon solution. The JLayeredPane is a great way to display "popup" style information to the user or provide "overlay" information over the content pane, but that's me.
The core of the problem
In the JPicButton class you implement two methods..
/**
* #return the x
*/
public synchronized int getX() {
return x;
}
/**
* #return the y
*/
public synchronized int getY() {
return y;
}
The problem is, these two methods are already defined by JButton and relate to the location the button should be placed relative to it's parent container. Overriding these methods means that when you use setLocation, the values are been ignored.
So, when I modify your code to remove those methods, I get the following result...
The "x/y" position you are trying to manage should actually be managed by a model, the GUI should simply be a representation of the state of the model.
Final Remarks
I've made a number of remarks about the state of your code, it would unprofessional for me to do otherwise, as you are digging yourself into a never ending hole of re-work and head scratching issues which could be easily solved with the available API support.
I believe, however, you've made a good start on attempting to solve the over all problem and would encourage you to continue, but taking into account some of the observations that have been made.
I'm trying to create an animation in which a given number of icons start on the left side of the frame and move to the right side of the screen. The icons are lined up vertically and each is supposed to run on its own thread.
How do I get all icons to do this? I tried adjusting posY when I create each racer, but so far I can only get the last racer that's created to show.
import javax.swing.*;
import java.awt.*;
public class Races {
private JFrame frame;
private JPanel gui;
private Icon img;
private int imgWidth;
private int imgHeight;
private int numOfRacers; // num of threads / racers
public static void main(String[] args) {
new Races(5);
}
public Races(int num) {
numOfRacers = num;
createGUI();
frame.add(gui);
frame.pack();
frame.setVisible(true);
}
private void createGUI() {
frame = new JFrame("Off to the Races - by Brienna Herold");
gui = new JPanel();
gui.setPreferredSize(new Dimension(imgWidth * 20, imgHeight * numOfRacers));
img = new ImageIcon("races.png");
imgWidth = img.getIconWidth();
imgHeight = img.getIconHeight();
int posY = 0;
for (int i = 0; i < numOfRacers; i++) {
System.out.println("Starting new thread..." + posY);
racer = new Racer(posY);
Thread racerThread = new Thread(racer);
racerThread.start();
posY += imgHeight;
}
}
protected class Racer extends JPanel implements Runnable {
private int lastPosX;
private int posX;
private int posY;
public Racer(int _posY) {
posX = 0;
posY = _posY;
}
#Override
public void paintComponent(Graphics g) {
// Call the method on the JPanel
super.paintComponent(g);
img.paintIcon(gui, g, posX, posY);
//posY += imgHeight;
posX += lastPosX + 3;
}
#Override
public void run() {
while (true) {
repaint();
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
}
gui.add(racer, BorderLayout.CENTER);
You only ever add one Racer component to the frame.
but so far I can only get the last racer that's created to show.
The "racer" variable points to the last Racer component created.
If you want multiple components then you will need to create a panel using a null layout. Then you need to add each Racer component to this panel and then add the panel to the frame. Using this approach you would move the component by using the setLocation(...) method of the component.
If you want to paint an image in a different location, then you would use a single panel which would contain an ArrayList or Racer objects. Then when the paintComponent() method of the panel is invoked you iterate through the List and paint each Racer at its new location.
I am having a problem on relating a listener to the southButton to handle events.
(southButton.addActionListener(new RandomColorListener(drawPanel));)
When the user clicks on the JButton in the SOUTH region, the
rectangles filled with color1 should all change to a random Color,
while the rectangles filled with color2 should not change. A second
click on the JButton should make the rectangles filled with color2 all
change to a random Color, while the rectangles filled with a random
Color by the first click should stay the same Color.
The user should be able to continue clicking on the button indefinitely, and with each click one set of rectangles will be filled with a random Color. In each case, the rectangles to change should be the ones that stayed the same on
the last click (in other words, the Color change should alternate between the two sets of rectangles). This means that with each click only one set of rectangles should change colour.
I tried to pass drawPanel into randomListener but there is this Java error comes out.
Java Error: Constructor RandomColorListener in class
RectanglesGUI.RandomColorListener cannot be applied to given type.
Can somebody tell me what should I do in order to use drawPanel inside class randomListener
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
public class RectanglesGUI
{
JFrame frame;
RectangleDrawPanel drawPanel;
Color color1 = Color.orange;
Color color2 = Color.blue;
//Set fixed number of rows and columns
protected static final int ROWS = 5;
protected static final int COLS = 5;
private List<Color>colors;
public static void main (String[] args)
{
RectanglesGUI gui = new RectanglesGUI();
gui.go();
}
//this method sets up the JFrame, adds the button and drawpanel to the frame and adds the ActionListener to the button
public void go()
{
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawPanel = new RectangleDrawPanel();
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
//Add a JButton to the SOUTH region of the JFrame using BorderLayout. Set the text on the button.
JButton southButton = new JButton("Click to CHANGE color on alternate set of Rectangles");
frame.getContentPane().add(BorderLayout.SOUTH, southButton);
frame.setSize(600,600);
frame.setVisible(true);
//Relate a listener to the southButton to handle events.
southButton.addActionListener(new RandomColorListener(drawPanel));
//Relate another listener to northButton.
northButton.addActionListener(new ResetListener() {});
}
//Inner class to implement actionListener and listen to the JButton in the SOUTH region
class RandomColorListener implements ActionListener
{
private RectangleDrawPanel myPanel;
public RectangleDrawPanel (RectangleDrawPanel aPanel)
{
this.myPanel = aPanel;
}
#Override
public void actionPerformed (ActionEvent e)
{
int r = (int)(Math.random()*256);
int g = (int)(Math.random()*256);
int b = (int)(Math.random()*256);
color1 = new Color(r,g,b);
RectangleDrawPanel();
}
}
class RectangleDrawPanel extends JPanel{
#Override
public void paintComponent (Graphics g)
{
//Store 2 colors Alternatively in the Arraylist using for loop
int length = ROWS * COLS;
colors = new ArrayList<>(length);
for(int i=1;i<=length;i++)
{
double count;
count = i;
if(count%2 == 0)
{colors.add(color2);}
else
{colors.add(color1);}
}
super.paintComponent(g);
Graphics2D g2=(Graphics2D)g;
//Distribute the rectangles Evenly using for loop and Fill them with colors (from ArrayList)
int rectWidth = getWidth()/5;
int rectHeight = getHeight()/5;
for (int y = 0; y < ROWS; y++)
{
for (int x = 0; x < COLS; x++)
{
int index=(y * COLS) + x;
g2.setColor(colors.get(index));
g2.fillRect(x * rectWidth, y * rectHeight, rectWidth, rectHeight);
}
}
}
}
}
I have a picture that details what I want to achieve for all values of Game.height. Problem is my mathematical expression in the variable circle_dy seems to be incorrect when it comes to scale the image's location for all values of Game.height.
// images of the game
private Image circle;
// ball's spawning location
private int circle_dx = 0;
private int circle_dy = (Game.height/2) + 30 ;
public class GameBoard{
public GameBoard(){
// construct an ImageIcon specified by the given string directory
ImageIcon circle = new ImageIcon("src/pics/circle.png");
// get image type of the ImageIcon and assign it into the image instance //variable
this.circle = circle.getImage();
setBackground(Color.black);
}
// appropriate method to paint is paintComponent
public void paintComponent(Graphics g){
// if you are overriding a method call the super class paintComponent method
// because you are creating your own version of the paintComponent method
super.paintComponent(g);
// draw the image itself at a particular location on the JPanel
g.drawImage(this.circle,circle_dx,circle_dy,this);
}
}
public class Game extends JFrame{
public static final int width = 600;
public static final int height = 200;
public Game(){
// add the JPanel to the jframe
add(new GameBoard());
setVisible(true);
// set the size of the jframe
setSize(width,height);
}
}
As a suggestion:
Write a listener for windows resize that will update the size of your ball.
To calculate the required size changes, grab the x and y sizes of your window (would suggest saving them each time listener finishes). Work out the old and new values as a % then scale your ball by the same %.
For reference: http://docs.oracle.com/javase/tutorial/uiswing/events/componentlistener.html
For homework, I'm trying to create a "CustomButton" that has a frame and in that frame, I draw two triangles, and a square over it. It's supposed to give the user the effect of a button press once it is depressed. So for starters, I am trying to set up the beginning graphics, drawing two triangles, and a square. The problem I have is although I set my frame to 200, 200, and the triangles I have drawn I think to the correct ends of my frame size, when I run the program, I have to extend my window to make the whole artwork, my "CustomButton," viewable. Is that normal? Thanks.
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CustomButton
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
CustomButtonFrame frame = new CustomButtonFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class CustomButtonFrame extends JFrame
{
// constructor for CustomButtonFrame
public CustomButtonFrame()
{
setTitle("Custom Button");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
CustomButtonSetup buttonSetup = new CustomButtonSetup();
this.add(buttonSetup);
}
private static final int DEFAULT_WIDTH = 200;
private static final int DEFAULT_HEIGHT = 200;
}
class CustomButtonSetup extends JComponent
{
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
// first triangle coords
int x[] = new int[TRIANGLE_SIDES];
int y[] = new int[TRIANGLE_SIDES];
x[0] = 0; y[0] = 0;
x[1] = 200; y[1] = 0;
x[2] = 0; y[2] = 200;
Polygon firstTriangle = new Polygon(x, y, TRIANGLE_SIDES);
// second triangle coords
x[0] = 0; y[0] = 200;
x[1] = 200; y[1] = 200;
x[2] = 200; y[2] = 0;
Polygon secondTriangle = new Polygon(x, y, TRIANGLE_SIDES);
g2.drawPolygon(firstTriangle);
g2.setColor(Color.WHITE);
g2.fillPolygon(firstTriangle);
g2.drawPolygon(secondTriangle);
g2.setColor(Color.GRAY);
g2.fillPolygon(secondTriangle);
// draw rectangle 10 pixels off border
g2.drawRect(10, 10, 180, 180);
}
public static final int TRIANGLE_SIDES = 3;
}
Try adding
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
to your CustomButtonSetup class.
And then do
setTitle("Custom Button");
//setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
CustomButtonSetup buttonSetup = new CustomButtonSetup();
this.add(buttonSetup);
pack();
(From the api-docs on pack():)
Causes this Window to be sized to fit the preferred size and layouts of its subcomponents.
You should get something like:
The DEFAULT_WIDTH and DEFAULT_HEIGHT that you set is for the entire frame, including borders, window titles, icons, etc. It's not the size of the drawing canvas itself. Thus, it is expected that if you draw something in a 200x200 canvas, it would not necessarily fit in a 200x200 window containing that canvas.