2016-04-21 111 views
0

我試圖設置下面的程序的按鈕,但他們不會正確控制程序。我不確定他們爲什麼不工作。反轉按鈕起作用,但開始按鈕和停止按鈕不起作用。按鈕無法在程序

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

'wait'不會暫停線程,而是讓當前(調用)線程等待,直到有人在同一個對象上調用notify。看看[這個問題](http://stackoverflow.com/questions/19894607/java-how-to-stop-thread) – Itai

回答

2

這應該用時間軸來完成,我知道這是你的功課,並且出於一些瘋狂的原因,你的作業被指定爲不使用時間軸。但對其他人來說,不要這樣做,只需使用時間軸。

這就是說......

你提到你沒有的開始和停止按鈕。我認爲開始意味着恢復並停止意味着暫停,因爲那些是你有的按鈕。所以我會相應地回答。

處理這個問題的最簡單方法是使用布爾變量來控制風扇是否在移動。

定義應用程序中的一員:

private boolean paused = false; 

在你的線程只能移動風扇,如果沒有暫停:

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

配置您的按鈕來設置你的標誌:

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

我只是把暫停變量直接放在調用應用程序中,但是你可以封裝暫停狀態如果你願意的話,你可以在粉絲對象的內部。

正常情況下,當處理多線程的東西時,你必須小心數據由於競爭條件而被破壞。例如,您可以使用類似AtomicBoolean的結構或同步語句。但是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); 
+0

這實際上不起作用。現在我正在使用first.stop()暫停程序。但是,我停止後無法重新啓動線程。你知道爲什麼簡歷按鈕不起作用嗎? – milliehol

+0

此答案中的解決方案確實有效。您不應該調用[thread.stop()](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#stop--),它已被棄用,文檔說明它的使用是不安全的。此外,如果你這樣做,線程狀態將轉到[Thread.State.TERMINATED](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.State.html#TERMINATED) 。這是[結束狀態](http://www.uml-diagrams.org/examples/java-6-thread-state-machine-diagram-example.html)。終止的線程將永遠終止,它永遠不會恢復處理。 – jewelsea

+0

當我嘗試使用您的解決方案時,它說我不能使用布爾變量,除非它是最終的。當我將其聲明爲final時,我無法在按鈕區域將其設置爲true或false。你知道我爲什麼得到這個錯誤嗎? – milliehol