Issue with drawRect/fillRect from Swing Library (Images included) - java

Just started messing around with Swing for a class project GUI in Java. I'm trying to draw a game board, however, not a conventional one. I'm trying to draw one more like a parchessi board, so each board tile needs to have a specific location rather than a grid.
So far, I've run into this issue. In paint(), I'm trying to paint 5 rectangles, odd ones blue and empty, even ones red and filled in. However, instead of a nice checkered pattern, I get this:
Can anyone help me figure out why it's doing this?
Code:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Rectangles extends JPanel {
public static void main(String[] a) {
JFrame f = new JFrame();
f.setSize(800, 800);
f.add(new Rectangles());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
public void paint(Graphics g) {
int x = 15;
int y = 15;
int w = 15;
int h = 15;
for(int i = 0; i < 5; i++){
if(i%2==0){
g.setColor(Color.RED);
g.fillRect (x, y, x+w, y+h);
}
else{
g.setColor(Color.BLUE);
g.drawRect (x, y, x+w, y+h);
}
x+=15;
System.out.println(Integer.toString(x) + ' ' + Integer.toString(y) + '|' + Integer.toString(w) + ' ' + Integer.toString(h));
}
}
}
Output from the Println statement(x,y,width,height):
30 15|15 15
45 15|15 15
60 15|15 15
75 15|15 15
90 15|15 15
It looked like there was overlap in the first image, so I modified the code and tried this:
for(int i = 0; i < 5; i++){
g.setColor(Color.BLUE);
g.drawRect (x, y, x+w, y+h);
x+=15;
}
Here's what happens with this code:
Why is there overlap? What causes this?
Also, does anyone know a good way to make an easily modifiable array of Rectangles? Or any good advice or tools for drawing that type of board?

Welcome to the reasons you should not break the paint chain...
Start by calling super.paint(g) as the first line of your paint method, before you do any custom painting.
A better solution would be to override paintComponent instead of paint, but still making sure you call super.paintComponent before you perform any custom painting...
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
Next, start reading the JavaDocs on Graphics#fillRect, you will see that the last two parameters represent the width and height, not the x/y position of the bottom corner
public class Rectangles extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 15;
int y = 15;
int w = 15;
int h = 15;
for (int i = 0; i < 5; i++) {
if (i % 2 == 0) {
g.setColor(Color.RED);
g.fillRect(x, y, w, h);
} else {
g.setColor(Color.BLUE);
g.drawRect(x, y, w, h);
}
x += 15;
System.out.println(Integer.toString(x) + ' ' + Integer.toString(y) + '|' + Integer.toString(w) + ' ' + Integer.toString(h));
}
}
}

Related

Java Code not working. Using loops to draw stripes on the US Flag

I am attempting to draw the US flag using java. I have pretty much done all this coding using lots of variables. It should be at least displaying the stripes, blue box, and the stars(ovals in this case). However, when I run the code through the compiler, and run it, all it displayes is a white background with a red stripe on the top. Could I please receive some help to see where my error is? I have tried everything.
Here is the code:
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Color;
public class UsFlag extends JPanel {
int w = getWidth();
int h = getHeight();
int numberStripes = 13;
int numStarCol = 8;
int numStarRow = 6;
int stripeHeight = h/numberStripes;
int boxWidth = (int)(w*0.4);
int boxHeight = 7 * stripeHeight;
int starWidth = boxWidth/numStarCol;
int starHeight = boxHeight/numStarRow;
/*public UsFlag() {
//ask user to enter number of stripes, star columns, and star rows
}*/
#Override
public void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
//Background
g.setColor(Color.RED);
g.fillRect(0, 0, w, h);
//Stripes
g.setColor(Color.WHITE);
for (int i = 0; i < numberStripes; i += 1) {
g.fillRect(0,stripeHeight, w, stripeHeight);
stripeHeight = stripeHeight + 45;
}
//Blue Rect
g.setColor(Color.BLUE);
g.fillRect(0, 0, boxWidth, boxHeight);
//stars
int y = 0;
int x = 0;
for (int j = 0; j < numStarRow; j++){
for (int i = 0; i < numStarCol; i++){
g.setColor(Color.WHITE);
g.fillOval(5, 5, starWidth, starHeight);
x += starWidth;
}
y += starHeight;
x = 0;
}
}
public static void main(String[] args) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(400, 400);
window.setContentPane(new UsFlag());
window.setVisible(true);
}
}
The first two parameters for the fillRect() method and the fillOval() method are considered coordinates (x & y) for the object you want to paint. This means that for x you need to place a integer pixel value as to where you want the Left edge of the object is to Start being painting from along the horizontal plain, and for y you need to place a integer pixel value as to where you want the Top edge of the object is to Start being painting from along the vertical plain. For fillRect() for example:
g.fillRect(20, 20, 100, 30);
The other two parameters are for the Width (w) and Height (h) in pixels of the object to paint. Use the the variable i from your for loop (y = i + 30; for example) to draw objects below one another. Read this for more information.

