How to handle window size for GraphicsProgram (ACM library)? - java

I want to define the size of the window, but I did not find a clean way to do it. SetSize() gives a strange result:
public class Test extends GraphicsProgram {
public void run() {
setSize(400, 600);
add(new GLabel("Width: " + getWidth(), 30, 30));
add(new GLabel("Height: " + getHeight(), 30, 50));
}
}
The result is 384 x 542. The gap is always the same (-16 x -58), so it's easy to build a work around. Is there a way to define the size in useful pixels directly?

I found a solution to this while studying the code of a Stanford course project (breakout). GraphicsProgram is not constructed according to its fields, WIDTH, HEIGHT, EAST, CENTER etc, automatically. Therefore we need a resize() to set the window size which acm.program.GraphicsProgram inherits from java.applet.Applet.
Simply adding a resize() and pause() will do the work.
public class Test extends GraphicsProgram {
private static final int WIDTH = 400;
private static final int HEIGHT = 600;
private static final int PAUSE = 10; // or whatever interval you like
public void run() {
this.resize(WIDTH,HEIGHT);
pause(PAUSE);
// game logic here
...
}
}
The pause() is necessary as the resize takes time. It avoids the mis-displacement of components if you are adding them right after resizing.

public void init() {
setSize(400, 600);
}
instead of setting the size in the run method do it on the init!

After class:
public static final int APPLICATION_WIDTH = 900; // x size of window
Before run:
public static final int APPLICATION_HEIGHT = 540; // y size of window

No need for setSize or resize.
You just need to add this two public variables:
/** Width and height of application window in pixels */
public static final int APPLICATION_WIDTH = 400;
public static final int APPLICATION_HEIGHT = 600;
and these two if you need exactly WIDTH and HEIGHT to use:
/** Dimensions of window (usually the same) */
private static final int WIDTH = APPLICATION_WIDTH;
private static final int HEIGHT = APPLICATION_HEIGHT;

Related

Trying to add a JavaFX shape from another class and create it in my main class. The Class cannot be converted to node

