JaxaFx学习(二)

目录:

(1)controller中的initialize方法

(2)在Application操作Controller

 (3)多线程操作PlatForm.runLater

(4)Canvas画布控件介绍

(5)Canvas保存图片文件

(6)Canvas开发游戏的基本思路

(7)javaFX多媒体播放

(8)media包里的AudioClip类

(1)controller中的initialize方法

controller中可以写一个initalize方法,这个方法呢,当把布局文件加载完成,把组件绑定到属性上之后,他会调用一次initialize方法,我们可以写一些复杂的没办法在fxml中写的一些事件,或者对组件数据的填充

initialize是在布局文件加载之后,属性绑定完之后,才调用的方法 

有时候我们的控件是需要填充数据的,我们在action方法绑定fxml的事件里是没有办法做到的,因为他必须有触发事件的条件,我们的需求呢启动的时候就应该把数据加载好

controller:

启动的时候给tableView里面给填充上数据,这个时候就需要initiate来做 

我们是没有办法在布局文件中做填充的,在事件中填充需要有触发事件的条件,他的触发时机是加载好布局文件绑定好控件id之后,才调用一次

需要注意在initialize中是不能访问到Scene的,因为还没有new出来有空指针的错误,因为他是先加载好布局之后,才能知道布局是放到那个场景里面

(2)在Application操作Controller

我们有这样一个需求,在主线程,主启动类Application里面需要调用到controller进而去操作这里面的空控件

Idea跟外界的Build进行关联

同步进行了更改:

在fxml里面是没有办法更改让中心点可以随着窗口进行移动,不能通过事件来绑定,Controller里面也没有办法自动调用绑定的逻辑,我们只能在主线程里面获取controller的引用,主动对他进行绑定

ci可以设置成public的,在主线程里面我们可以直接获取到这个,为了封装性,我们设置一个在外面调用的方法,来进行控件属性的绑定

这样就实现了自适应:

这就是在主线程里面来操作来操作fxml里的控件,或者来操作controller

(3)多线程操作PlatForm.runLater

在javaFX里面是不允许除主线程以外的其他线程去更改或刷新UI的,也就是说刷新界面的操作只能由main方法这个线程(Application这个线程)来执行,他是为了线程安全来考虑的,为了避免其他线程去污染UI的数据,只允许单线程去更新数据

可以进行这样更改:

runLater是把这个任务放到一个队列里在Application空闲的时候去执行队列里面的任务,箱单与是在Application这个线程里面执行的

 

在FX的很多控件的事件里内部是调用了这个 runLater,事件里也是在这个代码里执行的 

点击按钮回去一个网址去加载一个照片放到场景里面,上面的线程是没有手动的调用 runLater,属性监听器其实内部把把change这个方法放到了队列里面了

像这种连接网络,或者数据的耗时任务,我们最好是新建线程让他去其他线程去执行去,不要让他占用主线程

(4)Canvas画布控件介绍

我们可以在画布上绘制线段、文本、图形、图片都可以

他没有直接的方法,只有设置坐标宽高的,如果想在这个画布上绘制东西,需要使用getGraphicsContext2D 

他提供了一些绘制的方法

通过这个我们可以去开发一些绘图类的软件,或者2d游戏

package org.example;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;


/**
 * fxml的运用:现实视图、控制器、java代码就实现了分离,主类里面的代码会非常简介
 *
 */
public class Canvas0 extends Application {
    public static final double WIDTH=800,HEIGHT=600;
    private Canvas canvas=new Canvas(WIDTH,HEIGHT);
    //GraphicsContext对象操作绘制
    private GraphicsContext graphicsContext=canvas.getGraphicsContext2D();


    public static void main(String[] args) {
        System.out.println("Hello world!");
        //入口函数调用lanch方法,launch会自动的调用start方法
        Application.launch(args);
    }


    @Override
    public void start(Stage primaryStage) throws Exception {//窗口Stage

        //窗口是否可以改变大小
        primaryStage.setResizable(true);

        canvas.setLayoutX(0);
        canvas.setLayoutY(0);

        //填充颜色
        graphicsContext.setFill(Color.RED);
        //描边的颜色
        graphicsContext.setStroke(Color.GREEN);
        //边框宽度
        graphicsContext.setLineWidth(10);

        //绘制一个没有填充的矩形
        //graphicsContext.strokeRect(30,30,300,300);
        //有提填充色的矩形
        //graphicsContext.fillRect(30,30,300,300);


        //绘制一个圆
        graphicsContext.fillOval(30,30,300,300);



        //组件图,树形结构组件图
        AnchorPane anchorPane=new AnchorPane();
        anchorPane.getChildren().add(canvas);



        Scene scene=new Scene(anchorPane,500,500);

        primaryStage.setScene(scene);//设置场景


        primaryStage.setTitle("窗口");//标题
        primaryStage.show();
    }

}

