I have a problem with the method fillArc of the class Graphics.
When I give the int values of the size of the arc,it paint an arc with wrong dimensions.
Dimension dimensione; //dimension of the window.
public void paint() {
BufferStrategy bS = this.getBufferStrategy();
Graphics g=bS.getDrawGraphics();
g.clearRect(0, 0,(int)dimensione.getWidth(), (int)dimensione.getHeight());
// g.fillArc((int)dimensione.getWidth()/2-150,(int)dimensione.getHeight()/2-150, 300,300, 0, 360);
g.fillArc(0,0,(int)dimensione.getWidth(), (int)dimensione.getHeight(),0, 360);
bS.show();
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Disegno.class.getName()).log(Level.SEVERE, null, ex);
}
}
It should create an arc as big as the window... but this is the result:
What am I doing wrong?
Understand that the “viewable area” is the window size MINUS the frame decorations.
You shouldn’t be using the window size as a baseline, instead, override getPreferredSize (in your case of java.awt.Canvas) and return the preferred size you would like to use, you can then use Window#pack to pack the window around the content and it will become platform independent.
You can then use the getWidth and getHeight methods of Canvas to determine the actual size available
Related
Following a guide that was released in Nov, 2015. I have copied his code verbatim at this point and it still won't work for me. Has something been deprecated?
I have 3 buffers (call them 1,2, and 3). When 2 and 3 are drawn to the screen they have black lines on the top and left sides of the screen. This same code works fine with two buffers.
Bug footage: https://gfycat.com/gifs/detail/GraveCompetentArmyworm
package field;
import javax.swing.JFrame;
import java.awt.*;
import java.awt.image.BufferStrategy;
public class Main extends JFrame{
private Canvas canvas=new Canvas();
public Main() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(0,0,1000,1000);
setLocationRelativeTo(null);
add(canvas);
setVisible(true);
canvas.createBufferStrategy(3);
BufferStrategy buffert = canvas.getBufferStrategy();
int p=0;
int ap=0;
while(p<1000) {
if (ap==100){
p++;
ap=0;
}
ap++;
buffert=canvas.getBufferStrategy();
Graphics g = buffert.getDrawGraphics();
super.paint(g);
g.setColor(Color.GREEN);
g.fillOval(p+100, 200, 50, 50);
buffert.show();
}
}
// public void paint(Graphics graphics) {
// super.paint(graphics);
// graphics.setColor(Color.RED);
// graphics.fillOval(100, 100, 100, 100);
//
// }
public static void main(String[] args){
new Main();
}
}
You need to go read the JavaDocs for BufferStrategy and Full-Screen Exclusive Mode API, which a number of important tutorials and examples on BufferStrategy
A BufferStrategy is a means to perform "page flipping", which is independent of the regular painting system. This provides you with "active" control over the painting process. Each buffer is updated off screen and the pushed onto the screen when it's ready.
This generally does not involve the component's own painting system and the intention is to avoid it.
This means you should NOT be calling super.paint(g) on the JFrame or canvas.paint. In fact, as a general rule, you should NEVER call paint manually.
Each time you want to update a buffer, you will be required to "prepare" it. This typically means filling it with some base color
So, based on the example from the JavaDocs, you could do something like...
// Check the capabilities of the GraphicsConfiguration
...
// Create our component
Window w = new Window(gc);
// Show our window
w.setVisible(true);
// Create a general double-buffering strategy
w.createBufferStrategy(2);
BufferStrategy strategy = w.getBufferStrategy();
// Main loop
while (!done) {
// Prepare for rendering the next frame
// ...
// Render single frame
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
// Get a new graphics context every time through the loop
// Determine the current width and height of the
// output
int width = ...;
int height = ...l
// to make sure the strategy is validated
Graphics graphics = strategy.getDrawGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
// Render to graphics
// ...
// Dispose the graphics
graphics.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());
// Display the buffer
strategy.show();
// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}
// Dispose the window
w.setVisible(false);
w.dispose();
Now, personally, I'd prefer to use Canvas as the base, as it gives a more re-usable solution and it's easier to determine dimensions from
I have a loaded image, but when I try to display it nothing is appearing.
public class JComponentButton extends JComponent implements MouseListener {
BufferedImage image;
public static void main(String[] args) {
JFrame mainFrame = new JFrame("Test Title3");
mainFrame.setSize(400,400);
mainFrame.setLayout(new GridLayout(1,1));
mainFrame.addWindowListener(new WindowAdapter() {
#Override public void windowClosing(WindowEvent windowEvent){
System.exit(0);
}
});
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new FlowLayout());
JComponentButton button = new JComponentButton();
button.setSize(64,64);
controlPanel.add(button);
mainFrame.add(controlPanel);
mainFrame.setVisible(true);
System.out.println("finishing");
}
public JComponentButton(){
super();
try {
this.image = ImageIO.read(new File("resources/default.png"));
} catch (IOException e) {
System.out.println("did not load image");
System.exit(1);
}
enableInputMethods(true);
addMouseListener(this);
}
#Override public void paintComponent(Graphics g){
super.paintComponent(g);
System.out.println(image.getHeight() + "," + image.getWidth());
g.drawImage(image, 64, 64, null);
}
The image seems to be loaded as 64,64 is printed into the console. However where it should be appearing on the window is blank. I drew a square there without a problem using g.fillRect. So it seems like the problem has to be with g.drawImage. I also tried changing the perspective from null to this, but nothing changed.
In your code the method g.drawImage(image, 64, 64, null) will draw your image at it's full resolution starting at the offset at 64, 64.
Javadoc for drawImage:
Draws as much of the specified image as is currently available. The image is drawn with its top-left corner at (x, y) in this graphics context's coordinate space. Transparent pixels in the image do not affect whatever pixels are already there.
This means that whilst your image is indeed being drawn, it's being drawn outside the visible co-ordinate space of your button.
To fix the issue, replace the 64, 64 with 0, 0 if the image is sized at the component's size or use the more explicit method drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) to specify what the image should be resized to whilst in the button.
E.g.
g.drawImage(image, 0, 0, null); //draws image at full resolution
g.drawImage(image, 0, 0, 64, 64, null); //draws image at offset 0, for max resolution of 64x64
You can't view the image is because the image is drawn outside of the button.
since you don't have any panel outside the button,it cannot be drawn.
The reason is,the x and y axis of the image that you have specified,i.e.Top left corner,are 64,64 and the button is of size 64,64.Thus,this image will be drawn at bottom right of the button,that is the corner point of the button.
Thus you should specify image points as 0,0 (these are the top-left corner of image) so that it will cover the 0,0(these are the top-left corner of button) point of the button.
Also,you must specify the width and height of the image.So,that it will not go out side of bounds of button.If you don't want to specify the width and height then you must decrease the pixels of the image to the size of button(at least).
you can rewrite the code as:
g.drawImage(image,0,0,64,64,null);
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.
I am currently profiling my Java-2d-Application (Game-Engine for learning purposes).
Since I cannot guarantee that each frame is overwritten completely, I have to clear the background to a solid color (i.e. Color.BLACK) each frame.
The way I do it is SLOW (about 40% of drawing-time in my environment goes to just clearing the background).
First I get a graphics-context from the bufferStrategy, then I draw a [PickYourColor]-Rectangle in full resolution on it before drawing the actual content.
// fill background with solid color
graphics.setColor(Color.BLACK);
graphics.fillRect(
0,
0,
(int) bounds.getWidth(),
(int) bounds.getHeight());
Is there a more efficient, platform-independant, way to clear the background to a solid color each frame using Java-2D (this is not a LWJGL-question)?
What I'm looking for is a graphics.clearBackgroundToSolidColor(Color color) - Method...
By request: here the full rendering method (it's not an SSCCE, but it's pretty short and self explanatory)
/**
* Create a new graphics context to draw on and
* notify all RenderListeners about rendering.
*/
public void render() {
///// abort drawing if we don't have focus /////
if (!this.windowJFrame.hasFocus()) {
return;
}
///// draw and create new graphics context /////
Graphics2D graphics = null;
do {
try {
graphics = (Graphics2D) this.bufferStrategy.getDrawGraphics();
Rectangle2 bounds = this.getBounds();
// set an inexpensive, yet pretty nice looking, rendering directives
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// fill background with solid color
graphics.setColor(Color.BLACK);
graphics.fillRect(
0,
0,
(int) bounds.getWidth(),
(int) bounds.getHeight());
// notify all listeners that they can draw now
synchronized (this.renderListeners) {
for (RenderInterface r : this.renderListeners) {
r.render(graphics, bounds);
}
}
// show buffer
graphics.dispose();
this.bufferStrategy.show();
} catch (Exception e) {
Logger.saveMessage("window", Logger.WARNING, "Caught exception while drawing frame. Exception: " + e.toString());
}
} while (this.bufferStrategy.contentsLost());
}
I can't say why the fillRect is slow, but you can try creating an Image and draw it as bg. not sure if it will be faster though.
try:
BufferedImage bi = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
int[] imageData =((DataBufferInt)bi.getRaster().getDataBuffer()).getData();
Arrays.fill(imageData, 0);
then instead of fillRect draw the Image:
graphics.drawImage(bi, 0, 0, null);
Tell me how it went(I have my doubts about this).
If you would like to clear the entire background than try canvas.drawColor(color, PorterDuff.Mode.CLEAR). Should be a bit faster
I have a JPanel with a size of 816 x 1056 pixels (size of a standard typewriting paper). Is there any way of displaying the whole JPanel and its content without altering its actual size, in a small JFrame? Is there a way of like zooming it out?
I can't think of an easy method to zoom a JPanel out, but you can do it via double-buffering:
private void paintPanel (Graphics2D g)
{
// here goes the code of your paint() or paintComponent() method
}
/** Draw content into an Image, shrink it, and display it. */
protected void paintComponent (Graphics g)
{
// paint image
BufferedImage img = new BufferedImage(MAX_WIDTH, MAX_HEIGHT, BufferedImage.TYPE_INT_ARGB);
paintPanel(img.createGraphics());
// shrink image and paint it
g.drawImage(img, 0,0, WIDTH,HEIGHT, 0,0, MAX_WIDTH,MAX_HEIGHT, null);
}
This will paint everything on a BufferedImage with the size MAX_WIDTH x MAX_HEIGHT. Then, the Image will be shrinked into the size WIDTH x HEIGHT and then displayed.