Mouse Listener on Rectangle

I'm trying to draw a game map using many rectangular shapes(just like a screen contains many pixels). I'm using graphics 2D and fillRect(int x, int y, width, height) method. I make the rectangular so small with 10 widths and 10 height.
How can I detect if someone clicks a rectangle? I have read other questions but I am still confused by how the mouse listener detects my small rectangle?
Can someone give me any other solution instead of making pixels with a rectangular shape? maybe like buttons or something?
Here is my example code of making multiple rectangle :
public void paint (Graphics g){
Graphics2D g2D = (Graphics2D) g;
for (int j = 0; j<Map.WIDTH; j++){
if(j==100){
if(map[i][j]=='#'){
x=50;
y+=10;
g2D.setColor(Color.BLACK);
g2D.fillRect(x, y, 10, 10);
x+=10;
y+=0;
}
note: just ignore the iteration because i'm iterate from some input file(a template)
Is it a class that extends JPanel ?
Generally you have to set your listener on your JPanel or whatever:
void setListener(MouseListener listener) {
myPanel.addMouseListener(listener);
}
then in your listenerClass you do something like that :
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
class ControlButton extends MouseAdapter {
private MyViewClass view;
ControlButton(MyViewClass view) {
this.view = view;
view.setListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
//if my x and y point represent the upper left corner
int rectX = view.getMyRectX();
int rectY = view.getMyRectY();
int rectWidth = view.getRectWidth();
int rectHeight = view.getRectHeight();
if (e.getX() > rectX && e.getX() < rectX + rectWidth
&& e.getY() > rectY && e.getY() < rectY + rectHeight) {
System.out.println("YES");
}
}
}
Of course, I suppose you are working with Swing. If it is not what you want, please be more precise in your explanation ;)

Drawing tic-tac-toe boards

I'm making an Ultimate Tic-Tac-Toe game. If you aren't familiar with the rules, that's fine. But the board layout is just a 3x3 of Tic-Tac-Toe boards. I need an algorithm, for lack of a better term, to make it so I can make x and y wherever I want and it will draw it there correctly.
int width = 67; // Note: I've determined this variable means a lot to this "algorithm" because changing it changed the lines dramatically.
g.drawRect(0, 0, x, y); // Changing this made the boxes go to the center, so this works
g.drawLine(width, 0, width, y);
g.drawLine(width*2, 0, width*2, y);
g.drawLine(0, width, x, width);
g.drawLine(0, width*2, x, width*2);
The Class Constructor calls for the x and y to be input, so those are varying.
Specifically, I want this to work no matter what I make the x and y coordinates be.
The last 4 lines in the code make the 4 intersection bars (shaped like a very large #).
Making 1: This works fine.
Making 2: The Horizontal(--) lines work, not the Vertical(|).
Making 3: Third box doesn't even show up.
Also note that these above 3 tests are just 1 row of Tic-Tac-Toe boards.
I also understand that width can not be a single value (like it is now) but changing it makes the lines go far from where they're supposed to be so I don't know what to change it to.
Please refer to the Java Platform documentation for the Graphics class. Specifically the documentation for the drawLine() method, and also the drawRect() method (although you don't strictly need drawRect() to accomplish the task).
Based on your description, it sounds like you want to reuse the four drawLine() statements from your code sample to create each of the nine small grids as well as the one big grid.
Assuming your calling code looks something like this:
int totalWidth = 200;
// draw big grid
drawGrid(g, 0, 0, totalWidth);
// draw small grids
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
drawGrid(g, totalWidth / 3 * i, totalWidth / 3 * j, totalWidth / 3);
}
}
Here's what I would do:
private void drawGrid(Graphics g, int x, int y, int width) {
// draw box around grid (not necessary)
//g.drawRect(x, y, width, width);
// draw vertical grid lines
g.drawLine(width / 3 + x, y, width / 3 + x, y + width);
g.drawLine(width / 3 * 2 + x, y, width / 3 * 2 + x, y + width);
// draw horizontal grid lines
g.drawLine(x, width / 3 + y, x + width, width / 3 + y);
g.drawLine(x, width / 3 * 2 + y, x + width, width / 3 * 2 + y);
}
Note this doesn't put any padding around the small grids, so it looks like one huge grid. I imagine you'll want to add some padding to make it look right. You'd do that from the calling code where it loops to create the small grids.
Um. Besides the fact that it appears your asking us to do the work for you...
I would suggest not even using the Java Graphics to draw the shape of an x and to draw the shape of an o (it'll make your program all dirty, but you know.. whatever this is a tutorial). Rather, I would a series of panels JTextAreas. Give them a giant font, and make their 'isFocusable()' boolean to false. Then, I would add mouse listeners to each of them, so whenever the mouse clicks the JTextArea, it runs a method. I will write a method for you here, it's very simple. It will take one parameter, a JTextArea. This will be the area that was clicked, which can be easily be found out, because you'll be calling this method inside the mouseListener's mousePressed() method. Bare in mind, this will require a mouseListener for all 9 of your JTextAreas. This method also assumes you have created two booleans, one for the first player and one for the second. If it is Player1's turn, this method will find out, then change the turn to Player2's and vise versa. ****NOTE**** make sure you set the value of Player1 to true when you create it, or at least before this method is called.
public void makingMove(JTextArea jta) {
if (player1) {
jta.setText("x");
player1 = false;
player2 = true;
}
if (player2) {
jta.setText("o");
player1 = true;
player2 = false;
}
}
Hmm will this work? NO! what if you click a JTextArea that already has a letter in it? it'll replace it! We can't have that! so, now we need to change up our makingMove method, so we know we don't break any rules:
public void makingMove(JTextArea jta) {
if (jta.getText() == null) {
if (player1) {
jta.setText("x");
player1 = false;
player2 = true;
}
if (player2) {
jta.setText("o");
player1 = true;
player2 = false;
}
}
else {
JOptionPane.showMessageDialog(null, "You can't move there, someone already has!");
}
}
Done right? WRONG! Now we need to create a method that will check to see if anyone has won yet!
We will call this after our else statement in our makingMove() method. Like so:
.....
}
else {
JOptionPane.showMessageDialog(null, "You can't move there, someone already has!");
}
checkWinnerX(1, 2, 3, 4, 5, 6, 7, 8, 9);
checkWinnerY(1, 2, 3, 4, 5, 6, 7, 8, 9);
}
The checkWinnerX method will have to take 9 parameters, same with our checkWinnerO method. Each input object will be a JTextArea, so we can compare their input. This method assumes, your JTextAreas are named 1-9, counting like it would be a phone's dialpad. In addition, we have our checkWinnerX and checkWinnerO methods calling a method to clear everything, and reset the game, which you can assign to a button if you'd like, but I would definitely recommend having one.
*****NOTE******
I will not write the checkWinnerO method because it is the same as the checkWinnerX, but with all o's instead. and I'm sure you get the idea. AND this is an EXTREMELY inefficient way of handling this, but oh well.
public static void checkWinnerX(JTextArea 1, JTextArea 2, etc.. up to 9) {
if (1.equals("x") && 2.equals("x") && 3.equals("x")) {
JOptionPane.showMessageDialogue(null, "The winner is X!");
clear();
}
if (4.equals("x") && 5.equals("x") && 6.equals("x")) {
JOptionPane.showMessageDialogue(null, "The winner is X!");
clear();
}
if (7.equals("x") && 8.equals("x") && 9.equals("x")) {
JOptionPane.showMessageDialogue(null, "The winner is X!");
clear();
}
if (1.equals("x") && 2.equals("x") && 3.equals("x")) {
JOptionPane.showMessageDialogue(null, "The winner is X!");
clear();
}
if (1.equals("x") && 5.equals("x") && 9.equals("x")) {
JOptionPane.showMessageDialogue(null, "The winner is X!");
clear();
}
if (7.equals("x") && 5.equals("x") && 3.equals("x")) {
JOptionPane.showMessageDialogue(null, "The winner is X!");
clear();
}
if (1.equals("x") && 4.equals("x") && 7.equals("x")) {
JOptionPane.showMessageDialogue(null, "The winner is X!");
clear();
}
if (2.equals("x") && 5.equals("x") && 8.equals("x")) {
JOptionPane.showMessageDialogue(null, "The winner is X!");
clear();
}
if (3.equals("x") && 6.equals("x") && 9.equals("x")) {
JOptionPane.showMessageDialogue(null, "The winner is X!");
clear();
}
}
public static void clear() {
1.setText(null);
2.setText(null);
3.setText(null);
4.setText(null);
5.setText(null);
6.setText(null);
7.setText(null);
8.setText(null);
9.setText(null);
}
Now if you've got your mouseListeners set up correctly, and you use GridBagConstraints to correctly format your playing board. You pretty much have it done.
I could make this a thousand ways, using a thousand different methods and objects and blah, I chose this way because you specified you wanted an 'algorithm' for it. Now, you should be able to refer to this VERY broken down tutorial of a not-so-great way of making this game, and write your own code for it.
Hope this helps.
If I understand you correctly, you want a 3 x 3 grid of tic tac toe boards.
Here's a quick Swing application that draws a 3 x 3 grid of tic tac toe boards. 9 tic tac toe boards on 9 panels.
And here's the code. The drawing code is in the DrawingPanel class.
package com.ggl.testing;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TicTacToe implements Runnable {
private JFrame frame;
private List<DrawingPanel> drawingPanels;
public TicTacToe() {
this.drawingPanels = new ArrayList<>();
}
#Override
public void run() {
frame = new JFrame();
frame.setTitle("Ultimate Tic Tac Toe");
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent event) {
exitProcedure();
}
});
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new GridLayout(3, 3, 10, 10));
for (int i = 0; i < 9; i++) {
DrawingPanel drawingPanel = new DrawingPanel();
mainPanel.add(drawingPanel);
drawingPanels.add(drawingPanel);
}
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void exitProcedure() {
frame.dispose();
System.exit(0);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new TicTacToe());
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = -3774580797998095321L;
public DrawingPanel() {
this.setPreferredSize(new Dimension(170, 170));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(5.0F));
Rectangle r = new Rectangle(0, 0, getWidth(), getHeight());
int sectionWidth = r.width / 3;
int sectionHeight = r.height / 3;
g2d.setColor(Color.BLACK);
g2d.drawLine(r.x, r.y + sectionHeight,
r.x + r.width, r.y + sectionHeight);
g2d.drawLine(r.x, r.y + sectionHeight + sectionHeight,
r.x + r.width, r.y + sectionHeight + sectionHeight);
g2d.drawLine(r.x + sectionWidth, r.y, r.x + sectionWidth,
r.y + r.height);
g2d.drawLine(r.x + sectionWidth + sectionWidth, r.y,
r.x + sectionWidth + sectionWidth, r.y + r.height);
}
}
}

