2012-06-23 4 views
4

Этот вопрос связан с тем, который я задал HERE. Теперь у меня есть класс «Контроллер», который состоит из основного метода и всех компонентов поворота. существует класс с именем «VTOL», который состоит из переменной с названием «высота» (я уже объявил эту переменную изменчивой).Доступ к переменным и компонентам качания через разные потоки

здесь это класс, который состоит из нити, которая проходит в фоновом режиме:

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

    } 
} 

Во-первых, проблема я столкнулся первоначально было то, что я не мог значение обновления на «высоте» осталось 0 в течение выполнения программы. Таким образом, я объявил его изменчивым (я не знаю, если это хорошая практика)

Во-вторых, есть класс jLabel в классе Controller с именем lblAltitude, я хочу обновить его значение по мере его изменения в этом потоке, но так или иначе не происходит. Как я могу это сделать?

+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

Всякий раз, когда вы изменяете компонент Swing, вам необходимо убедиться, что это событие происходит в потоке отправки событий (то есть EDT).

+2

+1. Существует ссылка на правила параллелизма с Swing для каждого компонента Swing javadoc, но половина вопросов Swing здесь не соблюдает правила. Вздох. http://docs.oracle.com/javase/6/docs/api/javax/swing/package-summary.html#threading –

+0

имеет возможность множественного EDT? это правильный способ сделать это? Короче, могу ли я сделать это в вышеуказанном классе? – md1hunox

+2

@vineetrok: no. есть только один поток событий, это своего рода целое. 1+ пользователю1329 ... –

2

Третий подход заключается в том, чтобы иметь свой компонент Swing, знает о модели, 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() (или, может быть, где-то еще во всех вызовах краски, есть небольшой шанс, что она должна быть в другом месте ...) от контроллера, который вы знаете работают на EDT

// 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, но связь все между очень связанными классами, так что «разумный», а в каком-то смысле это может быть «чище». И очередь отправки событий объединяет несколько рецензентов, поэтому это не так неэффективно, как только оно появляется. Если несколько потоков обновляют материал и ставят в очередь несколько repaints(), то только последняя repaint() фактически что-то делает.

Недостаток заключается в том, что если ваш графический интерфейс имеет gazillion виджеты, и вы обновляете все их каждый раз, когда это может стать немного медленным. Но сейчас процессоры невероятно быстрые.

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