目录:
(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的一声音效