how to draw a black rectangle over Image icon? - java

in my application I have a cross road picture in the background and I want to draw traffic lights on the top of it (black rectangle with 3 circles)
The problem is, I cannot see the rectangle at all, as if it was under the image or something. And if I switch the order in which the items are painted, I get all black image.
Do you have any idea how this can be solved?I am new to graphics and searched similar questions, but none helped me.
Thank you.
public MainFrame() throws HeadlessException {
super("semafor");
crossroad = new ImageIcon("cross.png");
initFrame();
initComponents();
sem1 = new Semafor(true, 100, 100);
add(sem1);
repaint();
setVisible(true);
}
//here I paint the image
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(crossroad.getImage(), 0, 45, this);
}
//and in class Semafor i paint the actual traffic lights
#Override
public void paint(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.darkGray);
//and then the circles
}

The first thing I'm noticing is that you are calling <unknown>.getWidth() and <unknown>.getHeight() for the rectangle size. If it's covering the entire image, this suggests that it is getting that width and height from the panel it is being drawn on.
A simple stack trace,
(new Exception).printStackTrace();
or
Thread.dumpStack();
will tell you as much. You could also query the width and height with a System.out call to verify that you're getting the values you're expecting, or, if this really gets out of control, learn to use JUnit and the assert statement. Honestly, though, it looks like you're just accidentally calling the wrong method.

Related

Rendering scenes into bufferedimage before painting it into screen?

