2016-11-10 2 views
0

Я выполняю задание из учебника Java Exposure, который был написан в 2007 году. В эту книгу входит некоторый код, который я обычно обновляю, чтобы использовать некоторые из последних функций (просто основной материал). Однако в этом я столкнулся с проблемой. Все, что я пытался сделать, это заменить show на setVisible(true) и сменить Frame на JFrame и добавить gfx.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);. Однако я заметил, что это фактически не приведет к закрытию окна. Если бы я много раз щелкнул, возможно, 1/30 попытается закрыть его. Если я уменьшил задержку с 10 до 1, она обычно закрывается в течение 2 попыток. Это, конечно, заставило меня поверить, что метод delay вызывает это неустойчивое поведение. Я пробовал Thread.sleep, но, конечно, это не сработало. Есть ли какой-либо простой способ получить этот код, чтобы рамка закроется, когда я нажму кнопку закрытия? Если этого не произойдет, будет ли менее простой способ сделать это?Почему эта простая петля вызывает проблемное поведение моего JFrame

Вот код:

// Lab30st.java 
// The Screen Saver Program 
// Student Version 


import java.awt.*; 
import java.awt.event.*; 
import java.applet.*; 
import javax.swing.JOptionPane; 


public class Lab30st 
{  
    public static void main(String args[]) 
    { 
     GfxApp gfx = new GfxApp(); 
     gfx.setSize(800,600); 
     gfx.addWindowListener(new WindowAdapter() {public void 
      windowClosing(WindowEvent e) {System.exit(0);}}); 
     gfx.show(); 
    } 
} 


class GfxApp extends Frame 
{ 

    private int circleCount, circleSize; 

    public GfxApp() 
    { 
     circleCount = 50; 
     circleSize = 30; 
    } 


    class Coord 
    { 
     private int xPos; 
     private int yPos; 

     public Coord(int x, int y) 
     { 
      xPos = x; 
      yPos = y; 
     } 
    } 

    public void paint(Graphics g) 
    { 
     int incX = 5; 
     int incY = 5; 
     int diameter = 30; 
     int timeDelay = 10; 
     Circle c = new Circle(g,diameter,incX,incY,timeDelay); 
     for (int k = 1; k <= 2000; k++) 
     { 
      c.drawCircle(g); 
      c.hitEdge(); 
     } 

    } 
} 



class Circle 
{ 
    private int tlX;  // top-left X coordinate 
    private int tlY;  // top-left Y coordinate 
    private int incX;  // increment movement of X coordinate 
    private int incY;  // increment movement of Y coordinate 
    private boolean addX; // flag to determine add/subtract of increment for X 
    private boolean addY; // flag to determine add/subtract of increment for Y 
    private int size;  // diameter of the circle 
    private int timeDelay; // time delay until next circle is drawn 



    public Circle(Graphics g, int s, int x, int y, int td) 
    { 
     incX = x; 
     incY = y; 
     size = s; 
     addX = true; 
     addY = false; 
     tlX = 400; 
     tlY = 300; 
     timeDelay = td; 
    } 

    public void delay(int n) 
    { 
     long startDelay = System.currentTimeMillis(); 
     long endDelay = 0; 
     while (endDelay - startDelay < n) 
      endDelay = System.currentTimeMillis(); 
    } 

    public void drawCircle(Graphics g) 
    { 
     g.setColor(Color.blue); 
     g.drawOval(tlX,tlY,size,size); 
     delay(timeDelay); 
     if (addX) 
      tlX+=incX; 
     else 
      tlX-=incX; 
     if (addY) 
      tlY+=incY; 
     else 
      tlY-=incY; 
    } 


    public void newData() 
    { 
     incX = (int) Math.round(Math.random() * 7 + 5); 
     incY = (int) Math.round(Math.random() * 7 + 5); 
    } 

    public void hitEdge() 
    { 
     boolean flag = false; 
     if (tlX < incX) 
     { 
      addX = true; 
      flag = true; 
     } 
     if (tlX > 800 - (30 + incX)) 
     { 
      addX = false; 
      flag = true; 
     } 
     if (tlY < incY + 30) // The +30 is due to the fact that the title bar covers the top 30 pixels of the window 
     { 
      addY = true; 
      flag = true; 
     } 
     if (tlY > 600 - (30 + incY)) 
     { 
      addY = false; 
      flag = true; 
     } 
     if (flag) 
      newData(); 
    } 

} 
+0

'gfx.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);' правильно. Вы также правы, что ваша «задержка» вызывает проблему. Не блокируйте поток awt paint() и не выполняйте задержки, вращая процессор. – BadZen

ответ

2

Вы «замораживание» на событие диспетчерской темы с

public void delay(int n) 
    { 
     long startDelay = System.currentTimeMillis(); 
     long endDelay = 0; 
     while (endDelay - startDelay < n) 
      endDelay = System.currentTimeMillis(); 
    } 

Это означает, что все другие вещи, которые пытаются произойти (например, закрытие window) должен ждать, пока нить не выйдет из «сна». в основном вы не должны делать задержки в EDT, он должен быть в другом потоке, а затем запрашивать поток EDT для обновления.

Задержка «ожидание ожидания» может вызвать и другие проблемы. Вы можете улучшить поведение с помощью Thread.sleep()

См Java Event-Dispatching Thread explanation

1

Это ужасно.
Необходимо перестроить весь код.

Начнем с очень плохого: delay (почти) оживленное ожидание, я не видел оживших ожиданий, так как BASIC был современным. Он в основном удерживает CPU заложником потока, он не только ничего не делает, ни один другой поток (почти) не может использовать временной срез. Причина, по которой я говорю, заключается в том, что вызов функции системного времени приводит к переключению контекста, который может позволить запускать другие потоки, но все равно плохо.

По-прежнему довольно плохо: Замена на Thread.sleep. Лучше да, не ожидание, но вы все еще держите единственный и единственный поток пользовательского интерфейса. Это означает, что никакая другая работа пользовательского интерфейса не может произойти вплоть до закрытия главного окна.

Что должно произойти:

Получить внешний таймер (например, javax.swing.Timer), чтобы вызвать событие отрисовки и сделать следующую часть анимации.

Поиск «гладкой анимации Java» есть много примеров того, как это сделать, двойной буфер и все.

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