2012-06-23 3 views
4

이 질문은 내가 질문 한 것과 다소 관련이 있습니다 HERE. 이제 메인 메서드와 모든 스윙 구성 요소로 구성된 "Controller"클래스가 있습니다. "고도"라는 이름의 변수로 구성된 "VTOL"이라는 클래스가 있습니다 (현재이 변수를 volatile로 선언했습니다).다른 스레드를 통해 변수에 액세스하고 구성 요소를 스윙

import java.util.logging.Level; 
import java.util.logging.Logger; 

/** 
* 
* @author Vineet 
*/ 
public class Gravity extends Thread { 

    String altStr; 
    double alt; 
    Controller ctrl = new Controller(); 

    @Override 
    public void run() { 
     while (true) { 
      alt=VTOL.altitude; 
      System.out.println(alt); 
      alt = alt-0.01; 
      VTOL.altitude= (int) alt; 
      altStr=new Integer(VTOL.altitude).toString(); 
      ctrl.lblAltitude.setText(altStr); 
      try { 
       Thread.sleep(10); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 

    } 
} 

첫째, 나는 "고도"의 업데이트 값을 couldnt한다이었다 처음 직면 한 문제는 그것이 실행에 걸쳐 0 남아 : 여기

는 백그라운드에서 실행되는 스레드로 구성된 클래스 프로그램의. 그래서 나는 그것을 휘발성으로 선언했다. (그 좋은 습관인지는 모르겠다.)

둘째, "lblAltitude"라는 컨트롤러 클래스에 jLabel이있다.이 스레드에서 변경된 값으로 업데이트하려고하지만, 어떻게 든 일어나지 않아. 어떻게 할 수 있습니까?

+0

'VTOL.altitude'를 전혀 변경하지 않았습니다. 'double'에 복사 한 후'0.01'을 뺀 다음 다시 int 형으로 캐스팅 한 뒤 다시 복사합니다. 'VTOL.altitude'는 캐스트가 소수 부분을 제거하기 때문에 변경되지 않습니다. '-0.01'. 'VTOL.altitude'는 두 배입니까? 그렇지 않다면 그렇게 할 수도 있습니다. 확실히 'int'로 캐스트를 제거해야합니다. – OldCurmudgeon

+0

실제로 VTOL.altitude는 int입니다. 내 목표는 vtol을 0.01 배 줄이는 것입니다. 나는 그것이 완전히 내려 오기를 원하지 않는다. 그래서 나는 그것을했다. – md1hunox

+1

그런 경우에는 'alt - = alt * 0'과 같은 것이 필요합니다.01' 안 그래? 만약 당신이 정말로 * * 요인에 의한 감소를 의미합니다. BTW - 0에서 시작하면 여전히이 편집으로 변경되지 않습니다. – OldCurmudgeon

답변

7

해결 방법 SwingPropertyChangeSupport 객체를 사용하여이 지원 객체로 고도를 "바운드"속성으로 만들고 GUI 리스너를이 모델 클래스에 추가하여 고도 변화를 GUI에 알립니다. 보다 완전한 실행 가능한 예를 들어, 예를 들어

,

import java.beans.PropertyChangeListener; 
import javax.swing.event.SwingPropertyChangeSupport; 

public class Gravity implements Runnable { 
    public static final String ALTITUDE = "altitude"; 
    private SwingPropertyChangeSupport swingPcSupport = new SwingPropertyChangeSupport(this); 
    private volatile double altitude; 

    @Override 
    public void run() { 
     while (true) { 
     double temp = altitude + 10; 
     setAltitude(temp); // fires the listeners 
     try { 
      Thread.sleep(10); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     } 

    } 

    public double getAltitude() { 
     return altitude; 
    } 

    public void setAltitude(double altitude) { 
     Double oldValue = this.altitude; 
     Double newValue = altitude; 

     this.altitude = newValue; 

     // this will be fired on the EDT since it is a SwingPropertyChangeSupport object 
     swingPcSupport.firePropertyChange(ALTITUDE, oldValue, newValue); 
    } 

    public void addPropertyChangeListener(PropertyChangeListener listener) { 
     swingPcSupport.addPropertyChangeListener(listener); 
    } 

    public void removePropertyChangeListener(PropertyChangeListener listener) { 
     swingPcSupport.removePropertyChangeListener(listener); 
    } 


} 

:

import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import javax.swing.*; 
import javax.swing.event.SwingPropertyChangeSupport; 

public class GravityTestGui extends JPanel { 
    private static final long ALT_SLEEP_TIME = 400; 
    private static final double ALT_DELTA = 5; 
    JLabel altitudeLabel = new JLabel("  "); 
    private Gravity gravity = new Gravity(ALT_SLEEP_TIME, ALT_DELTA); 

    public GravityTestGui() { 
     add(new JLabel("Altitude:")); 
     add(altitudeLabel); 

     gravity.addPropertyChangeListener(new PropertyChangeListener() { 

     @Override 
     public void propertyChange(PropertyChangeEvent pcEvt) { 
      if (Gravity.ALTITUDE.equals(pcEvt.getPropertyName())) { 
       String altText = String.valueOf(gravity.getAltitude()); 
       altitudeLabel.setText(altText); 
      } 
     } 
     }); 

     new Thread(gravity).start(); 
    } 

    private static void createAndShowGui() { 
     GravityTestGui mainPanel = new GravityTestGui(); 

     JFrame frame = new JFrame("GravityTest"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowGui(); 
     } 
     }); 
    } 


} 

class Gravity implements Runnable { 
    public static final String ALTITUDE = "altitude"; 
    private SwingPropertyChangeSupport swingPcSupport = new SwingPropertyChangeSupport(this); 
    private volatile double altitude; 
    private long sleepTime; 
    private double delta; 