I am thinking of some different ways of rendering the game into the screen.
I've currently working on a indie game and usually I just paint the textures on the screen right away:
public void paintComponent(Graphics g){
for(int i=0;i<textures.size;i++){
g.drawImage(texture.get(i).getTexture(),texture.get(i).getX(), texture.get(i).getY(), null)
}
}
But this is just an example. The problem with this is that if you have too many textures, you might start noticing some flickering or the process of drawing because when the g.drawImage is called, it paints the texture into the screen right after.
So I've though of a solution however I am not sure if it's a good way of doing it.
What I've done is instead of painting the textures into the screen, I simply draw them into the BufferedImage. After that, I simply draw the BufferedImage into the screen.
Here is an example:
public void paintComponent(Graphics g){
g.drawImage(bufferRender(), 0, 0, null);
}
public BufferedImage bufferRender(){
BufferedImage render = new BufferedImage(Main.window.getWidth(), Main.window.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = render.getGraphics();
for(int i=0;i<textures.size;i++){
g.drawImage(texture.get(i).getTexture(),texture.get(i).getX(), texture.get(i).getY(), null)
}
return render;
}
Now the question is... Is it a fine way of doing this?

Issues with drawing multiple circles (drawOval / Java)

My issues is the following: My actual project (of which the code below is a simplified version of) involves many concentric circles (each with a different colour) and animation utilising a Timer. The circles are drawn using the drawOval method.
My problem is that when these concentric circles are drawn, there appears to be loads of gaps in the outline of these circles, which I'm guessing is something to do with the fact that a circle is composed of pixels and lines as is any shape so the appearance of roundness is an illusion. I say this because when I swap the drawOval method for drawRect the painting looks as you would expect.
When messing around with other people's codes I saw that using RenderingHints somehow solved this problem however slowed down the animation beyond a point that I felt was acceptable.
Below is a screenshot of what is painted. Rather than seeing a solid opaque circle (as all of the circles drawn have the same colour in this example) we see this:
Here is my simplified code:
Test10
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Test10 extends JPanel {
Circle[] circles;
public static void main(String[] args) {
new Test10().go();
}
void go() {
JFrame frame = new JFrame("Circle Test");
frame.getContentPane().add(this);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
circles = new Circle[200];
for (int i = 0; i < 200; i++) {
circles[i] = new Circle(i, ((2 * ( 200 - i) + 1)));
}
repaint();
frame.setPreferredSize(new Dimension(500,500));
frame.pack();
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
for (Circle circle : circles ) {
circle.draw(g);
}
}
}
Circle
import java.awt.Graphics;
public class Circle {
int topLeft;
int diameter;
public Circle(int topLeft, int diameter) {
this.topLeft = topLeft;
this.diameter = diameter;
}
void draw(Graphics g) {
g.drawOval(topLeft, topLeft, diameter, diameter);
}
}
Could anyone explain to me a) Why this is happening and b) How to overcome this problem.
UPDATE
Having tried various methods including starting with the outermost circle and using fillOval instead of drawOval, and using a higher stroke value, I still find I have a problem with certain artefacts appearing similar to the screenshot Pavel posted. Here is a screenshot from my full application running the animation, if you look carefully you can see inconsistencies in the colour of mostly any given circle, resulting in these strange results. Their distribution actually follows the same pattern as the screenshot posted above so clearly something fundamental isn't being addressed by these options. Here is my screen shot:
It is impossible to draw perfect circle.
Try using the following method
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(2));
int i = 0;
for (Circle circle : circles ) {
Shape circle2 = new Ellipse2D.Double(i++, i, circle.diameter, circle.diameter);
g2d.draw(circle2);
}
}
You said you tried with RenderingHints, and it slowed your animation, but you haven't give us any code with animation, so maybe try my code (it would be good to see animation implementation). It looked better, but still not what you wanted. Setting stroke to another value will solve this (set to at least 2). Another one is to use .fill() instead of .draw(). I know that it is not perfect, but you may try it.
ANOTHER IDEA
I thought, that maybe you could add some blur to your image, so those artifacts are not visible?
I haven't done it before, but I found this (found HERE):
private class BlurGlass extends JComponent {
private JFrame f;
public BlurGlass(JFrame f) {
this.f = f;
setOpaque(false);
setFocusable(false);
}
public void paintComponent(Graphics g) {
int w = f.getWidth();
int h = f.getHeight();
setLocation(0, 0);
setSize(w, h);
g.setColor(new Color(0, 0, 0, 0.3f));
g.fillRect(0, 0, w, h);
}
}
now somwhere in go() method:
frame.setGlassPane(new BlurGlass(frame));
frame.getGlassPane().setVisible(true);
It looks a lot better for me. Play a bit with this GlassPane color (try changing .3f to some other value).
You might want to make the Stroke bigger. I've had luck with this in situations similar to yours
You can try by adding this line in your Circle class inside draw function:
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//and draw the Oval on g2
Also another solution might be to fill the circles:
Ellipse2D.Double circle = new Ellipse2D.Double(x, y, diameter, diameter);
g2.fill(circle);
That happens because a computer cannot draw a perfect circle.
A computer uses square pixels to approximate a real circle but its just not possible to achieve perfection and that results in some pixels not being shown
Drawing a filled circle will help you
a detailed explanation
Can you please try fillOval method instead of drawOval.
g.fillOval(topLeft, topLeft, diameter, diameter);
Reverse your idea. Start with the outermost circle, then draw the inner circle and so on, finishing with the smallest circle. You should use fillOval in the process.
The other rendering hint that is often useful for circles/ovals is
g.setRenderingHint( RenderingHints. KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
See my other answer with more details and example.

Transparency overlapping in Java

So I'm making a simple pause function in my game, and I want to have a grey transparent background, the problem is, the rectangle keeps overlapping and is just causing a fade out look. I've tried g2.dispose, and it works, but I can't draw anything else over that.
I have my render method, which is being called 60 times a second. (I issume the rectangle is being drawn 60 times a second)
public void render(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(new Color(0, 0, 0, 50));
g2.fillRect(0, 0, RPG.getWidth(), RPG.getHeight());
g2.drawImage(paused, 0, 0, null);
}
Thanks!
Edit: I feel like an idiot... I just had to draw my ingame screen underneath that!
If I understand correctly what you mean by "causing a fade out look" (although I'm not sure I do), you want to fill a background with a transparent color without blending the new transparent color with pixels that are already present. You can do this by setting the composite mode to "source":
g2.setComposite(AlphaComposite.Src);
You can set it back to the default "source over destination" rule to return to normal drawing afterwards by doing:
g2.setComposite(AlphaComposite.SrcOver);
Edit: Or perhaps you do want to blend the transparent color, but with the rest of the game graphics and not with itself? In that case, just make sure that you're redrawing the game background each time you draw the transparency over the top, although I'd suggest pausing the 60fps refresh during game pause if nothing on the screen is changing, just to avoid wasting CPU/battery.
Consider trying to create a copy of the Graphics context first and then disposing of it when your finished...
public void render(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(new Color(0, 0, 0, 50));
g2.fillRect(0, 0, RPG.getWidth(), RPG.getHeight());
g2.drawImage(paused, 0, 0, null);
g2.dispose();
}
This way, the changes to the Graphics state remain isolated between the create and dispose calls and don't affect anything else painted after it
Also, remember, unless you are clearing what was previously painted to the Graphics context, it will accumulate on repeated calls.

Graphics not drawing in paintComponent(Graphics)?

I'm working on a custom Swing Component for my application, and I started drawing things with the public void paintComponent(Graphics g). Everything works fine except for the fact that I can't draw any rectangles. I think the problem is with the getX() and getY() part, but I don't know that for sure. Here's my code:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (mouseEntered) {
g.setColor(HIGHLIGHTED_COLOR);
} else {
g.setColor(BACKGROUND_COLOR);
}
g.fillRect(getX(), getY(), getWidth(), getHeight());
//Draw rest of stuff (works fine)
The API says that it is supposed to be used like this: g.fillRect(x, y, width, height), and that's what I'm doing.
The rest of the drawing works perfectly, but I can't figure out why this isn't drawing. Any suggestions?
I'm not exactly sure how your Component is defined, but the default value for a Component's getX() method is the X coordinate of the Component's upper left hand corner (relative to the root Component).
When you are drawing in a Component's paintComponent(Graphics) method in Swing, the origin of the Graphics context that you are drawing to is typically located at the top-left of the Component itself, not the root Component.
So by doing this call:
g.fillRect(getX(), getY(), getWidth(), getHeight());
You are likely drawing the rectangle outside of the clip bounds of the Component!
(e.g. if the Component is located at 100, 100 and it has a width of 20 and height of 20, the rectangle you are drawing, in absolute coordinates, is at (200, 200) to (220, 220))
If you want to draw a rectangle that encompasses the entire component, you may want to try something more like this:
g.fillRect(0, 0, getWidth(), getHeight());
This will draw from the origin (again, likely the top-left hand corner of the Component) down to the width and height of the component.
(Using previous example: Component is at 100, 100, and width/height of 20, the rectangle this would draw is at (100, 100) to (120, 120))
Hope this helps =)

java - applet delete image

Sorry asking so many questions but believe me.. I tried Google first. :)
When you use the g.drawImage in paint() on an Applet... is there a way you can remove it? What I mean is remove the image that was drawn.
There's not really a direct way to clear the image, unless you are using an off screen buffer and painting that. I'm assuming you are drawing directly to the screen. To clear the image, you add a new flag to your applet, which you check in your paint() method. The flag indicates if the image should be drawn or not. E.g.
boolean shouldDrawImage = true;
void paint(Graphics g) {
if (shouldDrawImage) {
g.drawImage(...);
}
}
To clear the image, you then set the flag to false and invoke the repaint() method.
g.setColor( getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
public void removeImage(Image img, int id, width w, height h);
This function removes the image specified by name, id, height and width.

Categories

Resources