import javafx.application.Application;
import javafx.scene.Group;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.control.ChoiceBox;
import javafx.collections.FXCollections;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;

public class LayerTest extends Application {
    
    private Group root;//创建一个私有成员  节点组容器
    private BorderPane borderPane; //创建一个私有成员 边框布局对象
    private Canvas layer1;  //创建画布1
    private Canvas layer2;  //创建画布2
    private GraphicsContext gc1;  //私有画笔对象1(画笔上下文1)
    private GraphicsContext gc2; //私有画笔对象2 (画笔上下文2)
    private ChoiceBox cb;//选择框控件
    
    private void createLayers(){//私有方法创建层
        
        // Layers 1&2 are the same size
        layer1 = new Canvas(300,250);//创建画布对象1
        layer2 = new Canvas(300,250);//创建画布对象2
        
        // Obtain Graphics Contexts
        gc1 = layer1.getGraphicsContext2D();//获得图层一上的绘画上下文(创建canvas上的画笔对象)
        gc1.setFill(Color.GREEN);//画笔填充绿色墨水
        gc1.fillOval(50,50,20,20);//画一个小椭圆形
        gc2 = layer2.getGraphicsContext2D();//创建图层画布layer2上的画笔对象(获取canvas对象layer2对象上的绘画上下文环境对象)
        gc2.setFill(Color.BLUE);//画笔2填充蓝色染料
        gc2.fillOval(100,100,20,20);//利用画笔2画一个小椭圆
    }
    
    private void handleLayers(){
        // Handler for Layer 1
        layer1.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {//canvas对象 layer1上面添加鼠标按压事件处理器机制
            @Override
            public void handle(MouseEvent e) {          
                gc1.fillOval(e.getX(),e.getY(),20,20);
            }//鼠标事件回调方法利用画笔1在对应的画布上layer1画一个椭圆
        });
        
         // Handler for Layer 2
        layer2.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {//canvas对象 layer2上面添加鼠标按压事件处理器机制
            @Override
            public void handle(MouseEvent e) {
                gc2.fillOval(e.getX(),e.getY(),20,20);
            }//鼠标事件回调方法利用画笔2在对应的画布layer2上画一个椭圆
        });
    }
    
    private void createChoiceBox(){
        cb = new ChoiceBox();//创建选择框控件对象
        cb.setItems(FXCollections.observableArrayList("Layer 1 is GREEN", "Layer 2 is BLUE"));//将选择框对象上添加选项
        cb.getSelectionModel().selectedItemProperty().addListener(new ChangeListener(){// 设置选择控件的选择属性并添加事件监听器对象
            @Override
            public void changed(ObservableValue o, Object o1, Object o2){//内容改变事件处理回调函数/钩子方法(利用的gof23设计模式中的观察者模式)
                if(o2.toString().equals("Layer 1 is GREEN")){//当判断当前选择layer1对应的文本选项时候
                    layer1.toFront();//将layer1画布对象置前位置
                }else if(o2.toString().equals("Layer 2 is BLUE")){//当判断当前选择layer2对应的文本选项时候
                    layer2.toFront();//将layer2画布对象置前
                }
            }
        });  
        cb.setValue("Layer 1 is GREEN");//初始化时候设置ChoiceBox类型对象的默认选择项
    }
    
    private void addLayers(){//添加 画布对象到前文初始化建立好的 节点对象布局容器当中
        // Add Layers
        borderPane.setTop(cb);    //borderPane布局容器中添加 ChoiceBox类型ui控件对象cb
        Pane pane = new Pane();//创建一个面板对象
        pane.getChildren().add(layer1);//面板上添加 Canvas类型对 layer1
        pane.getChildren().add(layer2);//面板上添加 Canvas类型对 layer2
        layer1.toFront();//将layer1对象位置置顶
        borderPane.setCenter(pane);   //borderPane对象的中心位置添加Pane类型面板对象 pane
        root.getChildren().add(borderPane);//根节点组容器添加 borderPane对象
    }
    
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {//启动舞台对象方法
        
        // Build GUI
        borderPane = new BorderPane();  //创建BorderPane类型布局面板对象
        primaryStage.setTitle("Layer demo");//设置舞台标题
        root = new Group();//创建节点组容器对象
        createLayers();//创建图层
        handleLayers();//绑定图层 canvas 对象的事件处理机制
        createChoiceBox();//创建选项组件及其事件处理绑定机制代码
        addLayers();  //默认添加并布局图层对象
      
        // Show Scene
        primaryStage.setScene(new Scene(root));//舞台上添加场景,场景上添加节点组容器
        primaryStage.show();//舞台放映展现
    }
}