简体   繁体   English

通过不同的线程访问变量和摆动组件

[英]accessing variables and swing components through different threads

This question is related somewhat to the one i asked HERE . 这个问题与我在这里问的问题有些关系。 Now, i have a class "Controller" which consists of the main method and all the swing components. 现在,我有一个类“Controller”,它由main方法和所有swing组件组成。 there is a class named "VTOL" which consists of a variable named "altitude"(i have declared this variable volatile as of now). 有一个名为“VTOL”的类,它由一个名为“altitude”的变量组成(我现在声明这个变量是volatile)。

here is a class that consists of a thread which runs in the background: 这是一个由在后台运行的线程组成的类:

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

    }
}

Firstly, the problem i was facing initially was that i couldnt update value of "altitude" it remained 0 throughout the execution of program. 首先,我最初面临的问题是我无法更新“高度”的值,它在整个程序执行过程中保持为0。 So i declared it as volatile (I dont know if its a good practice) 所以我宣称它是不稳定的(我不知道它是否是一个好习惯)

Secondly, there is a jLabel in Controller class named "lblAltitude", i wish to update its value as its changed in this thread, but somehow thats not happening. 其次,在Controller类中有一个名为“lblAltitude”的jLabel,我希望将其值更新为此线程中的更改,但不知何故那不会发生。 How can i do that? 我怎样才能做到这一点?

A solution is to use a SwingPropertyChangeSupport object, to make altitude a "bound" property with this support object, to have your GUI listener to this model class and to thereby notify the GUI of changes in altitude. 解决方案是使用SwingPropertyChangeSupport对象,使高度成为此支持对象的“绑定”属性,以使您的GUI监听器到此模型类,从而通知GUI高度变化。

eg, 例如,

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


}

For a more complete runnable example: 有关更完整的可运行示例:

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

每当修改Swing组件时,都需要确保在Event Dispatch Thread(即EDT)中发生此事件。

A third approach would be to have your Swing component know about the model, VTOL. 第三种方法是让您的Swing组件了解模型VTOL。

In Gravity, you'd update VTOL.altitude, then call repaint on the component. 在Gravity中,您将更新VTOL.altitude,然后在组件上调用repaint。 eg 例如

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

  controller.repaint();
  // sleep, break etc. left as an exercise for the reader
}

Then, in the paintComponent() method (or maybe somewhere else in all the paint calls, there's a slight chance it needs to be elsewhere...) of Controller, which you know is running on the EDT 然后,在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...

This is a bit tighter coupled than SwingPropertyChangeSupport, but the coupling is all between very related classes, so it is "reasonable", and in some ways this may be "clearer". 这比SwingPropertyChangeSupport更加紧密耦合,但耦合是在非常相关的类之间进行的,所以它是“合理的”,并且在某些方面这可能更“清晰”。 And the Event Dispatch Queue will combine multiple repaints so this isn't as inefficient as it first appear. 并且事件调度队列将结合多个重绘,因此这不像它首次出现那样低效。 If multiple threads are updating stuff and queuing up multiple repaints(), only the last repaint() actually does anything. 如果多个线程正在更新内容并排队多个重绘(),则只有最后一个重绘()实际上做了任何事情。

A disadvantage is that if your GUI has a gazillion widgets and you update all of them every time this may get a bit slow. 缺点是,如果您的GUI具有大量的小部件,并且每次更新所有这些小部件可能会变得有点慢。 But processors are amazingly fast nowadays. 但是现在处理器的速度非常快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM