My drawString won't work - java

Im somewhat new in java, been programming for about a year now and im currently working on a project that lets the user choose a map (worldmap for example) and add cities to that map by clicking the map.
When the user clicks on the map he/she inputs a name and the city is drawn on those coordinates, and that work's fine. My problem is that I also want the name of the city to be drawn above the city, but I can't get it to work for some reason.
It should be an easy task, but been trying for several hours now and it's starting to get very annoying so I hope someone else can help me with this simple enquiry.
The code:
public class Rita extends JComponent{
private boolean klickad=false;
protected int xx=0;
private int yy=0;
public Rita(int x, int y){
xx=x;
yy=y;
setBounds(x, y, 20, 20);
setPreferredSize(new Dimension(20,20));
setMaximumSize(new Dimension(20,20));
setMinimumSize(new Dimension(20,20));
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
drawString(g, xx+5, yy);
if(klickad==false)
klickadVal(g, xx, yy);
else if(klickad==true)
oKlickadVal(g);
}
public void drawString(Graphics g, int x, int y){
setFont(new Font("Courier New", Font.PLAIN, 16));
g.setColor(Color.BLACK);
g.drawString("Test test test test test", x, y);
}
public void klickadVal(Graphics g, int x, int y){
g.setColor(Color.RED);
g.fillRect(0,0,getWidth(),getHeight());
}
public void oKlickadVal(Graphics g){
g.setColor(Color.BLUE);
g.fillRect(0, 0, getWidth(),getHeight());
Thanks in advance
/Jimmy

It's because of your drawing coordinates should be define relative to the component.
You are setting the bounds of the component to x,y,w,h and drawing your text to the same x and y.
If x > w or y > h, then it won't be visible.
Change your code to this, using relative coordinates for the drawing commands:
protected void paintComponent(Graphics g){
super.paintComponent(g);
drawString(g, 5, 10);
if(klickad==false)
klickadVal(g, 0, 0);
else if(klickad==true)
oKlickadVal(g);
}
And be aware of that your drawing area is only 20px*20px, because of your bounds width and height.

You are calling klickadVal or oKlickadVal after you've painted the string. These two methods fill the entire component with a single color overwriting the string you've displayed.

Related

PaintComponent disrupting grid drawing

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.

Java paint not painting on top of previously called methods

I have been unable to find an answer to this issue, so hopefully someone can help me out.
I am doing a class assignment where I have to make a scene using graphics. We've only had two lectures covering graphics so far, so I am hardly familiar. The issue is that she methods are not being painted in the preferred order. As you can see in the code to follow, I have two recursive methods making a sky and grass background/foreground. On top of those, I wish to have a cross (as well as many components thereafter granted I can get past this problem), but the cross does not appear as it should despite having that being the last method called within paint.
import java.awt.*;
import javax.swing.*;
public class DrawPicture extends JApplet
{
public final int SIZE = 800;
public final int DIST = 20;
public Color bg1 = new Color(0, 200, 255);
public Color bg2 = new Color(0, 175, 255);
public Color grass1 = new Color(0, 220, 60);
public Color grass2 = new Color(30, 255, 150);
public Color brown = new Color(110, 80, 20);
public void backgroundRec(int x, int y, int c, Graphics g)
{
if (c%2==0)
g.setColor(bg1);
else if (c%2==1)
g.setColor(bg2);
if (c < 40)
{
g.fillOval(x, y, SIZE, SIZE);
backgroundRec(x, y - DIST, c+1, g);
}
}
public void foregroundRec(int x, int y, int c, Graphics g)
{
if (c%2==0)
g.setColor(grass1);
else if (c%2==1)
g.setColor(grass2);
if (x < SIZE/2)
{
g.fillRect(x, y, SIZE, DIST);
foregroundRec(x, y + DIST, c+1, g);
}
}
public void cross(int x, int y, Graphics g)
{
g.setColor(brown);
g.fillRect(SIZE/2, SIZE/2, 45, 275);
g.fillRect(SIZE/2-50, SIZE/2+45, 150, 45);
}
public void paint(Graphics g)
{
//backgroundRec(0, 0, 0, g);
//foregroundRec(0, 400, 0, g);
cross(SIZE/2, SIZE/2, g);
}
}
One of the problems is, you have a StackOverflowException in foregroundRec, because nothing is seems to be stopping it from updating, probably because you're not changing the value of x.
I "think" foregroundRec(x, y + DIST, c + 1, g); should be foregroundRec(x + DIST, y + DIST, c + 1, g); or something :P - but based on your code, x has to change
You should also be calling super.paint before you do any of your own painting, this ensures that you don't end up with any weird paint artifacts
The other problem you're having is the fact that you're relying on the SIZE property, instead, you should be using getWidth or getHeight to determine what the actual size of the applet is
I'd also suggest having a look at:
Java Plugin support deprecated and Moving to a Plugin-Free Web
Painting in AWT and Swing
Performing Custom Painting
2D Graphics
Updated
Okay, after going through a few iterations, what I actually think you're trying to do is...
if (y < SIZE) {
g.fillRect(x, y, SIZE, DIST);
foregroundRec(x, y + DIST, c + 1, g);
}

understanding difficulties java swing

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.

Java - paintComponent with nested loops

I am currently trying to paint a grid with rectangles, but having some issues.
I am using an enum class for different type of SquareTypes:
public enum SquareType
{
EMPTY, OUTSIDE, I, O, T, S, Z, J, L
}
These SquareTypes are saved in arrays containing arrays in a Board class. Then, paintComponent -- which is supposed to draw my grid -- reaches in and get these object by using:
public SquareType getCell(int width, int height) {
return squares[width][height];
However, now when we get to paintComponent:
public void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D g2d = (Graphics2D) g;
EnumMap<SquareType, Color> dictionary = new EnumMap<SquareType, Color>(SquareType.class);
dictionary.put(SquareType.EMPTY, Color.BLACK);
dictionary.put(SquareType.I, Color.LIGHT_GRAY);
dictionary.put(SquareType.J, Color.ORANGE);
dictionary.put(SquareType.L, Color.BLUE);
dictionary.put(SquareType.O, Color.YELLOW);
dictionary.put(SquareType.OUTSIDE, Color.BLUE);
dictionary.put(SquareType.S, Color.GREEN);
dictionary.put(SquareType.T, Color.CYAN);
dictionary.put(SquareType.Z, Color.RED);
for (int i = 0; i < game.getHeight(); i++) {
for (int j = 0; j < game.getWidth(); j++) {
g2d.setColor(dictionary.get(game.getCell(j,i)));
g2d.drawRect(0, 0, 52 * j, 52 * i);
}
}
}
}
The issue is that paintComponent paints every square Blue, but if I use my getCell()-method and check what is inside the actual cells I can clearly see that there are different SquareTypes.
Might also add that the first rectangle which the the program draws is supposed to always be blue. So it seems to me as if it starts painting with blue and then sticks to it all the way? Why is that?
I am really new to the programming language and would love any help.
The line
g2d.drawRect(0, 0, 52 * j, 52 * i);
is clearly wrong. The method is described as follows:
drawRect(int x, int y, int width, int height)
So your line draws a rectangle above all prior drawn rectangles. Thats why your final result is a big blue rectangle.
I think it should be something like this:
g2d.drawRect(j * 52, i * 52, 52, 52);

How can I draw a rectangle towards the top of the application in java

How can I draw a rectangle towards the top of the application in java ? Normally the drawRect method draws towards the bottom I tried to use a negative number but this would not work
Graphics g = p.getGraphics();
g.fillRect(50, 200,50,100);
In rectangles, the X and Y coordinates represent the top left corner. The length and width then draw away from the defining point. Your example draws a rectangle with the top left corner at 50,200 and with a width of 50 and a hight of 100, both away from those points in a positive direction. If you wanted a rectangle with 50,200 representing the lower left corner, simply subtract the height from that y coordinate (200), and use that as the starting y:
Graphics g = p.getGraphics();
g.fillRect(50, 100, 50, 100);
To address your examples, try something like this (I'll just use rectangle objects rather than
actually filling the graphics):
int baseline = 200;
Rectangle rect1 = new Rectangle(50, baseline - 100, 50, 100);
Rectangle rect2 = new Rectangle(150, baseline - 50, 50, 50);
Rectangle rect3 = new Rectangle(250, baseline - 80, 50, 80);
After filling rectangles with these dimensions on the graphics object, you'll have three
rectangles with a width of 50 each, spaced 50 apart, with the bottom all on the y=200 line.
Java's Graphics class assumes that the origin (0, 0) is the top-left corner of the frame, that is, that (1, 1) is down and to the right of (0, 0). This is contrary to mathematics, in which the origin in a standard Cartesian plane is the lower-left corner, and (1, 1) is above and to the right of (0, 0).
Also, Java doesn't allow you to use negative values for widths and heights. This results in special logic that typically treats the rectangle differently than a normal, positive-dimension rectangle.
To get what you want, first reverse your thinking about the y-coordinate in Java's Graphics coordinate system. Positive y is down, not up (though positive x is still right, like standard Cartesian plots).
That being said, the fields for drawRect and fillRect are:
The x-coordinate of the top-left corner of the rectangle
The y-coordinate of the top-left corner of the rectangle
The positive width of the rectangle
The positive height of the rectangle
Zoe's answer shows a good example of how to get what you want, I just thought you might like a more thorough explanation of why "the drawRect method draws towards the bottom."
Run it..
Drag and drop the mouse in any direction on the applet window..and see what's happening...
Hope you will get some idea from it....
//Simulation of the desktop screen
package raj_java;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
public class DesktopDemo extends Applet implements MouseListener, MouseMotionListener {
int x1, y1, x2, y2;
Image img;
public void init() {
setSize(1200, 700);
setVisible(true);
img = getImage(getCodeBase(), "Nature.jpg");
addMouseListener(this);
addMouseMotionListener(this);
}
public void mouseEntered(MouseEvent me) {
//blank
}
public void mouseExited(MouseEvent me) {
//blank
}
public void mouseClicked(MouseEvent me) {
//blank
}
public void mouseReleased(MouseEvent me) {
Graphics g = getGraphics();
g.drawImage(img, 0, 0, 1200, 700, this);
}
public void mouseMoved(MouseEvent me) {
//blank
}
public void mousePressed(MouseEvent me) {
x1 = me.getX();
y1 = me.getY();
}
public void mouseDragged(MouseEvent me) {
x2 = me.getX();
y2 = me.getY();
repaint();
}
public void paint(Graphics g) {
g.drawImage(img, 0, 0, 1200, 700, this);
g.setColor(new Color(10, 99, 126));
g.drawLine(x1, y1, x2, y1);
g.drawLine(x2, y1, x2, y2);
g.drawLine(x2, y2, x1, y2);
g.drawLine(x1, y2, x1, y1);
g.setColor(new Color(193, 214, 220, 70));
int width = Math.abs(x2 - x1);
int height = Math.abs(y2 - y1);
if(x2 < x1) {
g.fillRect(x2, y1, width, height);
}else if(y2 < y1) {
g.fillRect(x1, y2, width, height);
}else {
g.fillRect(x1, y1, width, height);
}
}
}

Categories