绘制一条线:

package org.example;

import javafx.application.Application;
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.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;


/**
 * fxml的运用:现实视图、控制器、java代码就实现了分离,主类里面的代码会非常简介
 *
 */
public class Canvas1 extends Application {
    public static final double WIDTH=800,HEIGHT=600;
    private Canvas canvas=new Canvas(WIDTH,HEIGHT);
    //GraphicsContext对象操作绘制
    private GraphicsContext graphicsContext=canvas.getGraphicsContext2D();

    private double x;//记录x轴坐标

    private double y;


    public static void main(String[] args) {
        System.out.println("Hello world!");
        //入口函数调用lanch方法,launch会自动的调用start方法
        Application.launch(args);
    }


    @Override
    public void start(Stage primaryStage) throws Exception {//窗口Stage

        //窗口是否可以改变大小
        primaryStage.setResizable(true);

        canvas.setLayoutX(0);
        canvas.setLayoutY(0);

        //添加鼠标落下的事件
        canvas.setOnMousePressed(event -> {
            x =event.getX();
            y =event.getY();
        });

        //鼠标拖拽移动的时候
        canvas.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                //绘制一条线 记录初始坐标和结束坐标,我们这里只记录结束坐标,然后在绘制的过程中把运动中的坐标设置到起始的上面
                double x2=event.getX();//结束坐标x
                double y2=event.getY();//结束坐标y

                graphicsContext.strokeLine(x,y,x2,y2);

                //把起始位置变成第二位置
                x=x2;
                y=y2;
            }
        });



        //组件图,树形结构组件图
        AnchorPane anchorPane=new AnchorPane();
        anchorPane.getChildren().add(canvas);



        Scene scene=new Scene(anchorPane,500,500);

        primaryStage.setScene(scene);//设置场景


        primaryStage.setTitle("窗口");//标题
        primaryStage.show();
    }

}

绘制矩形:

package org.example;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;


/**
 * fxml的运用:现实视图、控制器、java代码就实现了分离,主类里面的代码会非常简介
 *
 */
public class Canvas2 extends Application {
    public static final double WIDTH=800,HEIGHT=600;
    private Canvas canvas=new Canvas(WIDTH,HEIGHT);
    //GraphicsContext对象操作绘制
    private GraphicsContext graphicsContext=canvas.getGraphicsContext2D();

    private double x;//记录x轴坐标

    private double y;

    private WritableImage image=null;//快照保存变量


    public static void main(String[] args) {
        System.out.println("Hello world!");
        //入口函数调用lanch方法,launch会自动的调用start方法
        Application.launch(args);
    }


    @Override
    public void start(Stage primaryStage) throws Exception {//窗口Stage

        //窗口是否可以改变大小
        primaryStage.setResizable(true);

        canvas.setLayoutX(0);
        canvas.setLayoutY(0);

        //添加鼠标落下的事件 鼠标按下事件
        canvas.setOnMousePressed(event -> {
            x =event.getX();
            y =event.getY();
        });

        //鼠标拖拽移动的时候,鼠标拖拽事件
        canvas.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                //绘制矩形
                double startx=x;
                double starty=y;
                double endx=event.getX();//结束坐标x
                double endy=event.getY();//结束坐标y

                //往上画是画不出来的,因为起始坐标是拖拽中的坐标而不是落下去的,加个判断
                if(endx <startx){
                    startx=endx;
                    endx=x;
                }
                if(endy <starty){
                    starty=endy;
                    endy=y;
                }

                //宽高
                double width=endx-startx;
                double height=endy-starty;

                //清理实时的拖拽,把绘制中的东西擦掉
                graphicsContext.clearRect(0,0,WIDTH,HEIGHT);

                //清理实时绘制的东西之后呢,先把上一个保存的快照画画上去,再画现在画的   drawImage:绘制图片的功能
                graphicsContext.drawImage(image,0,0,WIDTH,HEIGHT);

                //绘制矩形
                graphicsContext.strokeRect(startx,starty,width,height);


            }
        });

        //绘制的时候会把绘制的第一个清理掉,因为进行了实时清理绘制过程的东西,
        // 我们可以在松开手的时候把画布做一个快照保存起来,清理掉之后呢,先把快照画上去,然后在绘制图形
        //鼠标松开手事件
        canvas.setOnMouseReleased(event -> {
            image=canvas.snapshot(null,null);//获取快照
        });



        //组件图,树形结构组件图
        AnchorPane anchorPane=new AnchorPane();
        anchorPane.getChildren().add(canvas);



        Scene scene=new Scene(anchorPane,500,500);

        primaryStage.setScene(scene);//设置场景


        primaryStage.setTitle("窗口");//标题
        primaryStage.show();
    }

}

