按钮不适用于程序

时间:2016-04-21 04:32:10

标签: multithreading javafx

我正在尝试在以下程序中设置按钮,但它们无法正确控制程序。我不确定他们为什么不工作。反向按钮有效,但启动和停止按钮不起作用。

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class ch30 extends Application {
  @Override // Override the start method in the Application class
  public void start(Stage primaryStage) {       
    FanPane fan = new FanPane();

    HBox hBox = new HBox(5);
    Button btPause = new Button("Pause");
    Button btResume = new Button("Resume");
    Button btReverse = new Button("Reverse");
    hBox.setAlignment(Pos.CENTER);
    hBox.getChildren().addAll(btPause, btResume, btReverse);

    BorderPane pane = new BorderPane();
    pane.setCenter(fan);
    pane.setBottom(hBox);

    // Create a scene and place it in the stage
    Scene scene = new Scene(pane, 200, 200);
    primaryStage.setTitle("Exercise15_28"); // Set the stage title
    primaryStage.setScene(scene); // Place the scene in the stage
    primaryStage.show(); // Display the stage

     //Runnable first = new Begin();

     //Thread first = new Thread();

     //t1.start();


        Thread first = new Thread(new Runnable() {
            @Override public void run() {
                while (true) {
                    try {
                        //Pause
                        Thread.sleep(100);

                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    Platform.runLater(new Runnable() {
                        @Override public void run() {

                          fan.move(); 

                        }
                    });
                }
            }
        });

                first.start();



   //Timeline animation = new Timeline(
      //new KeyFrame(Duration.millis(100), e -> fan.move()));
    //animation.setCycleCount(Timeline.INDEFINITE);
    //animation.play(); // Start animation

    scene.widthProperty().addListener(e -> fan.setW(fan.getWidth()));
    scene.heightProperty().addListener(e -> fan.setH(fan.getHeight()));

   //btPause.setOnAction(e -> first.wait());
    btResume.setOnAction(e -> first.start());
    btReverse.setOnAction(e -> fan.reverse());
  }

  /**
   * The main method is only needed for the IDE with limited
   * JavaFX support. Not needed for running from the command line.
   */
  public static void main(String[] args) {
    launch(args);


  }
} 

class FanPane extends Pane {
  private double w = 200;
  private double h = 200;
  private double radius = Math.min(w, h) * 0.45;
  private Arc arc[] = new Arc[4];   
  private double startAngle = 30;
  private Circle circle = new Circle(w / 2, h / 2, radius);

  public FanPane() {
    circle.setStroke(Color.BLACK);
    circle.setFill(Color.WHITE);
    getChildren().add(circle);

    for (int i = 0; i < 4; i++) {
      arc[i] = new Arc(w / 2, h / 2, radius * 0.9, radius * 0.9, startAngle + i * 90, 35);
      arc[i].setFill(Color.RED); // Set fill color
      arc[i].setType(ArcType.ROUND);
      getChildren().addAll(arc[i]); 
    } 
  }

  private double increment = 5;

  public void reverse() {
    increment = -increment;
  }

  public void move() {
    setStartAngle(startAngle + increment);
  }

  public void setStartAngle(double angle) {
    startAngle = angle;
    setValues();
  }

  public void setValues() {
    radius = Math.min(w, h) * 0.45;
    circle.setRadius(radius);
    circle.setCenterX(w / 2);
    circle.setCenterY(h / 2);

    for (int i = 0; i < 4; i++) {
      arc[i].setRadiusX(radius * 0.9);
      arc[i].setRadiusY(radius * 0.9);
      arc[i].setCenterX(w / 2);
      arc[i].setCenterY(h / 2);
      arc[i].setStartAngle(startAngle + i * 90);
    }     
  }

  public void setW(double w) {
    this.w = w;
    setValues();
  }

  public void setH(double h) {
    this.h = h;
    setValues();
  }
}

1 个答案:

答案 0 :(得分:2)

这应该用时间轴来完成,我知道这是你的作业,而且由于某些疯狂的原因,你的作业被指定为不使用时间轴。但是对于其他人来说,不要这样做,只需使用时间轴。

那说......

你提到你没有的开始和停止按钮。我假设开始意味着恢复,停止意味着暂停,因为那些是您拥有的按钮。所以我会相应地回答。

处理此问题的最简单方法是使用布尔变量来控制风扇是否在移动。

定义应用程序的成员:

private boolean paused = false;

在你的主题中,如果没有暂停,只移动风扇:

Platform.runLater(() -> { if (!paused) fan.move(); });

配置按钮以设置标记:

btPause.setOnAction(e -> paused = true);
btResume.setOnAction(e -> paused = false);

我只是将暂停变量直接放在调用应用程序中,但如果您愿意,可以将暂停状态封装在粉丝对象中。

通常在处理多线程内容时,必须注意由于竞争条件而导致数据损坏。例如,您将使用AtomicBoolean或synchronized语句等构造。但runLater将所有内容都放在JavaFX应用程序主题上,因此您不必担心这一点。

您可以使用其他机制来确保您的主题不会保持循环播放和休眠,例如wait/notifyConditions,但是对于这样的示例,您可能需要这里需要它。

更新了应用

更新了演示建议修改的示例,在JDK 8u60,OS X 10.11.4上进行了测试。

public class ch30 extends Application {
    private boolean paused = false;

    @Override 
    public void start(Stage primaryStage) {
        FanPane fan = new FanPane();

        HBox hBox = new HBox(5);
        Button btPause = new Button("Pause");
        Button btResume = new Button("Resume");
        Button btReverse = new Button("Reverse");
        hBox.setAlignment(Pos.CENTER);
        hBox.getChildren().addAll(btPause, btResume, btReverse);

        BorderPane pane = new BorderPane();
        pane.setCenter(fan);
        pane.setBottom(hBox);

        Thread first = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                    break;
                }
                Platform.runLater(() -> { if (!paused) fan.move(); });
            }
        });
        first.setDaemon(true);    
        first.start();

        btPause.setOnAction(e -> paused = true);
        btResume.setOnAction(e -> paused = false);
        btReverse.setOnAction(e -> fan.reverse());

        Scene scene = new Scene(pane, 200, 200);
        scene.widthProperty().addListener(e -> fan.setW(fan.getWidth()));
        scene.heightProperty().addListener(e -> fan.setH(fan.getHeight()));
        primaryStage.setScene(scene); 
        primaryStage.show(); 
    }
}

除了

设置线程的daemon status,以便当有人关闭主舞台时,应用程序会干净地关闭。

first.setDaemon(true);