I'm very new to Java. I've been using it for the last two months. The end goal of my code is to try and create a shape and add it to the window without having to set all the properties of the shape in the main "view" class.
When I attempt to add my work in progress Castle class, Intellij is telling me I need to provide a node instead. Below I will provide the class where I'm setting the properties of the shape and the main class where I get halted trying to add it to my window.
public class Castle {
private int width = 1280; // width of the window
private int height = 720; // height of the window
private double x, y, size;
private int denizens;
private Color color;
private String name;
private Random rn = new Random();
// constructor
Castle() {
x = 50;
y = 50;
size = 10;
color = Color.GRAY;
name = "Anthony's Castle";
denizens = rn.nextInt();
}
// GraphicsContext method
protected void draw(GraphicsContext gc) {
Rectangle rec = new Rectangle(x, y);
rec.setX(100);
rec.setY(100);
rec.setWidth(100);
rec.setHeight(100);
rec.setFill(Color.RED);
}
// get methods
public int getDenizens() {
return denizens;
}
public double getSize() {
return size;
}
}
public class TwoDomains extends Application {
public void start(Stage primaryStage) {
Group root = new Group();
Scene scene = new Scene(root, 1280, 720, Color.BEIGE);
Castle castle = new Castle();
root.getChildren().add(castle);
primaryStage.setScene(scene);
primaryStage.setTitle("Village");
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
You can only add Nodes to the scene graph, and your Castle class is not a node.
Your draw() method looks strange. It creates a Rectangle (which is a Node), but doesn't do anything with it. It also takes a GraphicsContext2D as a parameter, which looks like you're going to draw on a canvas, but you don't have a canvas.
You just need to organize the code so that, one way or another, your Castle class provides some kind of Node.
One way is to refactor your draw method as
public Node draw() {
Rectangle rec = new Rectangle(x, y);
rec.setX(100);
rec.setY(100);
rec.setWidth(100);
rec.setHeight(100);
rec.setFill(Color.RED);
return rec ;
}
and then replace
root.getChildren().add(castle);
with
root.getChildren().add(castle.draw());
Note that with this setup, each time you call draw() on a single Castle instance will create a new Node, which may or may not be what you want, but it is a very simple task to refactor it if it's not what you want.
Maybe you want:
public class Castle extends Group {
private int width = 1280; // width of the window - does EACH castle need a separate copy of this info?
private int height = 720; // height of the window
private double x, y, size;
private int denizens;
private Color color;
private String name;
private Random rn = new Random(); // This probably should be static, or somewhere else.
// constructor
Castle() {
x = 50;
y = 50;
size = 10;
color = Color.GRAY;
name = "Anthony's Castle";
denizens = rn.nextInt();
makeShape();
}
protected void makeShape() {
Rectangle rec = new Rectangle(x, y);
rec.setX(100);
rec.setY(100);
rec.setWidth(100);
rec.setHeight(100);
rec.setFill(Color.RED);
getChildren().add(rec);
}
// get methods
public int getDenizens() {
return denizens;
}
public double getSize() {
return size;
}
}

Java Swing DrawRect: creating new replaces old dimensions

I tried making two rectangles using the class below: DrawRect but when I create a new DrawRect object it replaces old one's width and height.
package MemDiagramVisualizer;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class DrawRect extends JPanel {
private static int RECT_X;
private static int RECT_Y;
private static int RECT_WIDTH;
private static int RECT_HEIGHT;
public DrawRect(int w, int h) {
RECT_X = 20;
RECT_Y = 20;
RECT_WIDTH = w;
RECT_HEIGHT = h;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(RECT_X, RECT_Y, RECT_WIDTH, RECT_HEIGHT);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(RECT_WIDTH + 2 * RECT_X, RECT_HEIGHT + 2 * RECT_Y);
}
}
JPanel visDisplay = new JPanel();
visDisplay.setLayout(new GridLayout(1,3));
DrawRect rec2 = new DrawRect(40,60);
visDisplay.add(rec2);
DrawRect rec = new DrawRect(100,600);
visDisplay.add(rec);
The code above when added to frame content pane creates two rectangles with 100,600 dimensions
You have a couple of issues in your program:
All these 4 variables:
private static int RECT_X;
private static int RECT_Y;
private static int RECT_WIDTH;
private static int RECT_HEIGHT;
They all are static, but you're trying to change them inside the program, this will apply for all the instances of your program and they all are gonna share the value. In this case I'd suggest you to remove that and you should be good. This is the reason why when you create another class with the same code, it worked.
RECT_X = 20; and RECT_Y = 20; inside the constructor, if these are constants, then initialize them at the top and don't set them in every instance of the class.
Not an error, but depending on your requirements, you might want to stop using multiple JPanels and instead use the Shape API as shown in this answer to create an Array of Shapes that you can draw in a single JPanel. Again, this all depends on your needs.
After removing the static keyword from those constants above, we have this:

I'm trying to draw square in java but it doesn't work

I'm trying to draw squares to make grid system to make snake game in java but when i run my code i can't see any thing.
I made node class that has the square info like position, and grid class that has the data of all the squares and GUI class and i tried to use drawRect method but i have no result.
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.*;
import java.util.List;
public class SnakeGame {
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setSize(300,300);
frame.setLayout(null);
Grids grids = new Grids(300);
GUI gui = new GUI(grids.nodesList,grids.nodeSize);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(gui);
frame.setVisible(true);
}
public static class Node{
public float[] position = new float[2];
public Node(float[] Position){
//this is the x position
position[0] = Position[0];
//this is the y position
position[1] = Position[1];
}
}
public static class Grids{
public int nodesNum = 6;
public float screenSize;
public float nodeSize;
public float[] startNodePos = new float[2];
public List<Node> nodesList = new ArrayList<Node>();
public Grids(float ScreenSize){
screenSize = ScreenSize;
nodeSize = screenSize / nodesNum;
//set the start node position
//x
startNodePos[0] = nodeSize /2;
//y
startNodePos[1] = nodeSize /2;
//use for loop to create nodes
for (float X = startNodePos[0] ; X <= nodeSize * 5; X += nodeSize / 2) {
for (float Y = startNodePos[1]; Y <= nodeSize * 5; Y += nodeSize / 2) {
float[] Pos = {X, Y};
Node node = new Node(Pos);
nodesList.add(node);
}
}
}
}
public static class GUI extends JPanel{
public List<Node> nodes;
public float NodeSize;
public GUI(List<Node> Nodes,float nodeSize){
nodes = Nodes;
NodeSize = nodeSize;
}
#Override
public void paintComponents(Graphics g) {
super.paintComponents(g);
for(Node node : nodes){
g.setColor(Color.BLACK);
g.drawRect((int)node.position[0],(int)node.position[1],(int)NodeSize,(int)NodeSize);
}
}
}
}
There are two primary mistakes
First
frame.setLayout(null);
This means that you will become completely responsible for determine the location and size of all child components.
In this case, it's probably just easier to get rid of it and use the default BorderLayout
Second
You're overriding paintComponents, not paintComponent (not the s at the end)
public void paintComponents(Graphics g) {
//...
}
Since, there are no components to be painted, it's not getting called
Simple change it to paintComponent (and make sure you call it's super properly)
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Node node : nodes) {
g.setColor(Color.BLACK);
g.drawRect((int) node.position[0], (int) node.position[1], (int) NodeSize, (int) NodeSize);
}
}
Observations
While running through the code, I note some ... interesting things, which might cause you issues in the long run.
The size of the view area is not the same as the size of the window. A window also needs to display the window decorations (title bar, borders, etc), which are inset into the window. This reduces the available viewable area. It's better to have the content provide a sizing hint and pack the window around, which brings me to...
The model seems to be taking into consideration view properties. You should aim to have the model and view be as agnostic as possible, meaning that the model should not be dictating display state to the view. Instead, the size of the cell's, and by extensions, the size of the panel, should be determined by the view.