    public Gravity(long sleepTime, double delta) { 
     this.sleepTime = sleepTime; 
     this.delta = delta; 
    } 

    @Override 
    public void run() { 
     while (true) { 
     double temp = altitude + delta; 
     setAltitude(temp); // fires the listeners 
     try { 
      Thread.sleep(sleepTime); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     } 

    } 

    public double getAltitude() { 
     return altitude; 
    } 

    public void setAltitude(double altitude) { 
     Double oldValue = this.altitude; 
     Double newValue = altitude; 

     this.altitude = newValue; 

     // this will be fired on the EDT since it is a SwingPropertyChangeSupport object 
     swingPcSupport.firePropertyChange(ALTITUDE, oldValue, newValue); 
    } 

    public void addPropertyChangeListener(PropertyChangeListener listener) { 
     swingPcSupport.addPropertyChangeListener(listener); 
    } 

    public void removePropertyChangeListener(PropertyChangeListener listener) { 
     swingPcSupport.removePropertyChangeListener(listener); 
    } 
} 
+0

+1, 나는 'SwingPropertyChangeSupport' 클래스를 전혀 알지 못했다. 무엇을 찾아라! 그러나이 클래스는 Java 버전 1.6 이상에서만 사용할 수 있습니다. – user1329572

+0

@ user1329572 : 그 제한에 대해 알지 못했습니다. 정보를 제공해 주셔서 감사합니다. 1.5를 사용해야하는 경우 지원 요청을 EDT에 대기시키기가 쉽습니다. –

+0

@HovercraftFullOfEels : 감사합니다. 내가 찾던 것을 가지고있어. 새로운 것을 배웠습니다. – md1hunox

6

스윙 구성 요소를 수정할 때마다이 이벤트가 이벤트 발송 스레드 (즉, EDT)에서 발생하는지 확인해야합니다.

+2

+1. 각 Swing 구성 요소 javadoc마다 Swing과의 동시성 규칙에 대한 링크가 있지만 여기에있는 Swing 질문의 절반은 규칙을 준수하지 않습니다. 한숨. http://docs.oracle.com/javase/6/docs/api/javax/swing/package-summary.html#threading –

+0

에 여러 개의 EDT가 가능합니까? 그것을하는 적당한 방법 있는가? 간단히 말해서 나는 위의 클래스에서 그것을 할 수 있습니까? – md1hunox

+2

@vineetrok : no. 단 하나의 이벤트 스레드가 있습니다. 1+ to user1329 ... –

2

세 번째 방법은 당신의 스윙 구성 요소가하는 것입니다 모델, VTOL에 대해 알고.

Gravity에서는 VTOL.altitude를 업데이트 한 다음 구성 요소에서 다시 칠하기를 호출합니다. 예 :

while (true) { 
    VTOL.altitude -= 0.01; 
    VTOL.makeAnyOtherChangesHereAsWell(); 

    controller.repaint(); 
    // sleep, break etc. left as an exercise for the reader 
} 
의 paintComponent() 메소드에서 다음

, 당신이이 실행되는 알고 컨트롤러, (아니면 다른 곳에서 모든 페인트 통화에서, 다른 곳에서 할 필요가있는 약간의 기회가 ...있다) 동부 서머 타임

// update my widgets from the VTOL model - may want this in a method 
String altStr=new Integer(VTOL.altitude).toString(); 
this.lblAltitude.setText(altStr); 
// may be more, e.g. ... 
this.lblFuelSupply.setText(VTOL.getFuelSupply()); 

super.paintComponent(); // now go draw stuff... 

이것은 SwingPropertyChangeSupport보다 결합 약간 타이트하지만 커플 링은 모두 매우 관련 클래스 사이에, 그래서 "합리적"이며, 어떤면에서는이 "명확하게"할 수있다. 그리고 Event Dispatch Queue는 여러 repaints를 결합 할 것이므로 처음 나타나는 것처럼 비효율적이지는 않습니다. 여러 스레드가 물건을 업데이트하고 여러 repaints()를 대기열에 추가하면 마지막 repaint() 만 실제로 작업을 수행합니다.

단점은 GUI에 gazillion 위젯이 있고이 기능이 약간 느려질 때마다 모두 업데이트한다는 것입니다. 그러나 프로세서는 요즘 놀라 울 정도로 빠릅니다.