(5)Canvas保存图片文件

 

保存图片需要转换成BufferImage才可以保存:下面这个可以转换 

 

打开文件的窗口和保存文件的窗口: 

canvas.getScene():获取场景 

canvas.getScene().getWindows():获取主窗口stage

 

(6)Canvas开发游戏的基本思路

开发游戏要实现对用户的操作进行响应,当用户按下键盘的上下左右箭头的时候,这个角色要进行相应的移动,也就是坐标要进行更改,第二个就是屏幕的刷新

屏幕刷新:

 

package org.example;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;


/**
 * fxml的运用:现实视图、控制器、java代码就实现了分离,主类里面的代码会非常简介
 *
 */
public class CanvasYx extends Application {
    public static final double WIDTH=800,HEIGHT=600;
    private static Canvas canvas=new Canvas(WIDTH,HEIGHT);
    //GraphicsContext对象操作绘制
    private GraphicsContext graphicsContext=canvas.getGraphicsContext2D();

    //定义变量控件方法需要改变坐标的
    private Image backgrouund=new Image("/images/baise.png");
    private Image self=new Image("/images/chi.png");

    private double x=400,y=300;//记录xy轴坐标


    static {
        canvas.setLayoutX(0);
        canvas.setLayoutY(0);
    }

    //绘制游戏场景的方法
    private void paint(){
        graphicsContext.drawImage(backgrouund,0,0);
        graphicsContext.drawImage(self,x,y);
    }
    //屏幕刷新的方法
    private void update(){
        AnimationTimer animationTimer=new AnimationTimer() {
            @Override
            public void handle(long now) {
                paint();
            }
        };
        animationTimer.start();
    }



    public static void main(String[] args) {
        System.out.println("Hello world!");
        //入口函数调用lanch方法,launch会自动的调用start方法
        Application.launch(args);
    }


    @Override
    public void start(Stage primaryStage) throws Exception {//窗口Stage

        //启动的时候先调用绘制
        //paint();

        //屏幕刷新
        update();

        //窗口是否可以改变大小
        primaryStage.setResizable(true);


        //组件图,树形结构组件图
        AnchorPane anchorPane=new AnchorPane();
        anchorPane.getChildren().add(canvas);



        Scene scene=new Scene(anchorPane);

        scene.setOnKeyPressed(event -> {
            KeyCode keyCode=event.getCode();//获取键盘按键
            switch (keyCode){
                case UP:
                    y-=5;
                    System.out.println("y-=5");
                    break;
                case DOWN:
                    y+=5;
                    System.out.println("y+=5");
                    break;
                case LEFT:
                    x-=5;
                    System.out.println("x-=5");
                    break;
                case RIGHT:
                    x+=5;
                    System.out.println("x+=5");
                    break;
            }
        });


        primaryStage.setScene(scene);//设置场景

        primaryStage.setTitle("窗口");//标题
        primaryStage.show();
    }

}

移动: 

 

(7)javaFX多媒体播放

多媒体对象:

一些多媒体文件的属性参数 

Media需要放在MediaPlayer里

 

视频需要放在MediaView里面,才能显示画面,音频就不需要了

 

vSlider使用的是外部的 带三方库

 

mediaPlayer.setOnReady():我们做响应加载好之后再进行功能的绑定

 

 

做一个音量绑定,跟vSlider进行双向绑定

此时拖拽视频是没有画面的:需要处理

 

需要把mediaPlayer放发哦mView中

设置一下进度条:

 点击暂停程序就退出了,更改一下:

此时进度条拖拽是无效的:

给进度设置点击事件来更改进度

就实现了拖拽播放 

可以更改下拖拽是的秒提示:

可以手写,也可以使用源代码的转换

 

(8)media包里的AudioClip类

他也是media包里的,他可以独立的播放,但是media必须放在一个mediaPlayer里面,他其实是一个音频片段,一旦调用了play方法他只能调用stop停止,不能进行其他操作,调用之前可以设置它的音量,还有其他的简单设置,这个类适合做一些音效,游戏的音效

点击就会触发ka的一声音效

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喵俺第一专栏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值