0

I have a java program that's should be doing something very simple. It contains a JPanel, on which repaint() is called 30 times each second. This JPanel overrides the paintComponent() method, and in this overwritten method, I take a BufferedImage and draw it to the JPanel.

This BufferedImage consists of a black image with a somewhat smaller blue rectangle inside of it. This displays, but the problem is that the left side, 50-80 pixels or so, of the screen flickers. On the leftmost part of what should be the blue rectangle, some of the pixels will sometimes appear black instead, as though there's some black overlay extending from the left side of the screen covering it, that flickers a bit each frame.

I wouldn't think just drawing a rectangle would be so consuming that it would cause graphical bugs with something like this; is it? I can't figure out why this would be happening, so do any of you have any idea what would cause a black "flicker" on the left of either a BufferedImage or a Graphics2D?

'Runnable example(please add the imports)':

public class Panel extends JPanel{
public int width, height;
public long lastTime;
public BufferedImage canvas;
public Panel(int a, int b){
width = a;
height = b;
canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
lastTime = System.currentTimeMillis();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.drawImage(canvas, 0, 0, this);
}
public void drawRect(int startX, int startY, int w, int h, int color){
for(int i=0; i<w; i++){
for(int j=0; j<h; j++){
canvas.setRGB(i + startX, j + startY, color);
}
}
}
public void render(){
drawRect(0, 0, width, height, 0x000000);
drawRect(10, 10, width - 20, height - 20, 0x0000ff);
}
public void update(){
int delta = (int)(System.currentTimeMillis() - lastTime);
if(delta >= 1000 / 30){
render();
lastTime = System.currentTimeMillis();
}
}

//in a different class, contains main()

public class Main{
public static Panel pan;
public static void main(String[] args){
JFrame frame = new JFrame();
Container c = frame.getContentPane();
c.setPreferredSize(500, 500);
pan = new Panel(500, 500);
frame.add(pan);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
new runThread().run();
}
class runThread extends Thread{
public void run(){
while(true){
pan.update();
}

}
}
}
user2649681
  • 750
  • 1
  • 6
  • 23
  • 3
    If this were my problem and I were seeking help here, I'd take a little time to create and post a [minimal example program](http://stackoverflow.com/help/mcve) since I'd know that this would be the best and quickest way to get folks to fully understand my problem and then help me. Please consider this; you won't regret it, trust me! – Hovercraft Full Of Eels Jan 31 '15 at 23:54
  • One way to get images for an example is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). – Andrew Thompson Feb 01 '15 at 01:06
  • 1
    `Graphics#drawImage` should use `this` as the `ImageObserver` – MadProgrammer Feb 01 '15 at 01:39
  • @MadProgrammer, that didn't help. – user2649681 Feb 01 '15 at 03:42
  • 1
    Well, until you can provide a [runnable example](https://stackoverflow.com/help/mcve) which demonstrates your problem, the only thing you will get a wild guesses (but you should supply `this` as the `ImageObserver` when drawing images to components as a general rule) – MadProgrammer Feb 01 '15 at 03:45
  • I tried asking him for that @MadProgrammer with no success. Perhaps your request will yield more fruit. – Hovercraft Full Of Eels Feb 01 '15 at 04:08
  • See [*How to Use Swing Timers*](http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html). – trashgod Feb 01 '15 at 04:42
  • @trashgod You mean to call `update()`? Would that make a difference? – user2649681 Feb 01 '15 at 04:44
  • Your program incorrectly synchronized in several ways; the result is indeterminate; see also [*Initial Threads*](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html), for [example](http://stackoverflow.com/a/3256941/230513). – trashgod Feb 01 '15 at 04:46
  • @trashgod Care to elaborate? – user2649681 Feb 01 '15 at 04:47
  • The [example cited](http://stackoverflow.com/a/3256941/230513) does not flicker. – trashgod Feb 01 '15 at 04:49
  • @trashgod I have a 15-class program, at the moment, that uses something I've already made to render it. I can't see what difference between my program and the example you give causes the flicker. Is it the use(or lack of) `invokeLater()`? – user2649681 Feb 01 '15 at 04:56

1 Answers1

2

Because your program is incorrectly synchronized in several ways, the result is indeterminate. Swing GUI objects must be constructed and manipulated only on the event dispatch thread; this is required on all supported platforms. As discussed in How to Use Swing Timers, this example runs at 50 Hz without flicker.

I have a 15-class program…

In larger programs, you can search for EDT violations using one of the approaches cited here. Also review the animation techniques suggested here.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045