Reputation: 208
I am making a JFrame holding several images that refresh using repaint(). The problem, however, was that the more images I added (or as the area that was being rendered increased) the framerate drastically decreased.
I was initially attempting to reduce the lag that Swing's unpredictable Timer experiences, but was unsuccessful. This time, I tried to call
repaint()
every 10 milliseconds based on system time. (To bypass the timer, desktop.screenPaint.drawWindow(); is called instead of repaint())
while(true)
{
long starttime = System.currentTimeMillis();
while(System.currentTimeMillis()-starttime < 10)
{
}
desktop.screenPaint.drawWindow();
desktop2.screenPaint.drawWindow();
}
Each "desktop" is just one of the draggable windows that you see if you run the code below. I noticed that when only "desktop" is added to "frame," there is no flickering. However, when "desktop2" is also added, flickering does not go away until the time until each refresh is set to 20 or more milliseconds. It is extremely strange, because when I was still using the timer, even thought the wait was set to 10 milliseconds, the framerate would lower to a frame every 20 milliseconds! I tested a little and noticed a trend: you will get flickering until the wait time to the amount of time that the 10 millisecond timer lagged behind. My question: Why is this happening? And is there any way to prevent the flickering, other than going back to the timer?
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.SwingUtilities.*;
import static java.awt.GraphicsDevice.WindowTranslucency.*;
import java.io.File;
import java.io.IOException;
public class Display extends JPanel
{
public static int width, height;
public static JFrame frame = new JFrame("");
private static int rh = 10;
public static Display desktop = new Display();
public static Display desktop2 = new Display();
public static void main(String[] args)
{
Dimension screen = new Dimension();
screen = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
width = (int)screen.getWidth();
height = (int)screen.getHeight();
frame.setLayout(null);
frame.setLocation(0, 0);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(null);
desktop.setBounds(0, 0, 620, 500+rh);
desktop2.setBounds(1000, 200, 620, 500+rh);
frame.add(desktop);
frame.add(desktop2);
frame.setUndecorated(true);
frame.setSize(width, height);
frame.setVisible(true);
while(true)
{
long starttime = System.currentTimeMillis();
while(System.currentTimeMillis()-starttime < 10)
{
}
desktop.screenPaint.drawWindow();
//desktop2.screenPaint.drawWindow();
}
}
private BufferedImage image;
private Graphics2D g;
public Listener screenPaint = new Listener();
private Display identify;
public Display()
{
identify = this;
image = new BufferedImage(620, 500+rh, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D)image.getGraphics();
Timer timer = new Timer(1, screenPaint);
timer.start();
addMouseListener(new mMouse());
addMouseWheelListener(new wWheel());
setFocusable(true);
}
private BufferedImage toCompatibleImage(BufferedImage image)
{
GraphicsConfiguration gfx_config = GraphicsEnvironment.
getLocalGraphicsEnvironment().getDefaultScreenDevice().
getDefaultConfiguration();
if (image.getColorModel().equals(gfx_config.getColorModel()))
return image;
BufferedImage new_image = gfx_config.createCompatibleImage(
image.getWidth(), image.getHeight(), image.getTransparency());
}
public void paint(Graphics view)
{
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
view.drawImage(toCompatibleImage(image), 0, 0, 620, 500+rh, null);
view.dispose();
}
private class Listener implements ActionListener
{
int y = 0;
int wy = 0;
int b = 500;
int c = 1500;
int iy = (int)(wy/(c/(double)b));
int a = -1;
int i = -1;
int j = -1;
boolean d = false;
boolean u = false;
int f = 0;
public void moveY(int sy)
{
f += sy;
}
public void actionPerformed(ActionEvent e)
{
//drawWindow();
}
public void drawWindow()
{
int lx = (int)(identify.getLocation().getX());
int ly = (int)(identify.getLocation().getY());
g.setColor(Color.white);
g.fillRect(0, 0, 620, 500+rh);
g.drawImage(new ImageIcon("image.png").getImage(), 0, wy+rh, 610, c, null);
if(c > b)
{
if(d || Mouse.withinRect(610+lx, (int)(-wy/(c/(double)b))+rh+ly, 10, (int)Math.ceil(Math.pow(b, 2)/(double)c)))
{
if(Mouse.pressLeft())
{
if(!d)d = true;
if(a == -1)a = Mouse.y()-(int)(-wy/(c/(double)b));
y = (int)((Mouse.y()-a)*(c/(double)b));
f = y;
g.setColor(Color.black);
}
else
{
if(d)d = false;
if(a != -1)a = -1;
g.setColor(new Color(60, 60, 60));
}
}
else
{
g.setColor(Color.gray);
if(a != -1)a = -1;
}
if(y == f){}
else if(y < f)
{
y += (int)((f-y)*0.1);
if(y < f)y++;
}
else
{
y -= (int)((y-f)*0.1);
if(y > f)y--;
}
if(y < 0)
{
y = 0;
f = 0;
}
else if(y > c-b)
{
y = c-b;
f = y;
}
wy = -y;
if(u || Mouse.withinRect(lx, ly, 620, 10))
{
if(Mouse.pressLeft())
{
if(!u)u = true;
if(i == -1)i = Mouse.x()-lx;
if(j == -1)j = Mouse.y()-ly;
identify.setLocation(Mouse.x()-i, Mouse.y()-j);
}
else
{
if(u)u = false;
if(i != -1)i = -1;
if(j != -1)j = -1;
}
}
else
{
if(u)u = false;
if(i != -1)i = -1;
if(j != -1)j = -1;
}
int scrollBarLength = (int)Math.ceil(Math.pow(b, 2)/(double)c);
g.fillRect(610, (int)(-wy/(c/(double)b))+rh, 10, scrollBarLength);
}
else
{
g.setColor(new Color(200, 200, 200));
g.fillRect(610, rh, 10, b);
}
g.setColor(new Color(50, 50, 50));
g.fillRect(0, 0, 620, rh);
if(identify == desktop)
repaint();
else if(false)
{}
}
}
}
public static boolean LMPress, LMRelease = false;
public static boolean LMRight, LMLeft = false;
private class mMouse extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
LMPress = true; LMRelease = false;
if(SwingUtilities.isRightMouseButton(e))
{
LMRight = true;
LMLeft = false;
}
else if(SwingUtilities.isLeftMouseButton(e))
{
LMLeft = true;
LMRight = false;
}
}
public void mouseReleased(MouseEvent e)
{
LMRelease = true; LMPress = false;
if(SwingUtilities.isRightMouseButton(e))
{
LMRight = true;
LMLeft = false;
}
else if(SwingUtilities.isLeftMouseButton(e))
{
LMLeft = true;
LMRight = false;
}
}
}
private class wWheel implements MouseWheelListener
{
public void mouseWheelMoved(MouseWheelEvent e)
{
int notches = e.getWheelRotation();
if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {}
e.getScrollAmount();
screenPaint.moveY(e.getUnitsToScroll()*60); //desired pixel jump: 120
}
}
}
Mouse class:
import java.awt.*;
import java.awt.event.*;
public class Mouse {
public static int x() {
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
return (int) b.getX();
}
public static int y() {
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
return (int) b.getY();
}
public static boolean withinRect(int x, int y, int w, int h) {
if (x() >= x && x() < x + w && y() >= y && y() < y + h) return true;
else return false;
}
public static boolean press() {
return Display.LMPress;
}
public static boolean release() {
return Display.LMRelease;
}
public static boolean pressLeft() {
if (Display.LMPress && Display.LMLeft)
return true;
else return false;
}
public static boolean releaseLeft() {
if (Display.LMRelease && Display.LMLeft)
return true;
else return false;
}
public static boolean pressRight() {
if (Display.LMPress && Display.LMRight)
return true;
else return false;
}
public static boolean releaseRight() {
if (Display.LMRelease && Display.LMRight)
return true;
else return false;
}
}
Upvotes: 0
Views: 2750
Reputation: 205785
Updating the view at 1 kHz is unrealistic; instead, consider the alternatives cited here. See this AnimationTest
for an example of self-timing to determine your animation budget.
Addendum: The while(true)
loop at the top is running at 100 Hz.
The available resolution of System.currentTimeMillis()
may vary by platform.
Addendum: I am reopening this question because I was not able to fix it. Any more help?
Absent a Minimal, Complete, Tested and Readable Example, it's hard to say. You appear to be overriding paint()
; was noted in Painting in AWT and Swing: The Paint Methods, "Swing programs should override paintComponent()
." Moreover, you need to invoke super.paintComponent()
, as shown here, to avoid visual artifacts.
Upvotes: 2