Checkerboard center and resizing in java

I wrote a checkerboard program (shown below). My problem is that I can't figure out how to center it with resize, and have it resize proportionately.
I added in a short statement. Int resize (shown below) I did something similiar with a previous program regarding a bullseye where I used a radius. I just haven't the slightest clue how to implement that in here.
import java.awt.*;
import javax.swing.JComponent;
public class CheckerboardComponent extends JComponent {
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
int s = 12;
int x = s;
int y = s;
// int resize = Math.min(this.getHeight(), this.getWidth()) / 8 ;
for (int i = 0; i < 8; i++) {
// one row
for (int j = 0; j < 8; j++) {
g2.fill(new Rectangle(x, y, 4 * s, 4 * s) );
x += 4 * s;
if(g2.getColor().equals(Color.RED)){
g2.setColor(Color.BLACK);
}else{
g2.setColor(Color.RED);
}
}
x = s;
y += 4 * s;
if(g2.getColor().equals(Color.RED)){
g2.setColor(Color.BLACK);
}else{
g2.setColor(Color.RED);
}
}
}
}
here is a viewer program
import javax.swing.*;
public class CheckersViewer {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(430, 450);
frame.setTitle("Checkerboard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CheckerboardComponent component = new CheckerboardComponent();
frame.add(component);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Hmm... Here's one idea then, though it probably isn't a good one (I'm also not that good with jComponent and jFrame, so there's probably a better way and a more suited person)
I believe the component object has a built-in method called getSize(). If you can relate the size of the rectangle to the size of the window, then it could be resizable. Obviously there would be more code and arguments, but for example:
public void drawStuff(Component c)
{
...
Dimension size = c.getSize();
double RectWidth = (size.width)*(.05);
...
}
check this out for more complete examples:
http://www.javadocexamples.com/java/awt/Component/getSize().html
And I apologize I can't be of more help.

Java applet displays itself multiple times

I am making a Java applet for school whose function is to randomly select six numbers for coordinates of three points and connect them to make a triangle. It is only supposed to draw one triangle and find the "length of the sides". However when I put it on my website it will redraw itself multiple times.
I made another applet, simpler, that only selects 4 random numbers for coordinates to draw a line. Same problem.
The redrawing problem seems to happen when the user moves the screen, e.g. when I scroll or when I resize the applet viewer in Eclipse. My source code is posted here.
I appreciate any help! Thanks!
import javax.swing.JApplet;
import java.awt.*;
#SuppressWarnings("serial")
public class LineApplet extends JApplet {
/**
* Create the applet.
*/
static int width;
int height;
public void init() {
width = getSize().width;
height = getSize().height;
}
public static int[] randomLine() {
int[] pointArray = new int[4];
int x;
for (int i = 0; i < 4; i++) {
x = ((int)(Math.random()*(width/10-2)))*20+10;
pointArray[i] = x;
}
return pointArray;
}
public void paint(Graphics g) {
g.setColor(Color.blue);
int[] coords = new int[4];
coords = randomLine();
g.drawLine(coords[0], coords[1], coords[2], coords[3]);
g.drawString(coords[0]/10 + ", " + coords[1]/10, coords[0], coords[1]);
g.drawString(coords[2]/10 + ", " + coords[3]/10, coords[2], coords[3]);
int midpointx = (coords[0] + coords[2])/2;
int midpointy = (coords[1] + coords[3])/2;
g.drawString(midpointx/10 + ", " + midpointy/10, midpointx, midpointy);
}
}
As pointed out by Reimues, you are re-generating your coords each time the applet is repaint.
The other problem with your paint method is actually you're not clear the previous state of the graphics context (this would have being done by paint, but you failed to respect it's functionality when you overrode it).
You have two choices.
call super.paint(g)
call super.paint(g) and call Graphics#clearRect(int, int, int, int) or Graphics#fillRect(int, int, int, int)
You should also, very rarely, need to override the paint method of top level containers. One of the reasons is that they're not double buffered, the other is the paint chain is complex and easily broken...
You're better off using a JPanel (or such) and overriding the paintComponent method instead...
UPDATED
I updated your code to demonstrate the issues.
public class TestBadApplet extends JApplet {
public void init() {
}
#Override
public void start() {
final LinePane linePane = new LinePane();
setLayout(new BorderLayout());
JButton update = new JButton("Update");
add(linePane);
add(update, BorderLayout.SOUTH);
update.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
linePane.regenerate();
}
});
}
protected class LinePane extends JPanel {
private int[] coords = new int[4];
public void regenerate() {
coords = randomLine();
repaint();
}
public int[] randomLine() {
int[] pointArray = new int[4];
int x;
for (int i = 0; i < 4; i++) {
x = ((int) (Math.random() * (Math.min(getWidth(), getHeight()) / 10 - 2))) * 20 + 10;
pointArray[i] = x;
}
return pointArray;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
g.drawLine(coords[0], coords[1], coords[2], coords[3]);
g.drawString(coords[0] / 10 + ", " + coords[1] / 10, coords[0], coords[1]);
g.drawString(coords[2] / 10 + ", " + coords[3] / 10, coords[2], coords[3]);
int midpointx = (coords[0] + coords[2]) / 2;
int midpointy = (coords[1] + coords[3]) / 2;
g.drawString(midpointx / 10 + ", " + midpointy / 10, midpointx, midpointy);
}
}
}
With super.paintComponent
Without super.paintComponent
You are calculating new co-ordinates every time paint() is called.
paint() is called every time the applet window is resized or regains focus.
To fix, you could make
int[] coords = new int[4];
a class member variable and move
coords = randomLine();
to your init() method, which will only be called once upon initialization.
Addendum:
Always call super.paint(g); when overriding paint().
For custom painting using Swing, the preferred approach is to extends a JComponent component leveraging the enhanced paint functionality offered by using paintComponent.
For more see: Performing Custom Painting.
The trouble seems to be that paint() is called every time the component needs repainting.
paint() methods should be written in a way that doesn't produce side effects and they shouldn't change the internal state of the applet. paint() must be restricted to doing just that: painting.

Categories

Resources