2014-02-08 2 views
0

Я делаю JFrame с несколькими изображениями, которые обновляются с помощью repaint(). Проблема, однако, заключалась в том, что чем больше изображений я добавил (или как область, которая была оказана увеличена), частота кадров резко снизилась.Частота обновления графического изображения Java Graphics

Сначала я пытался уменьшить отставание от непредсказуемого таймера Swing, но безуспешно. На этот раз я попытался позвонить

repaint() 

каждые 10 миллисекунд в зависимости от системного времени. (Для того, чтобы обойти таймер, desktop.screenPaint.drawWindow(); вызывается вместо перерисовки())

while(true) 
    { 
    long starttime = System.currentTimeMillis(); 
    while(System.currentTimeMillis()-starttime < 10) 
    { 
    } 
    desktop.screenPaint.drawWindow(); 
    desktop2.screenPaint.drawWindow(); 
    } 

Каждый «рабочий стол» это просто один из перемещаемых окон, которые вы видите, если вы запустите код, приведенный ниже. Я заметил, что когда в «фрейм» добавляется только «рабочий стол», мерцания нет. Однако, когда добавляется «desktop2», мерцание не исчезает до тех пор, пока каждое обновление не будет установлено на 20 или более миллисекунд. Это очень странно, потому что, когда я все еще использовал таймер, даже думал, что ожидание было установлено в 10 миллисекунд, частота кадров снизилась бы до кадра каждые 20 миллисекунд! Я немного протестировал и заметил тенденцию: вы будете мерцать до времени ожидания до времени, в течение которого 10 миллисекундный таймер отставал. Мой вопрос: почему это происходит? И есть ли способ предотвратить мерцание, кроме как вернуться к таймеру?

What the image is supposed to look like

flickering

класс

flickering

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 
     } 
    } 
} 

Мышь:

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; 
    } 
} 

ответ

2

Обновление вид на частоте 1 кГц нереально; вместо этого рассмотрите приведенные альтернативы here. См. Это AnimationTest для примера самосинхронизации для определения вашего бюджета анимации.

Добавление: Циклwhile(true)на вершине работает на частоте 100 Гц.

Доступное разрешение System.currentTimeMillis() may vary by platform.

Приложение: Я снова открываю этот вопрос, потому что я не смог его исправить. Больше помощи?

Отсутствует Minimal, Complete, Tested and Readable Example, это трудно сказать. Вы, кажется, переопределяете paint(); было отмечено в Painting in AWT and Swing: The Paint Methods: «Программы Swing должны переопределять paintComponent()». Кроме того, вам необходимо вызвать super.paintComponent(), как показано here, чтобы избежать визуальных артефактов.

+0

Я не уверен, где вы получили 1 Гц. Мой таймер, который настроен на обновление каждые 1 миллисекунды, составляет 1000 Гц (поэтому я его не использую. Извините, что я не прокомментировал 'timer.start()'). Цикл while (true) вверху работает на частоте 100 Гц. Я на самом деле модифицировал его, чтобы обновить каждые 50/3 миллисекунды, что снижает его до 60 Гц (скорость моего монитора), но все равно безуспешно. Однако ваши ответы были очень полезными! Я ценю это. – L3R5

+0

@ L3R5: Хорошая добыча; Я должен был сказать кГц; выше. – trashgod

+1

Вау! Большое спасибо!Когда я распечатывал разницу во времени, они всегда колебались бы на несколько миллисекунд. Когда время ожидания опустилось ниже 10 миллисекунд, экран погас. Теперь я знаю, что делать, чтобы исправить это. Еще раз спасибо! – L3R5

Смежные вопросы