I'm new at Java and I'm trying to make a chess with it for training.
I'm having some trouble with the Graphic methods though.
I listed the functions which the mistake could have been in.
The code below shows a function called in main.
This function is inside my package that handle Graphic stuff.
public class GUI_main extends JComponent{
private final int tam = 100;
private final int tamTab = 8 * tam;
Image torre;
public void inicializaTabuleiro(Torre t)
{ //Sets the window properties and the "tile" proper image.
JFrame janela = new JFrame("Xadrez");
janela.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
janela.setSize(816, 839);
janela.getContentPane().add(new GUI_main());
janela.setLocationRelativeTo(null);
janela.setResizable(false);
janela.setVisible(true);
paintPeca(t); /*this one is the function that sets the correct image
for the tile that will be on the board*/
System.out.println("Janela inicializada com sucesso!");
}
...
next one is the "paintPeca" function, which should initialize "Image torre".
public void paintPeca(Torre t)
{
System.out.println(t.imgPeca());
torre = Toolkit.getDefaultToolkit().getImage(t.imgPeca());
}
and finally my paint function:
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.black);
int x = 0, y = 0;
while(y<tamTab) //draw board
{
if(y%200 == 0)
{
g2.draw(new Rectangle2D.Double(x, y, tam, tam));
x = x + tam;
g2.fill(new Rectangle2D.Double(x, y, tam, tam));
x = x + tam;
}
else
{
g2.fill(new Rectangle2D.Double(x, y, tam, tam));
x = x + tam;
g2.draw(new Rectangle2D.Double(x, y, tam, tam));
x = x + tam;
}
if(x == tamTab)
{
y = y + tam;
x = 0;
}
}
x = 14;
y = 19;
g2.drawImage(torre, x, y, this); //draw tower
g2.finalize();
...
Together these functions should have draw a board and a tower on it.
It's showing me the board, but not the tower (Image torre), and I do not have a clue on the reason.
"t.imgPeca()" returns a string (path to image), and it's correct, as I have tested before.
Since I'm new at Java this might be some kind of of silly mistake, but I have not found the answer in other pages of stack that talked about the drawImage function.
Related
I'm new to Java as well as user interfaces, and I have a problem with Java Graphics. What I'm trying to achieve is drawing a grid on a JPanel, and then paint custom components into the grid.
Here is the class I want to draw the grid on (its base extends JPanel).
public class RectGridPanel extends GridPanel
{
List<Rectangle> rects;
public RectGridPanel(Simulator sim)
{
super(sim);
this.rects = new ArrayList<Rectangle>();
this.setLayout(new GridLayout(20,20));
for(int x = 1; x < 801; x += 40)
{
for(int y = 2; y < 801; y += 40)
{
Cell newCell = new RectCell(x, y, sim);
this.add(newCell);
}
}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.BLACK);
for(int x = 1; x < 801; x += 40)
{
for(int y = 2; y < 801; y += 40)
{
Rectangle rect = new Rectangle(x, y, 40, 40);
g2.draw(rect);
rects.add(rect);
}
}
}
}
Here are the cells I want to draw inside the grid:
public class RectCell extends Cell
{
Rectangle shape;
public RectCell(int x, int y, Simulator sim)
{
super(x, y, sim);
shape = new Rectangle(x, y, CELL_SIZE, CELL_SIZE);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.BLACK);
g2.fill(shape);
}
}
So the grid on its own draws out fine, but as soon as I try to create cells inside it it gets disrupted like that:
public class RectCell extends Cell
{
Rectangle shape;
public RectCell(int x, int y, Simulator sim)
{
super(x, y, sim);
shape = new Rectangle(x, y, CELL_SIZE, CELL_SIZE);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.BLACK);
g2.fill(shape);
}
}
The Graphics object that is passed to this paintComponent() function defines the screen space where the current RectCell can draw. The coordinate sysetem is relative to the upper left corner of the RectCell, so drawing the background should always start at x = 0 and y = 0 or some other meaningful value. The coordinates here are not relative to the parent component as you seem to assume.
Better yet, set the background color and let Swing take care of painting it rather than painting a rectangle yourself.
It is not clear what you try to achive.
What is the reason for RectCell? Why not paint the shapes direct in the RectGridPanel?
The nested loop in the paintComponent it not a good idea. Be aware that the paintComponent is called very often and every time you in crease the rects list with new objects. The former painted rectangles get lost (qraphicaly) and new rectangles with the same parameters are blowing the list.
UPDATE: I Figured out the problem and wrote it out below.If you'd like to see the full compliable code here it is on GitHub: https://github.com/scohen40/cohen-mco364-fall-2018/tree/mazeGUI/src/main/java/cohen/maze
I have a 2D Array of Cells, each with 4 walls. My generateMaze() class starts at a random point and digs out a maze. That part works correctly, and when I print out the maze in the console everything is fine.
My next goal is to have the maze painted out with a JComponent in a JPanel. The problem is that all I'm getting is one thick-lined box in the top left corner.
Here's the painting code:
public class AnimatedMaze extends JComponent {
private Maze maze;
private int componentHeight;
private int componentWidth;
private int seventhHeight;
private int seventhWidth;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
componentHeight = this.getHeight();
componentWidth = this.getWidth();
seventhHeight = componentHeight/7;
seventhWidth = componentWidth/7;
maze = new Maze(7, 7);
g.setColor(Color.black);
paintMaze(g);
}
/**
* The paintMaze() method runs through the generated maze and paints the existing walls.
* #param g
*/
void paintMaze(Graphics g) {
for (int x = 0; x < maze.getHeight(); x++) {
System.out.println("|");
for (int y = 0; y < maze.getWidth(); y++) {
Cell current = maze.getMaze()[x][y];
if(current.isWestWall()) {
g.drawLine(x, y, x, y + seventhHeight);
}
if(current.isNorthWall()){
g.drawLine(x, y,x + seventhWidth, y);
}
if(current.isEastWall()) {
g.drawLine(x + seventhWidth, y, x+ seventhWidth, y + seventhHeight);
}
if(current.isSouthWall()) {
g.drawLine(x, y + seventhHeight, x + seventhWidth, y +seventhHeight);
}
}
}
}
}
You can see in the console the generated maze but in the JPanel it'sjust a box.
In your painting code you need to multiply every x and y coordinate by 'seventhHeight', otherwise you are not painting to correct coordinates.
Building on the answer by Krzysztof Cichocki, realized that coordinates work differently from rows and tables. I switched the x's for y's and vice versa, after multiplying everything by seventhHeight. Also any additions that I did to any coordinate is always seventhHeight now, to make everything proportional.
Here's the current code for the painting method:
void paintMaze(Graphics g) {
for (int x = 0; x < maze.getHeight(); x++) {
System.out.println("|");
for (int y = 0; y < maze.getWidth(); y++) {
Cell current = maze.getMaze()[x][y];
if(current.isWestWall()) {
g.setColor(Color.black);
g.drawLine((y+1)*seventhHeight, x*seventhHeight, (y+1)*seventhHeight, x*seventhHeight + seventhHeight);
}
if(current.isNorthWall()){
g.drawLine((y+1)*seventhHeight, x*seventhHeight,(y+1)*seventhHeight + seventhHeight, x*seventhHeight);
}
if(current.isEastWall()) {
g.drawLine((y+1)*seventhHeight + seventhHeight, x*seventhHeight, (y+1)*seventhHeight + seventhHeight, x*seventhHeight + seventhHeight);
}
if(current.isSouthWall()) {
g.drawLine((y+1)*seventhHeight, x*seventhHeight + seventhHeight, (y+1)*seventhHeight + seventhHeight, x*seventhHeight +seventhHeight);
}
}
}
}
This is now what happens:
im trying to paint random (not yet) circles on a JPanel through click on a JMenu.
Im using a JTextField (and have to keep this) for some output.
Here is my Class:
class RandomDrawer extends JPanel implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
//double x = Math.random();
//double y = Math.random();
Random generator = new Random();
int x = generator.nextInt(100)+1;
int y = generator.nextInt(100)+1;
//System.out.printf("x = %d y = %d\n", x, y);
status.setText(String.format("rnd draw x: %d y: %d", x, y));
Graphics2D gg = (Graphics2D) canvas.getGraphics();
gg.setColor(Color.BLACK);
gg.drawOval(50, 50, 50, 50);
}
}
As long i let the line
status.setText(String.format("rnd draw x: %d y: %d", x, y));
stay in there i get nothing drawn. Without it i get my circle, im not sure what the problem is. I cant figure out why nothing is drawn.
Thanks a lot
EDIT:
Hello, i tried to understand the given informations.
Sadly I have to draw using the Graphics2D class, so i guess i can not draw using shapes. So i tried this, sadly it wont draw yet, can u give me some tips?
I tried to create a new class DrawShape, my thought was that i could keep track with those objects.
In my understanding there should be a drawn oval right now
gg.drawOval(100,100,100,100);
Thank you.
class DrawShape {
public DrawShape(String string) {
// TODO Auto-generated constructor stub
}
}
class RandomDrawer extends JPanel implements ActionListener {
/* (non-Javadoc)
* #see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
private List<DrawShape> shapes = new ArrayList<DrawShape>();
public void addShape(DrawShape s) {
shapes.add(s);
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D gg = (Graphics2D) g;
gg.setColor(Color.BLACK);
gg.drawOval(100, 100, 100, 100);
}
#Override
public void actionPerformed(ActionEvent e) {
Random generator = new Random();
int x = generator.nextInt(100)+100;
int y = generator.nextInt(100)+100;
if (e.getActionCommand()==("Draw RandomCircle")) {
System.out.printf("x = %d y = %d\n", x, y);
status.setText(String.format("rnd draw x:%d y:%d ", x, y));
DrawShape circle = new DrawShape("Circle");
addShape(circle);
int count = shapes.size();
System.out.printf("objects in array: %d\n", count);
}
else if (e.getActionCommand()==("Draw RandomRectangle")) {
System.out.printf("x = %d y = %d\n", x, y);
//status.setText(String.format("rnd draw x: y: "));
//Graphics2D gg = (Graphics2D) canvas.getGraphics();
//gg.setColor(Color.BLACK);
//gg.drawRect(x, y, generator.nextInt(x), generator.nextInt(y));
}
}
}
Painting and such happens event-driven. If a a piece of a component needs to be redrawn its paintComponent method is called.
This means you need a component that nows how to draw by for instance:
public class DrawShape {
public final String text;
public final Color color;
public final Shape shape;
public DrawShape(String text, Color color, Shape shape) {
this.text = text;
this.color = color;
this.shape = shape;
}
}
public class CanvasWithShapes extends JPanel {
private List<DrawShape> shapes = new ArrayList<>();
public void addShape(DrawShape shape) {
shapes.add(shape);
}
#Override
public void paintComponent(Graphics g) {
final Graphics2D gg = (Graphics2D) g;
// Java 8: shapes.stream().forEach((shape) -> gg.draw(shape));
for (DrawShape drawShape : shapes) {
gg.setColor(drawShape.color);
gg.draw(drawShape.shape);
Rectangle bounds = shape.getBounds();
gg.drawString(shape.text, bounds.x+ 10, bounds.y + 20);
}
}
}
And then just add shapes to be redrawn a bit later.
Shape oval = ...;
c.add(oval);
c.repaint(50L); // A bit later
More detailed
A Shape has many implementations of interest like rectangle and oval.
Graphics2D can draw and fill a Shape. So in your case it would be ideal to add such a Shape. Maybe together with color and text. So I took your DrawShape class to hold these properties.
Random generator = new Random();
int x = generator.nextInt(100)+100;
int y = generator.nextInt(100)+100;
if (e.getActionCommand().equals("Draw RandomCircle")) {
System.out.printf("x = %d y = %d\n", x, y);
status.setText(String.format("rnd draw x:%d y:%d ", x, y));
int w = generator.nextInt(100) + 10;
int h = w;
Shape circle = new Ellipse2D.Double(x, y, w, h);
addShape(new DrawShape(text, Color.BLACK, circle));
int count = shapes.size();
System.out.printf("objects in array: %d\n", count);
} else if (e.getActionCommand().equals("Draw RandomRectangle")) {
System.out.printf("x = %d y = %d\n", x, y);
generator.nextInt(y));
int w = generator.nextInt(100) + 10;
int h = generator.nextInt(100) + 10;
Shape rect = Rectangle2D.Double(x, y, w, h)
addShape(new DrawShape(text, Color.BLACK, rect));
}
Graphics2D gg = (Graphics2D) canvas.getGraphics();
Don't use the getGraphics() method to do painting. The painting is temporary. It will be lost if you resize the frame for example.
Instead you need to override the paintComponent() method of your panel.
If you want to paint multiple objects then you need to keep track of each object. Check out Custom Painting Approaches for the two common ways to do this:
keep of List of Objects to paint and then iterate through the List each time the component is repainted.
paint the Object directly to a BufferedImage and then just paint the BufferedImage.
The example paints Rectangles. Basically you need a method like the addRectangle(...) method to add a new object to paint. So every time you click your button you add the new random shape.
Presumably, your problem arises from the setText() invocation modifying the Graphics object in some unexpected way. It is rarely appropriate to use getGraphics() in your own code. Instead, paint with the Graphics that is given to you.
Your approach is anyway flawed. If you manage to draw on a GUI component only once, as you are trying to do, then whatever you have drawn will disappear when the component is next repainted. Repainting can happen for a wide variety of reasons, many of them unrelated to the program's own behavior.
What you need to do is store some kind of data that the component's paintComponent() method will rely upon to do your custom painting every time. It follows that you will need to override the paintComponent() method of the component on which you want the circles to be drawn. For example, you might create a class that records all the needed drawing details for one circle, and give RandomDrawer a List of those objects as a member variable. The action listener manipulates that list appropriately and schedules a repainting, and paintComponent() is overridden to perform the actual painting.
Hello I have an application where you click one point and then anotherand it draws a line that has a stroke of 20. I want to be able to click any part of the line and delete it.
private Shape line = new Line2D.Double(x, y, fx, fy);
public highlight(int x, int y, int fx, int fy, int page, boolean fin) {
this.x = x;
this.y = y;
this.fx = fx;
this.fy = fy;
line = new Line2D.Double(x, y, fx, fy);
this.fin = fin;
this.page = page;
}
public void tick() {
line = new Line2D.Double(x, y, fx, fy);
if (!fin) {
play.cannotdrawline = true;
fx = Comp.mx;
fy = Comp.my;
} else {
play.cannotdrawline = false;
}
if(line.intersects(Comp.mx,Comp.my,1,1) && play.candeleteline){
if(Comp.ml){
remove = true;
}
}
}
public void render(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(20, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
// g.setColor(new Color(190,240,93, 143));
if (line.intersects(Comp.mx, Comp.my,1,1) && play.candeleteline) {
g.setColor(Color.blue);
} else {
g.setColor(Color.red);
}
g.drawLine(x, y, fx, fy);
//g2d.draw(line);
}
}
This all works fine, I can delete it but I have to click one the very middle line of pixels to be able to delete it. I know how to set the stroke for drawing a line but I don't know how to set the stroke for the line shape (which is the part that checks if you can delete the line or not). How can I do this?
Thanks in advance.
I know how to set the stroke for drawing a line but I don't know how to set the stroke for the line shape (which is the part that checks if you can delete the line or not). How can I do this?
As far as I know, you can't since, similar to Color, the Stroke is a property of the Graphics2D object and not of the Shape. You can however associate a certain Stroke with certain Shape using a Map, or using a custom class if need be, for instance if you need to associate multiple properties such as Stroke and Color with Shape, just like any other Java association could be made.
Before I ask my question I apologize for any inconsistencies. I´m fairly new at this.
I´m making a game that for now looks like this (the picture is not important):
The red dots are supposed to move to the right and they do that with a timer. This works fine. The graphics does not update though so I have to drag the side of the window back and forth to see that my dots are moving. What can I do to fix this?
My paintcomponent method in my mainclass:
public void paintComponent(Graphics g){
super.paintComponent(g);
for (int x = 0; x < SomeInts.amount; x++){
for (int y = 0; y < SomeInts.amount; y++){
tile[x][y].colorBody(g, x, y);
Tower temp;
for (int i = 0; i < towers.size(); i++){
temp = towers.get(i);
temp.colorBody(g, tile[x][y].getSize());
temp.guard.colorBody(g, tile[x][y].getSize());
}
}
}
}
My red dot class. Also called Guard class:
public class Guard {
int x, y, size = 10, towerx, towery;
Timer timer;
public Guard(int towerx1, int towery1){
towerx = towerx1;
towery = towery1;
x = towerx + 1;
y = towery;
new Timer().schedule(new MyTask(), 1000, 1000);
}
public void colorBody(Graphics g, int tilesize){
g.setColor(new Color(255, 0, 0));
g.fillOval(x * tilesize + tilesize / 4, y * tilesize + tilesize / 4, size, size);
}
public class MyTask extends TimerTask {
public void run() {
x++;
}
}
}
Thank you for your time.
I'm guessing a bit here, but I think you need to call the repaint() method to see the changes you've made.