有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java通过不同的线程访问变量和swing组件

这个问题在某种程度上与我问的问题有关。 现在,我有一个类“Controller”,它由main方法和所有swing组件组成。有一个名为“VTOL”的类,它由一个名为“althip”的变量组成(我已经声明这个变量是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();
            }
        }

    }
}

首先,我最初面临的问题是,我无法更新“高度”的值,它在整个程序执行过程中保持为0。所以我宣布这是不稳定的(我不知道这是否是一个好的做法)

其次,在控制器类中有一个名为“lblAltitude”的jLabel,我希望在这个线程中随着它的更改而更新它的值,但不知何故,这并没有发生。 我该怎么做


共 (3) 个答案

  1. # 1 楼答案

    无论何时修改Swing组件,都需要确保该事件发生在事件分派线程(即EDT)中

  2. # 2 楼答案

    一种解决方案是使用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);
       }
    }
    
  3. # 3 楼答案

    第三种方法是让Swing组件了解模型VTOL

    在重力中,你需要更新VTOL。高度,然后调用组件上的重新绘制。e、 g

    while (true) {
      VTOL.altitude -= 0.01;
      VTOL.makeAnyOtherChangesHereAsWell();
    
      controller.repaint();
      // sleep, break etc. left as an exercise for the reader
    }
    

    然后,在paintComponent()方法中(或者在所有paint调用的其他地方,有一点可能需要在其他地方…)控制器,你知道它正在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的耦合更紧密一些,但耦合都是在非常相关的类之间,所以它是“合理的”,在某些方面可能更“清晰”。事件调度队列将合并多个重绘,因此不会像最初出现的那样效率低下。如果多个线程正在更新内容并排队等待多个repait(),那么实际上只有最后一个repait()执行任何操作

    一个缺点是,如果你的GUI有大量的小部件,并且你每次都更新它们,这可能会有点慢。但如今处理器的速度惊人