内含一点学习 Java 和 JavaFX 的笔记
前言
这学期有个大作业,是写一个有点类似于消消乐的游戏。写这篇文章算是为了庆祝一下我将近 60 个小时的工作。大概是因为担心查重检测等问题,不允许我们把代码发布到公共的代码仓库,那这里就放个视频吧。 评完分了应该就可以公开 代码 了吧.
一点 JavaFX 的笔记
写 JavaFX 还算是踩了点坑,这里记录下吧。
JavaFX 的 API Document 是非常好的一个地方,每个方法的描述都比较详细。如果想找为了实现某个功能要用到哪个方法,或者是单纯的想要知道这个方法是干什么的话可以选择先翻看这个,能比直接 Google 还省事的。
Listener
这个东西算是我一开始最头疼的东西了。其实上课的时候就不是特别理解,靠着看笔记和照葫芦画瓢算是理解了点皮毛。这里说的 Listener 不是一个 property 带有的 listener(比如 setOnChangeListener
), 而是我们自定的,用于在不同的 component 之间进行沟通的。Listener 其实就是以 anonymous class 的形式实现了一个 interface 的 method, 然后把实现出来的这个类注入到了我们要监听的类里面去。我们在被监听类里适宜时 call 被注入进去的 listener.
举个例子来说明下。假设我们有一个 IM,从 WebSocket
这个 class 中 获取到消息。消息分为两类:一类是普通消息,就是单纯的聊天消息;还有一种是指令消息,会对我们 IM 的运行状态进行控制,比如要求在 AppUI
中进行处理后,决定是直接显示在 UI 上,还是交给 AppCore
进行处理。interface NewMsgListener
是我的 listener, 它来负责 AppCore
和 Websocket
的交互,所以这两个 class 不需要依赖对方。
NewMsgListener.java
> /** > * 这是我的 Listener. 它就是单纯的一个 interface, 有且仅有一个方法。 > * 我们可以稍后使用 lambda expression 初始化它. > * 当然你可以定义更多方法,但是没啥必要。而且在那种情况下完全可以再创建一个 Listener > */ > public interface NewMsgListener { > public void setOnNewMsg(String msg); > } >
WebSocket.java
> /** > * 这个类负责连接到 ws 服务器获取信息 > */ > public class WebSocket { > private ArrayList<NewMsgListener> listeners; > > public WebSocket() {} > public void connect() {} > > public void addMsgListener(NewMsgListener listenr) { > this.listeners.add(listener); > } > > public void msgReceived() { > // 设定 `msg` 作为收到的信息 > for (int i = 0; i < this.listeners.size(); i ++) { > this.listeners.setOnNewMsg(); > } > } > } >
AppUI.java
> /** > * 这个类负责连接到 ws 服务器获取信息 > */ > public class AppUI { > private final WebSocket ws; > public AppUI() { > this.ws = new WebSocket(); > this.ws.connect(); > > this.ws.addMsgListener((msg) -> { > if (msg.starts("MSG")) { > // Do Something > } > }) > } > } >
GridPane
我一开始用 GirdPane
的时候不太理解怎么用它来布置布局。我们创建的 GirdPane
一开始都是没有 row 和 column 的限制。往一个 GridPane 里面增加新的 Node 时可以指定它的位置(通过传入这个 Node 的 row 和 column),也可选的限定这个 Node 可以扩展多少 row 和 column(不设定的话默认为 1). 我们也可以通过创建 ColumnConstrains
/RowConstrains
然后加入 GridPane 的方式来调账每一行、列的大小。
// 这是我比较喜欢使用的两个增加 node 的方法
newGridPane.add(Node child, int columnIndex, int rowIndex);
newGridPane.add(Node child, int columnIndex, int rowIndex, int colspan, int rowspan);
// 这样来限制每个 column 的宽度
ColumnConstraints column1 = new ColumnConstraints();
column1.setPercentWidth(50);
ColumnConstraints column2 = new ColumnConstraints();
column2.setPercentWidth(50);
newGridPane.getColumnConstraints().addAll(column1, column2); // each get 50% of width
在上面这个例子里,我们创建了两个 ColumnConstrains
,并且每个都占比 50%. 这样情况下,我们得到的结果就会是只有在 column 0 和 1 的 Node 会被显示出来。我们可以把他们的占比分别调整为 10% 和 20%, 这样还有 70% 的空间留给剩下的 column, 并且不需要创建第三个占比为 70% 的 ColumnConstrains
并增加进去(当然,你让 column 2 占比 70% 的话除外). JavaFX 会自动帮我们分配。
ListProperty 和 ObservableList
就我目前使用到的功能来讲,他们的区别在于,当给 ListProperty
注入 setOnChange
listener 后,只要这个 ListProperty 里包含的 child 发生了变动,listener 就会被调用。而这个功能在 ObservableList
中实现,需要整个 list 都被重新赋值。
在 Canvas 上画一个阴影效果
这个是可以通过 for-loop 来实现的。可以先使用针对 Color
的 instance color
使用 .darker
方法得到一个比 color
暗一点的颜色,再用 for-loop 画以这个颜色画出对应的梯形/弧形来。因为怕代码查重的问题,这里就不放例子了。
最后
暂时想不起来别的坑了,日后如果再遇到一些问题,或者是想起来别的值得记录的问题的话,就再加进去。虽然以我的记性,不要指望太多就是了。
除另有声明外,本博客文章均采用 知识共享(Creative Commons) 署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。