grid layout with JPanels java

I am trying to create a program in Java that is sort of like a board game. I have gameTiles, currently with only one color as I try to get the layout right. I want the tiles to appear about halfway of the width of the window and extend to the bottom, maybe anywhere from 9x9 or 11x11 different tiles. I have tried to use the grid layout to get these to be close together, not necessarily touching but close enough to look like a board game. However, no matter what I try, the tiles are space so far apart, and change shape when I resize window. I have been using the GridLayout manager to try to achieve this. Here is my code.
import java.awt.GridLayout;
import javax.swing.JFrame;
public class GameWindow extends JFrame {
public GameWindow(String title){
super(title);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1200,400);
}
/**
* #param args
*/
public static void main(String[] args) {
GameWindow gameWindow = new GameWindow("Game");
gameWindow.setLayout(new GridLayout(0,2));
GameTile greenTile = new GameTile(0,true,0,10);
GameTile greenTile2 = new GameTile(0,true,0,10);
gameWindow.add(greenTile);
gameWindow.add(greenTile2);
gameWindow.setVisible(true);
}
}
This is the GameWindow.java file. The GameTile.java I have so far (which is still mainly not finished just for testing) is as follows:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
/**
* #author Zachary Parks
*
*/
public class GameTile extends JPanel {
private Color color;
private Color[] colors = {Color.BLUE, Color.YELLOW, Color.BLACK};
private int score, multiplier,initialX,initialY;
private boolean positiveEffect;
public GameTile(int colorTile, boolean effect, int initX, int initY){
color = colors[colorTile];
score = getScore(color);
multiplier = getMultiplier(color);
positiveEffect = effect;
initialX = initX;
initialY = initY;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Image image = null;
try {
image = ImageIO.read(new File("greentile.png"));
} catch (IOException e) {
e.printStackTrace();
}
g.drawImage(image,initialX,initialY,this);
}
private int getMultiplier(Color color2) {
return 0;
}
private int getScore(Color color2) {
return 0;
}
/**
* Method that returns the data from the tile in
* array of int. 0 index = added score, 1 index = tile effect score
* #return
*/
public int[] getData() {
int [] scoreData = null;
scoreData[0] = score*multiplier;
return null;
}
}
A lot of the code is still in progress, like the GameTile's properties, all I'm trying at this point is get the tiles next to each other.
This is what I am getting:
To add tiles like a grid. A tileSize variable is great to have. Let's say the image/tile is 32 pixels.
public static final tileSize = 32;
With this, we can now add tiles using a for loop:
for(int x = 0; x < SCREEN_WIDTH / GameTile.tileSize; x++) { // loop through as many tiles fit the x-axis.
for(int y = 0; y < SCREEN_HEIGHT / GameTile.tileSize; y++) { // do the same with y-axis
GameTile greenTile = new GameTile(0,true, x * GameTile.tileSize , y * GameTile.tileSize);
gameWindow.add(greenTile);
}
}
SCREEN_WIDTH and SCREEN_HEIGHT is the size of your JFrame.
Keep in mind this loops through the whole screen, you wanted the half but it's easily configurable.
Please format your code next time (tab in), much easier to read and help you.
I highly recommend moving image = ImageIO.read(new File("greentile.png")); into the constructor, right now you're loading the image every framerate for every gameTile which will cause performance drop.
Also do not have a JPanel for every GameTile. Instead keep it in your main drawing class and loop through all GameTiles using an ArrayList
public static ArrayList<GameTile> gameTiles = new ArrayList<GameTile>();
protected void paintComponent(Graphics g) {
for(int i = 0; i < gameTiles.size(); i++) {
gameTiles.get(i).draw(g);
}
So instead of adding a JPanel to the JFrame for every gameTile, we draw gameTiles at the specified coordinates. Good luck!
To answer your question in the comment field: the code will look similar to this
public class GameWindow extends JPanel {
public static ArrayList<GameTile> gameTiles = new ArrayList<GameTile>();
public static void main(String[] args) {
new GameWindow();
}
public GameWindow() {
JFrame frame = new JFrame();
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.setVisible(true);
// add all the tiles (I just use x and y as parameters here)
gameTiles.add(new GameTile(10, 10));
gameTiles.add(new GameTile(50, 10));
}
public void paintComponent(Graphics g) {
for(int i = 0; i < gameTiles.size(); i++) {
gameTiles.get(i).draw(g);
}
}
}
And inside your GameTile class, remove the extends JPanel. And rename the paintComponent as draw or something alike.
However, no matter what I try, the tiles are space so far apart, and change shape when I resize window
A GridLayout expands each cell to fill the space available to the component. If you only have two cells each cell will take up half the width of the frame.
So the solution is to wrap your tile panel into another panel that will respect the preferred size of the tiles. So don't set the layout of the frame, set the layout of a panel holding the tiles:
Something like:
JPanel tilePanel = new JPane( new GridLayout(0, 2, 5, 5) );
tilePanel.add( new GameTile(...) );
tilePanel.add( new GameTile(...) );
JPanel wrapper = new JPanel( new GridBagLayout() );
wrapper.add(tilePanel, new GridBagConstraints() );
frame.add(wrapper, BorderLayout.CENTER );
The above code will cause the tiles to be centered in the frame.
frame.add(wrapper, BorderLayout.LINE_END);
The above will cause the tiles to display on the right of the frame vertically centered.

Cannot remove shapes in Java using mouseEvents

I am trying to make an original game in Eclipse and I am having some trouble writing code that will remove GObjects and change the properties of others, using the mouseClicked method.
The problem seems to be that the private instant variables are not being recognised in the mousePressed method.
Can someone please advise on what I'm getting wrong here? I have spent a whole day on this and some help will be greatly appreciated.
Kind regards,
Mehul
*/*
* File: Linesv1.java
* 07/08/2012
*
*/
import acm.graphics.*;
import acm.program.*;
import acm.util.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.MenuEvent;
public class Linesv1 extends GraphicsProgram {
/** Width and height of application window in pixels */
public static final int BACKGROUND_WIDTH = 400;
public static final int BACKGROUND_HEIGHT = 600;
/** Dimensions of game board (usually the same) */
private static final int WIDTH = BACKGROUND_WIDTH;
private static final int HEIGHT = BACKGROUND_HEIGHT;
/** Dimensions of triangle*/
private static final int LENGTH_OF_TRIANGLE_SIDE = 100;
/** Dimensions of arc height*/
private static final int ARC_HEIGHT = 100;
/** Dimensions of radius of switches*/
private static final int SWITCH_RADII = 5;
// private instant variables
private GObject switchA;
private GOval switchB;
private GObject triangle;
private GObject bottomArc;
public void run() {
addMouseListeners();
setUpGame();
}
public void setUpGame(){
//add central triangle
GPolygon triangle = new GPolygon (WIDTH/2,HEIGHT/2);
triangle.addVertex(0,-LENGTH_OF_TRIANGLE_SIDE*2/3);
triangle.addVertex(LENGTH_OF_TRIANGLE_SIDE/2,+LENGTH_OF_TRIANGLE_SIDE*1/3);
triangle.addVertex(-LENGTH_OF_TRIANGLE_SIDE/2,+LENGTH_OF_TRIANGLE_SIDE*1/3);
triangle.setFilled(true);
triangle.setFillColor(Color.green);
add(triangle);
//add topArc
GArc bottomArc = new GArc (WIDTH/2-LENGTH_OF_TRIANGLE_SIDE/2, HEIGHT/2+LENGTH_OF_TRIANGLE_SIDE*1/3-ARC_HEIGHT/2, ARC_HEIGHT,ARC_HEIGHT,0,-180);
bottomArc.setFilled(true);
bottomArc.setFillColor(Color.green);
add(bottomArc);
//add switches to the bottom of the triangle
GOval switchA = new GOval (WIDTH/2-LENGTH_OF_TRIANGLE_SIDE/2-SWITCH_RADII, HEIGHT/2+LENGTH_OF_TRIANGLE_SIDE*1/3-SWITCH_RADII,SWITCH_RADII*2,SWITCH_RADII*2);
switchA.setFilled(true);
switchA.setFillColor(Color.black);
add(switchA);
//add switches to the bottom of the triangle
GOval switchB = new GOval (WIDTH/2+LENGTH_OF_TRIANGLE_SIDE/2-SWITCH_RADII, HEIGHT/2+LENGTH_OF_TRIANGLE_SIDE*1/3-SWITCH_RADII,SWITCH_RADII*2,SWITCH_RADII*2);
switchB.setFilled(true);
switchB.setFillColor(Color.black);
add(switchB);
}
public void mousePressed(MouseEvent e) {
findObject(e.getX(),e.getY());
GObject check = findObject(e.getX(),e.getY());
if (check!=null){
remove(triangle);
switchA.setColor(Color.cyan);
}
}
private GObject findObject(int a, int b){
if(getElementAt(a,b) != null) {
return getElementAt(a,b);
} else {
return null;
}
}
}*
The triangle you are trying to remove is not the one you added. You created a local GPolygon called triangle in setupGame() and added that, not the private member.
private GObject triangle; // this is uninitialized
public void setUpGame(){
GPolygon triangle = new GPolygon (WIDTH/2,HEIGHT/2); // this is hiding your member variable
// THIS IS LOCAL COPY, NOT MEMBER VARIABLE
add(triangle);
And then later you try to remove the uninitialized member variable, so nothing happens. You probably don't want a separate local copy of triangle. You probably want
public void setUpGame() {
triangle = new GPolygon (WIDTH/2, HEIGHT/2);
// ...
add(triangle); // Now, you are adding the member
}

Categories