Hi I've been trying to get rid of my flickering on a JFrame app. Have searched around and seen that setDoubleBuffered(true) can be used for paintComponent of Jpanel, but not paint method of JFrame, nor applets.
Managed to diminish but not eliminate flickering by introducing the instructions this.createbufferstrategy(2) within paint method, and further reduced flickering with the instruction this.setignorerepaint(true) inside paint.
But I finally found an example of code that completely removes flickering and it works by drawing the static elements within the update function.
Tested fillRect within update in an applet and it works, but when copy pasted into a regular java application it does not work there within the jframe's update function.
Here's the code
Graphics graphics;
Image image;
public void update(Graphics g)
{
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
graphics = image.getGraphics(); }
graphics.setColor(Color.blue);
graphics.fillRect(0, 0, this.getWidth(), this.getHeight());
g.drawImage(image, 0, 0, this);//}
With an empty paint function this draws to the screen and fills it with blue in an applet, it also gets rid of flickering. But in a normal application of jframe it does nothing.
What needs to be done to allow either fillRect or drawImage to work from within update in a non applet regular application environment?
BTW, I'm a bit new to this if the graphics object is being modified itself by calling fillRect, how does that modify the image object? Because drawImage is necessary for the screen to turn blue.
PS I've tried not using both createbufferedstrategy and setignorerepaint, and nothing changes.
When using setIgnorePaint(true), its not allowing you to mess with the Graphics.
I'm guessing by the looks of your update(Graphics g) parameter, you call that within your paint method, using the paintMethod's graphic g to paint (inside paint method, you call update(g))
If you ignore paint, its not gonna allow you to use the paintComponent's Graphic parameter.
Post all code that includes graphics (Where you made your strategy, where you're calling this method, ect..)
The flickering is a pretty mainstream issue with the strategy, and I can't promise that I'll be able to fix it (my friend brought the problem up to me a while ago, but i didnt care enough to try and figure it out), but that should at least explain why your graphics aren't rendering
Related
I need to draw strings on a painted image. The project I am working on also requires the string to move around the screen at least 22 times in a second. Hence, its position can be anywhere on the image. So, redrawing the image with the string on it won't be possible as I feel there are better ways of doing this and that would unnecessarily consume resources redrawing the whole image. I have also tried using panel.getGraphics and then painting on the image but then all the drawn text is all over the screen(the code is below). I was wondering if someone could guide me in the right direction on how I can draw text over a paintedImage but it also needs to reset its position when required. The code I have tried that doesn't reset its previous position is below.
Original Panel with the Image:
public class PanelForImages extends JPanel{
private BufferedImage image;
public PanelForImages(File image) throws IOException{
//this.image = image;
//URL resource = getClass().getResource("so2.jpg");
this.image = ImageIO.read(image);
}
#Override
public void paintComponent(Graphics g){
//super.paint(g);
//super.paintComponents(g);
super.paintComponent(g);
//g.drawImage(image, 3, 4, this);
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
g.drawString("HELLOOOOOOOOOOOOOOOOOOOOOOOO", 400, 400);
//repaint();
}
}
Method with which I am trying to draw the string over the image.
public void drawFixationsOnFrame(GazeData gazeData){
Graphics g = this.panelForImages.getGraphics();
g.drawString("TEsting 123", (int)gazeData.smoothedCoordinates.x, (int)gazeData.smoothedCoordinates.y);
g.dispose();
jF.revalidate();
}
I have also tried making a new panel and then adding it to the current one but it doesn't seem to work. I am not sure how I can make it so it comes on top of the panelForImages without it hiding panelForImages.
The project I am working on also requires the string to move around the screen at least 22 times in a second. Hence, its position can be anywhere on the image. So, redrawing the image with the string on it won't be possible as I feel there are better ways of doing this and that would unnecessarily consume resources redrawing the whole image.
Then don't redraw the whole image. The JComponent repaint(...) method has an override, one that allows you to repaint only a select rectangle (check out the JComponent API for more on this). You will want to move the image in a Swing Timer, then repaint its old location (to get rid of the old String image) and repaint its new location. If you need the dimensions of the String, then use FontMetrics to help you get its bounding rectangle.
I note that your code has two other issues that are worrisome, some of it commented out:
Calling getGraphics() on a component to get its graphics component and draw with it -- you don't want to do this as this will result in a Graphics object that is short-lived risking broken images or a NPE
Calling repaint() from within the paintComponent. This is a bad and completely uncontrolled way of doing animation. Instead use a Swing Timer so you can have complete control of the animation and so you don't use paintComponent for something it was not intended to be used for.
I am developing a graphic project in java using swing and awt libraries. I am looking for a method that allow me to draw very fast on my JPanel. I tried various methods: overriding paintComponent, calling repaint(x, y, width, heigth).. But in all cases i have to repaint ALL the screen! I have a background and a small image in front of it that changes every few time. i am looking for a method that allow me to paint on the screen only the small image, i don't need to repaint the background too, because it is always the same, and the small image is always at the same coords. for example in C++ i painted the background and then i only painted the small images in front of it using putimage (graphics.h), so that it was very very fast. Do someone have some tips?
I've had some experience with game programming and usually a JPanel is used as canvas. Now to paint on it you would write a simple loop which continuously buffers an image and later paints it to the screen. So on initialisation you create a Graphics or Graphics2D object which is passed to a buffer() method. After painting a BufferedImage with the Instance of Graphics, some paint() method paints the BufferedImage to the screen.
When only painting the background once, previously drawn images will still be visible. If all your images are the same size, you don't have to bother but I still recommend repainting your background as well.
Have a look at the book Killer Game Programming In Java for further information, it's a great reference.
Tips:
Paint static images to a BufferedImage and then draw that within the paintComponent using Graphics#drawImage(...)
You do know that the repaint(...) method is overloaded and that one overload can accept a Rectangle parameter, limiting the area of repainting.
I was working on creating a fade-in animation and I ran into a problem where whenever I try to draw a BufferedImage with:
g2d.drawImage(unknown.getScaledInstance(100, 200, BufferedImage.SCALE_SMOOTH),
10,button.getLocation().y - 200, this);
after using
.setCompositeAlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity)
My JPanel's paint method was constantly being repeatedly and continuously being called. I tried commenting out the drawImage bit and everything worked fine again. I also noticed that when I called the paint method from another class using:
answerPanel.paint(answerPanel.getGraphics());
The paint method stopped being continuously called.
So could anyone shed some light on why the drawImage line is causing the paintMethod to be constantly called until I call it from another class? Thanks!
Agree with #user2864740, you should never call paint(...) directly, but I don't think that is the root of the problem here.
The last parameter to drawImage(...) (e.g. this) is an ImageObserver. It receives callbacks whenever an Image is updated (changed), and will cause a repaint() (which will eventually call paint()).
When you invoke Image.getScaledInstance(...) this will immediately return a new Image instance, but the actual scaling (or, resampling, really) will happen later. The image observer will handle "automagic" repaints of your component, as soon as (parts of) the scaled image is done. You component will be requested to repaint one or more times.
You should be able to observe the effects of this, by passing null as the last parameter, instead of this (probably, nothing will be painted, but you'll avoid the repaint loop).
The reason your component will go into a repaint loop, is because each time the component is asked to repaint itself, a new scaled instance is returned, causing a restart of the scaling and the automatic repainting by the image observer, as described above.
To fix the problem, don't use getScaledInstance() and instead, try:
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2d.drawImage(unknown, 10, button.getLocation().y - 200, 100, 200, this);
Another way, would be to make sure you create the rescaled image only once, and continue using it for each repaint:
Image scaled;
public void paint(Graphics g) {
...
if (scaled == null) {
scaled = unknown.getScaledInstacnce(100, 200);
}
...
g2d.drawImage(scaled, 10, button.getLocation().y - 200, this);
}
Following Code Draws a structure of a molecule. If I don't pass a molecule the last structure continue to show up in the JPanel. How do I reset this to a blank canvas when there is no molecule. In other words what should I put inside else{} of drawMolecule() method?
You could create a new BufferedImage in the else or you could get the BufferedImage's Graphics2D component, set its background color via setBackground(Color c) and then clear the image via clearRect(...) then dispose of the Graphics2D object when done via its dispose() method.
In fact, on review of your code I don't see you doing this. Don't forget to dispose of the Graphics or Graphics2D resource when done using them, if you've created them yourself (not if obtained from the JVM say via its paint or paintComponent method).
I found a rendering bug in some code and have found a workaround, but I would like to know why I am getting different behaviour. In the old code, the background would (sometimes) be rendered as white, despite while debugging getBackground() would return the correct colour.
Old code:
#Override
public void paint(Graphics g) {
// Stuff
g.setColor(getBackground());
g.clearRect(0, 0, width, height); // Obviously wrong.
// More stuff
}
New code:
#Override
public void paint(Graphics g) {
// Stuff
g.setColor(getBackground());
g.drawRect(0, 0, width, height); // Correct usage with 'setColor' call.
// More stuff
}
As I put in the code, it is obvious that setColor(getBackground()) has no effect on the clearRect(...) call. Yet I would assume that calling clearRect(...) and calling setColor(getBackground()) followed by drawRect(...) would be semantically the same.
I have also considered the opaqueness property, but the parent lightweight components and ancestor heavyweight component all use the same background colour, and it is quite obvious that this component is the one with the incorrect behaviour (it is one of 8 of the same type of component owned by its parent - yet only the ones that get to this section of code have a problem).
I am using JDK 1.6.0_07 (for business reasons of course) if that helps.
Here's the information from the JavaDocs -
Clears the specified rectangle by filling it with the background color of the current drawing surface. This operation does not use the current paint mode.
Beginning with Java 1.1, the background color of offscreen images may be system dependent. Applications should use setColor followed by fillRect to ensure that an offscreen image is cleared to a specific color.
As this implies, clearRect is system dependent and the value of getBackground() is not taken into account.
The difference is this :
if you use the graphics method fillRect() you can't erase the color by using drawRect() over the same recatngle specified in pixels.
but if you use the graphics method fillRect() then clear it with clearRect() and after that drawRect(); you reach a satisfaction and a conclusion.