1. 新增了多窗口切换功能

2. 新增多个example示例可供使用参考
3. 修正信号收发机制的bug
4. 规范化部分代码,并加以部分注释
5. 修改README
This commit is contained in:
suisui
2019-12-10 23:04:44 +08:00
parent 5cc7e57a88
commit c0684c7501
44 changed files with 1438 additions and 1528 deletions

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

2
.idea/compiler.xml generated
View File

@@ -15,7 +15,7 @@
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="JavaFx-Plus" options="-bootclasspath C:/java/jdk/jre\lib\rt.jar;C:/java/jdk/jre\lib\jce.jar -Xlint:deprecation" />
<module name="JavaFx-Plus" options="-bootclasspath /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/jre\lib\rt.jar;/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/jre\lib\jce.jar -Xlint:deprecation" />
</option>
</component>
</project>

8
.idea/dictionaries/suisui.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<component name="ProjectDictionaryState">
<dictionary name="suisui">
<words>
<w>biubiusuisui</w>
<w>scau</w>
</words>
</dictionary>
</component>

1231
.idea/workspace.xml generated
View File

File diff suppressed because it is too large Load Diff

514
README.md
View File

@@ -1,44 +1,54 @@
# JavaFX-Plus
- [JavaFX-Plus](#javafx-plus)
* [前言](#--)
+ [开发进程](#----)
* [特色](#--)
+ [信号机制](#----)
+ [JavaBean 和 JavaFxBean](#javabean---javafxbean)
+ [可拖动窗口和可伸缩窗口](#-----------)
+ [Spring支持](#spring--)
+ [数据表达式绑定](#-------)
- [Bean和View绑定](#bean-view--)
- [View和View绑定](#view-view--)
+ [模块化开发](#-----)
- [介绍](#--)
- [如何创建模块](#------)
- [scenebuilder中导入刚刚生成的上面的控件](#scenebuilder-------------)
* [如何使用这个框架](#--------)
+ [内置注解](#----)
+ [两个工厂和一个context](#-------context)
* [创建第一个程序](#-------)
* [前言](#前言)
+ [开发进程](#开发进程)
* [Maven仓库地址](#Maven仓库地址)
* [框架功能描述](#框架功能描述)
+ [模块化开发](#模块化开发)
- [介绍](#介绍)
- [如何创建模块](#如何创建模块)
- [scenebuilder中导入刚刚生成的上面的控件](#scenebuilder中导入刚刚生成的上面的控件)
+ [与Spring的融合](#与Spring的融合)
+ [信号机制](#信号机制)
+ [JavaBean与JavaFXBean的转换](#JavaBean与JavaFXBean的转换)
+ [可拔插功能](#可拔插功能)
+ [数据绑定](#数据绑定)
- [Bean和View绑定](#Bean和View绑定)
- [View和View绑定](#View和View绑定)
- [函数表达式绑定](#函数表达式绑定)
+ [多窗口切换功能](#多窗口切换功能)
* [框架的使用](#框架的使用)
+ [内置注解](#内置注解)
+ [两个工厂和一个context](#两个工厂和一个context)
* [创建第一个程序](#创建第一个程序)
## 前言
这个框架不是UI美化框架为了简化javaFX项目开发、为了减少项目之间组件耦合而打造的框架。目前框架主要功能如下图所示
这个框架不是UI美化框架为了简化javaFX项目开发、为了减少项目之间组件耦合而打造的框架。目前框架主要功能如下图所示
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/155142_1235eb9c_2067650.png "JavaFX-Plus.png")
![输入图片说明](doc/JavaFx-Plus.png)
### 开发进程
2019年11月25日起项目暂停更新将会下次发布将会升级为2.0版本,到时候将会提供更多数据绑定操作,以及优化性能。
- [x] 模块化
- [x] 与Spring的融合
- [x] 信号机制
- [x] 数据绑定
- [x] spring结合
- [x] JavaBean和JavaFXBean的转换
- [x] 可拔插功能(窗口拖动等功能)
- [x] 数据绑定
- [x] Bean和View的绑定
- [x] View和View的绑定
- [x] 函数表达式绑定
- [x] 多窗口切换功能
- [ ] 事件注解绑定
- [ ] 函数表达式绑定
- [ ] 数据校验
- [ ] 键盘事件绑定
- [ ] 优化性能
## 仓库地址
## Maven仓库地址
```xml
<dependency>
@@ -49,51 +59,130 @@
```
## 特色
## 框架功能描述
### 模块化开发
#### 介绍
在Java开发过程中很多界面是相似或者重复的如果能够将这些界面打包成为一个自定义控件并且通过Scenebuilder拖动就能产生一个控件那将会大大提高我们的开发效率。所以我们提出将不同区域划分为不同的子模块已达到减少耦合和加速并行开发。一般我们经常把界面分为顶部工具栏左边导航栏右侧的内容栏如果全部内容都写在一个Controller那么将会导致十分臃肿我们希望将不同的区域划分开来分而治之。
#### 如何创建模块
只要新建一个类继承自FXBaseController而FXBaseController是继承于Pane这就是JavaFX-Plus的设计思想之一切皆为Pane。在类上标上FXController注解提供FXML文件的地址。如果设置为FXWindow那么将会把这个Controller以单独的Window显示这里仅仅几句代码就实现了一个简单的窗口程序。
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/022014_83ecdbde_2067650.png "controllerConfig.png")
图2 Controller配置
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/022024_71892db3_2067650.png "demo1.png")
图3 显示结果
#### scenebuilder中导入刚刚生成的上面的控件
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/022036_e128f313_2067650.gif "modulesAction.gif")
图4 模块化操作
### 与Spring的融合
可以快速支持Spring和这个框架的融合只需要一行代码就可将实例的生成控制转交给容器管理。
代码如下:
```java
@FXScan(base = {"cn.edu.scau.biubiusuisui.example.springDemo"})
public class SpringDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //启动spring
FXPlusApplication.start(SpringDemo.class, new BeanBuilder() {
@Override
public Object getBean(Class type) {
return context.getBean(type); //接管FXPlus属性的创建
}
});
}
}
```
### 信号机制
有两个主要标签一个是FXSender这个标签作用在方法上,标记这个方法为信号发射方法。可以通过设置name修改这个信号发射方法的名称,默认是函数名字。
有两个主要标签一个是FXSender这个标签作用在函数上,标记这个方法为信号发射函数。可以通过设置name修改这个信号发射函数的名称,默认是函数名字。
发射信号会被订阅这个发射函数的所有FXReceiver接收并且发射函数的返回值会作为参数传进这个函数之中。而且这种发送和接关系是全局的只要是注册了的Controller都可以进行接不局限于同一个Controller。
发射信号会被订阅这个发射函数的所有FXReceiver接收并且发射函数的返回值会作为参数传进这个函数之中。而且这种发送和接关系是全局的只要是注册了的Controller都可以进行接不局限于同一个Controller。
我们通过一个简单的代码来理解一下。
我们通过一个简单的代码来理解一下主要实现自定义组件导航栏TopBar主界面中包含该组件当用户点击导航栏某些按钮时能返回主界面相关信息。fxml文件详见resources下的mqDemo文件夹
1. 利用JavaFX的模块化我们设计一个简单的导航栏
```java
@FXController(path = "Main.fxml")
@FXWindow(title = "demo1")
public class MainController extends FXBaseController{
@FXController(path = "mqDemo/topBar.fxml")
public class TopBarController extends FXBaseController {
@FXML
Button btn;
public void indexClick() {
sendToMain("点击[首页]");
}
@FXML
Label label;
public void scoreClick() {
sendToMain("点击[积分中心]");
}
@FXML
public void questionClick() {
sendToMain("点击[问答中心]");
}
@FXML
public void selfClick() {
sendToMain("点击[个人中心]");
}
/**
鼠标之后,系统通过发射信号,调用所有订阅这个发射信号函数的方法响应信号
*/
@FXML //绑定鼠标点击事件
@FXSender //标注为信号发射函数
public String send(){
System.out.println("before sending"); //输出 before sending
return "sending msg";
* 系统通过发射信号,调用所有订阅这个发射信号函数的方法,从而响应信号
* @param msg
* @return
*/
@FXSender //标注为信号发射函数
public String sendToMain(String msg) {
return msg;
}
/**
接受者必须指定要订阅的发送者类名+方法名
而且发送函数的返回值会注入到接受函数的参数中
*/
@FXReceiver(name = "MainController:send")
public void read(String msg){
System.out.println("read " + msg); //输出 read sending msg
}
}
```
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/022051_db8dbc7a_2067650.gif "signalshow.gif")
### JavaBean 和 JavaFxBean
2. 再设计一个主界面,里面包含导航栏
```java
@FXController(path = "mqDemo/main.fxml")
@FXWindow(mainStage = true, title = "MQDemo")
public class MainController extends FXBaseController {
@FXML
private TextArea outTA;
/**
* 接收者必须指定要订阅的[发送者类名:方法名]
* 发送函数的返回值会注入到接收函数的参数中
*
* @param msg
*/
@FXReceiver(name = "TopBarController:sendToMain")
public void handleTopBar(String msg) {
// TODO: 2019/12/8
// 处理导航栏的点击事件
outTA.appendText(msg + "\n");
}
}
```
![输入图片说明](doc/mqDemo/20191208-194336-signalshow.gif)
### JavaBean与JavaFXBean的转换
一般我们写的JavaBean都是基本类型的但是JavaFXBean的设计哲学是这些属性都应该是JavaFX定义的Property类型这十分不利于我们的开发我们如何在不修改JavaBean的条件下使用到JavaFX的Property的一些优良方法呢答案是我们通过反射获得基本类型对应的Property目前仅限于booleandoubleintegerlongstringfloatList等基本类型不支持封装对象。
@@ -203,8 +292,10 @@ public class Student {
直接操作JavaBean类就会通过动态绑定修改界面不需要讲JavaBean转换为JavaFX Bean可以减少开发中的类型转换。
### 可拖动窗口和可伸缩窗口
在Javafx中如果一个窗口隐藏了标题栏那么这个窗口也就没办法拖动和伸缩了在JavaFX-Plus中你就不需有这种烦恼只需要在@FXWindow中设置
### 可拔插功能
在本框架中实现了窗口可拖动和窗口可伸缩在Javafx中如果一个窗口隐藏了标题栏那么这个窗口也就没办法拖动和伸缩了在JavaFX-Plus中你就不需有这种烦恼只需要在@FXWindow中设置
```java
@FXWindow(title = "demo1",dragable = true,style = StageStyle.UNDECORATED)
```
@@ -215,30 +306,12 @@ public class Student {
![输入图片说明](https://images.gitee.com/uploads/images/2019/0630/135637_cb0e0a89_2067650.gif "resizeAble.gif")
### Spring支持
可以快速支持Spring和这个框架的融合只需要一行代码就可将实例的生成控制转交给容器管理。
代码如下:
```java
@FXScan(base = {"cn.edu.scau.biubiusuisui.example.springDemo"})
public class SpringDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //启动spring
FXPlusApplication.start(SpringDemo.class, new BeanBuilder() {
@Override
public Object getBean(Class type) {
return context.getBean(type); //接管FXPlus属性的创建
}
});
}
}
### 数据绑定
```
与之相关的注解有`@FXBind`注解在JavaFX控件的字段上面标明该变量的绑定方式和绑定属性类似于Vue中的界面绑定。目前已实现Bean和View的绑定、View和View的绑定、函数表达式的绑定
### 数据表达式绑定
#### Bean和View绑定
在JavaFX控件的字段上面添加@FXbind可以绑定属性类似于Vue中的界面绑定但是不同的是这里的绑定可以是普通Bean和View绑定可以是View和View绑定也可以是Bean和Bean绑定不推荐
如下面代码通过FXBind将Studen的姓名与文本框输入内容绑定学生的密码和密码框输入框内容绑定完全简化了数据传递操作代码中完全没有出现界面数据传输到控制器代码。
如下面代码,通过FXBind将Student的姓名与文本框输入内容绑定学生的密码和密码框输入框内容绑定完全简化了数据传递操作代码中完全没有出现界面数据传输到控制器代码
例子:
```java
@@ -253,8 +326,9 @@ public class SpringDemo extends Application {
@FXML
private PasswordField psw;
@FXML
private Label label;
private Label pswMsg;
@FXML
void login(ActionEvent event) {
@@ -272,7 +346,10 @@ public class SpringDemo extends Application {
如图所示:
![输入图片说明](https://images.gitee.com/uploads/images/2019/0724/231705_976181ba_2067650.gif "expression.gif")
#### View和View绑定
```java
@FXBind("text=${psw.text}")
@FXML
@@ -281,62 +358,273 @@ private Label pswMsg;//任何psw中的内容都会同步到pswMsg中
如图所示
![输入图片说明](https://images.gitee.com/uploads/images/2019/0724/232237_7e243f15_2067650.gif "expressionV2V.gif")
### 模块化开发
#### 函数表达式绑定
示例代码可见`cn.edu.scau.biubiusuisui.example.listDemo``cn.edu.scau.biubiusuisui.actionDemo`以下举actionDemo为例。
1. 使用方法
使用在界面Controller类中的JavaFX控件上与以上两种绑定类似`${}`为外部标识,当该绑定属于函数表达式绑定时,需要在函数名前加`@`
```java
@FXBind("text=${@toUs(time.text)}") // 将Label中的text和toUs()函数的返回值绑定
private Label us;
```
2. 示例代码
如以下代码,实现简单的汇率转换器。
```java
@FXController(path = "actionDemo/actionDemo.fxml")
@FXWindow(title = "actionDemo", mainStage = true)
public class MainController extends FXBaseController implements Initializable {
@FXML
@FXBind("text=${@toUs(time.text)}") // 将Label中的text和toUs()函数的返回值绑定
private Label us;
@FXML
@FXBind("text=${@toJp(time.text)}")
private Label jp;
@FXML
@FXBind("text=${@toUk(time.text)}")
private Label uk;
@FXML
private TextField time;
public String toUs(String value) {
double money = Double.valueOf(value);
double percent = 0.1454;
return String.valueOf(money * percent);
}
public String toJp(String value) {
double money = Double.valueOf(value);
double percent = 15.797;
return String.valueOf(money * percent);
}
public String toUk(String value) {
double money = Double.valueOf(value);
double percent = 0.1174;
return String.valueOf(money * percent);
}
}
```
3. 动态演示
如图所示:
![20191210-175409-actionDemo](doc/actionDemo/20191210-175409-actionDemo.gif)
### 多窗口切换功能
#### 介绍
在Java开发过程中很多界面是相似或者重复的如果能够将这些界面打包成为一个自定义控件并且通过Scenebuilder拖动就能产生一个控件那将会大大提高我们的开发效率。所以我们提出将不同区域划分为不同的子模块已达到减少耦合和加速并行开发。一般我们经常把界面分为顶部工具栏左边导航栏右侧的内容栏如果全部内容都写在一个Controller那么将会导致十分臃肿我们希望将不同的区域划分开来分而治之
在JavaFX中常常需要多个窗口之间进行切换比如登录窗口点击登录后跳转至登录成功/失败窗口网上部分有关多窗口切换的JavaFX教程实现过程为在Controller中是实现FXML绑定并通过外部调用某个show方法来切换窗口。由于本框架已经将FXML绑定这一功能封装故通过在Controller内部直接初始化Stage并设置参数这一方法并不现实。因此在本框架中编写StageController类对Controller进行管理
#### 如何创建模块
#### 涉及到的注解
只要新建一个类继承自FXBaseController而FXBaseController是继承于Pane这就是JavaFX-Plus的设计思想之一切皆为Pane。在类上标上FXController注解提供FXML文件的地址。如果设置为FXWindow那么将会把这个Controller以单独的Window显示这里仅仅几句代码就实现了一个简单的窗口程序
`@FXController`标记于类上用于绑定FXML文件需要注意的是标记了`FXController`只能标记这是一个控件
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/022014_83ecdbde_2067650.png "controllerConfig.png")
`@FXWindow`标记于类上标记这个Controller需要以窗口显示只有需要以单独窗口显示时才会被重定向。
图2 Controller配置
`@FXRedirect`:标记于函数上,标记该函数用于处理重定向。
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/022024_71892db3_2067650.png "demo1.png")
#### 规定
图3 显示结果
本框架规定,当需要使用`@FXRedirect`标记函数处理重定向时函数必须是返回String类型的函数且返回已注册的Controller名如需要重定向至登录成功界面控制器为`SuccessController`,则需要写上`return "SuccessController"。
#### scenebuilder中导入刚刚生成的上面的控件
#### 使用方法
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/022036_e128f313_2067650.gif "modulesAction.gif")
1. `FXRedirect`注解的使用如下:
图4 模块化操作
```java
@FXRedirect
public String redirectToRegister() {
return "RegisterController";
}
@FXML
@FXRedirect(close = false) //测试弹窗
public String redirectToDialog() {
return "DialogController";
}
```
## 如何使用这个框架
close是标明是否需要关闭当前的窗口默认为true即默认当跳转另一个窗口时关闭当前窗口。
2. 创建程序初始界面Controller此处举例为登录界面
```java
@FXController(path = "redirectDemo/login.fxml")
@FXWindow(title = "redirectDemo", mainStage = true)
public class LoginController extends FXBaseController {
@FXML
private TextField usernameTF;
@FXML
private PasswordField passwordPF;
@FXML
public void registerClick() {
System.out.println("点击注册.....");
redirectToRegister();
}
@FXRedirect
public String redirectToRegister() {
return "RegisterController";
}
@FXML
@FXRedirect(close = false) //测试弹窗
public String redirectToDialog() {
return "DialogController";
}
}
```
3. 编写需要跳转的界面Controller比如登录时尚无账号跳转至注册界面和测试弹窗的Controller
```java
@FXController(path = "redirectDemo/register.fxml")
@FXWindow(title = "register")
public class RegisterController extends FXBaseController {
@FXML
private TextField usernameTF;
@FXML
private TextField emailTF;
@FXML
private PasswordField passwordPF;
@FXML
private PasswordField confirmPasswordPF;
@FXML
public void registerClick() {
}
@FXML
public void loginClick() {
redirectToLogin();
}
@FXRedirect
public String redirectToLogin() {
return "LoginController";
}
}
```
```java
@FXController(path = "redirectDemo/dialog.fxml")
@FXWindow(title = "弹窗")
public class DialogController extends FXBaseController {
}
```
#### 示例演示
本次示例源码已存于`cn.edu.scau.biubiusuisui.example.redirectDemo`fxml文件于resources下的redirectDemo文件夹中。
1. 跳转至另一个窗口(关闭原窗口)
![](doc/redirectDemo/20191208-125739-close.gif)
2. 弹窗形式弹出窗口(不关闭原窗口)
![](doc/redirectDemo/20191208-125511-not close.gif)
#### 不足之处
暂未实现携带数据的窗口跳转目前只实现纯粹跳转到另一个Controller。
## 框架的使用
### 内置注解
| 名字 | 作用 | 参数 | 要求 |
| ------------- | ------------------------------------------------------------ | --------------------------------------- | -------------------- |
| @FXData | 表面这个普通bean要装配成javafxBean | fx_id | 重新命名 |
| @FXScan | 扫描@FXEntity和@FXController注解标记的类 | 要扫描的目录 | 默认当前目录之下所有 |
| @FXController | 标记这个类为控件 | fxml文件地址 | 无 |
| @FXWindow | 标记这个控件要以单独窗口显示 | title是窗口名字也可以设置窗口长度宽度 | 无 |
| @FXEntity | 标记JavaBean系统会自动识别@FXField然后包装JavaBean为JavaFXBean | 重命名 | |
| @FXField | 代表这个属性要映射为Property属性 | | |
| @FXSender | 信号发送者 | name可以重命名信号 | |
| @FXReceiver | 信号接收函数 | name订阅的发射者函数名 | 不可空 |
| 名字 | 作用 | 参数 | 要求 |
| ------------- | ------------------------------------------------------------ | --------------------------------------- | ---------------------------------------- |
| @FXData | 标明这个普通bean要装配成javafxBean | fx_id | 重新命名 |
| @FXScan | 扫描@FXEntity和@FXController注解标记的类 | 要扫描的目录 | 默认当前目录之下所有 |
| @FXController | 标记这个类为控件 | pathfxml文件地址 | 无 |
| @FXWindow | 标记这个控件要以单独窗口显示 | title是窗口名字也可以设置窗口长度宽度 | 无 |
| @FXEntity | 标记JavaBean系统会自动识别@FXField然后包装JavaBean为JavaFXBean | 重命名 | |
| @FXField | 代表这个属性要映射为Property属性 | | |
| @FXSender | 信号发送者 | name重命名信号 | |
| @FXReceiver | 信号接收函数 | name订阅的发射者函数名 | 不可空 |
| @FXRedirect | 标记函数为重定向函数 | close是否关闭当前窗口 | 返回值为某个使用了FXView注解的Controller |
### 两个工厂和一个context
1. 两个工厂
在JavaFX-Plus中所有Controller对象和FXEnity对象都必须通过工厂创建。
```
```java
student = (Student) FXEntityFactory.getInstance().createJavaBeanProxy(Student.class); //工厂产生一个学生
```
通过工厂创建JavaBean在创建同时工厂会对JavaBean代理并且包装对应的Property属性。
通过工厂创建JavaBean在创建同时工厂会对JavaBean代理并且包装对应的Property属性。
```
```java
MainController mainController = (MainController)FXFactory.getFXController(MainController.class);
```
2. 一个context
存储所有用@FXController注解后的Controller和FXEntity的代理类。
```java
public class FXPlusContext {
private FXPlusContext(){}
private static Map<String, List<FXBaseController>> controllerContext = new ConcurrentHashMap<>(); //FXController控制器注册表
private static Map<Object, FXEntityProxy> beanMap = new ConcurrentHashMap<>(); // Object注册为FXEntityObject
public static void addController(FXBaseController fxBaseController){
List<FXBaseController> controllers = controllerContext.get(fxBaseController.getName());
if(controllers == null){
controllers = new LinkedList<>();
}
controllers.add(fxBaseController);
}
public static List<FXBaseController> getControllers(String key){
return controllerContext.get(key);
}
public static FXEntityProxy getProxyByBeanObject(Object object){
return beanMap.get(object);
}
public static void setProxyByBeanObject(Object object,FXEntityProxy fxEntityProxy){
beanMap.put(object,fxEntityProxy);
}
}
```
## 创建第一个程序
1. 主程序类。
```java
@FXScan(base = {"cn.edu.scau.biubiusuisui.example"}) //会扫描带FXController和FXEntity的类进行初始化
public class Demo extends Application {
@@ -347,24 +635,20 @@ public class Demo extends Application {
}
```
接下来我们生成FXML和Controller
2. 接下来我们生成FXML和Controller
```java
@FXController(path = "Main.fxml")
@FXWindow(title = "demo1")
public class MainController extends FXBaseController{
@FXML
private ResourceBundle resources;
@FXML
private URL location;
@FXML
private Button addBtn;
@FXML
private Button delBtn;
@FXML
private ListView<String> list;
@@ -382,9 +666,9 @@ public class MainController extends FXBaseController{
@Override
public void initialize() {
student = (Student) FXEntityFactory.createJavaBeanProxy(Student.class);
Property property = FXPlusContext.getEntityPropertyByName(student, "list");
list.itemsProperty().bind(property);
student = (Student) FXEntityFactory.createJavaBeanProxy(Student.class); // 从工厂中拿到将JavaBean转换得到的JavaFXBean
Property listProperty = FXPlusContext.getEntityPropertyByName(student, "list");
list.itemsProperty().bind(listProperty);
}
}
@@ -396,7 +680,7 @@ Studen类的定义如下
@FXEntity
public class Student {
@FXField
@FXField //标记该属性是否被生成对应的Property
private String name;
@FXField
@@ -411,6 +695,8 @@ public class Student {
}
```
请注意FXML文件的根标签必须为`<fx:root>`。
```xml
<?xml version="1.0" encoding="UTF-8"?>

BIN
doc/JavaFX-Plus.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

View File

@@ -0,0 +1,17 @@
package cn.edu.scau.biubiusuisui.annotation;
import java.lang.annotation.*;
/**
* @author suiyu_yang
* @description 重定向的注解
* @date 2019/12/3 12:53
* @email suiyu_yang@163.com
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface FXRedirect {
boolean close() default true;
}

View File

@@ -8,17 +8,16 @@ import cn.edu.scau.biubiusuisui.factory.FXControllerFactory;
import cn.edu.scau.biubiusuisui.function.FXWindowParser;
import cn.edu.scau.biubiusuisui.utils.ClassUtils;
import java.util.List;
import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @Author jack
* @Date:2019/6/25 2:54
*/
public class FXPlusApplication {
public class FXPlusApplication {
private static FXWindowParser windowAnnotationParser = new FXWindowParser();
@@ -26,26 +25,26 @@ public class FXPlusApplication {
private static BeanBuilder beanBuilder;
public static boolean IS_SCENE_BUILDER = true;
public static boolean IS_SCENE_BUILDER = true;
public static void start(Class clazz, BeanBuilder beanBuilder){
public static void start(Class clazz, BeanBuilder beanBuilder) {
IS_SCENE_BUILDER = false;
FXPlusApplication.beanBuilder = beanBuilder;
Annotation []annotations = clazz.getDeclaredAnnotations();
for(Annotation annotation : annotations){
if(FXScan.class.equals(annotation.annotationType())){
String []dirs = ((FXScan)annotation).base();
Annotation[] annotations = clazz.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
if (FXScan.class.equals(annotation.annotationType())) {
String[] dirs = ((FXScan) annotation).base();
Set<String> sets = new HashSet<>();
for(String dir : dirs){
for (String dir : dirs) {
sets.add(dir);
}
Set<String> classNames = new HashSet<>();
for(String dir:sets){
for (String dir : sets) {
ClassUtils classUtils = new ClassUtils();
List<String> temps = classUtils.scanAllClassName(dir);
for(String className:temps){
for (String className : temps) {
try {
loadFXPlusClass(className,beanBuilder);
loadFXPlusClass(className, beanBuilder);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
@@ -54,14 +53,15 @@ public class FXPlusApplication {
}
}
}
public static void start(Class clazz){
start(clazz,DEFALUT_BEAN_FACTORY);
public static void start(Class clazz) {
start(clazz, DEFALUT_BEAN_FACTORY);
}
private static void loadFXPlusClass(String className,BeanBuilder beanBuilder) throws ClassNotFoundException {
private static void loadFXPlusClass(String className, BeanBuilder beanBuilder) throws ClassNotFoundException {
Class clazz = Class.forName(className);
if(clazz.getAnnotation(FXWindow.class)!=null) {
FXControllerFactory.loadMainStage(clazz, beanBuilder);
if (clazz.getAnnotation(FXWindow.class) != null) {
FXControllerFactory.loadStage(clazz, beanBuilder);
}
}
}

View File

@@ -1,10 +1,10 @@
package cn.edu.scau.biubiusuisui.entity;
import cn.edu.scau.biubiusuisui.annotation.FXController;
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
import cn.edu.scau.biubiusuisui.config.FXMLLoaderPlus;
import cn.edu.scau.biubiusuisui.config.FXPlusApplication;
import cn.edu.scau.biubiusuisui.utils.StringUtils;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
@@ -17,31 +17,25 @@ import java.lang.annotation.Annotation;
*/
/**
* In JavaFX-Plus Framework Controller
* We use MVC model
* V means view which stand for fxml
* C means controller which stand for FXBaseController instance
* M means model which is base cn.edu.scau.biubiusuisui.entity in your program
* Every BaseController has a name which is used for identifying different <strong>instance</strong>
*
* In JavaFX-Plus Framework Controller
* We use MVC model
* V means view which stand for fxml
* C means controller which stand for FXBaseController instance
* M means model which is base cn.edu.scau.biubiusuisui.entity in your program
* Every BaseController has a name which is used for identifying different <strong>instance</strong>
*/
public class FXBaseController extends Pane {
public class FXBaseController extends Pane {
protected String name = "";
private Stage stage;
private boolean isController = false;
private boolean isWindow = false;
private boolean isWindows = false;
public FXBaseController(String name){
public FXBaseController(String name) {
this.name = name;
}
public FXBaseController(){
public FXBaseController() {
FXController fxController = null;
Annotation[] annotations = getClass().getAnnotations();
// Find FXController cn.edu.scau.biubiusuisui.annotation
@@ -50,36 +44,52 @@ public class FXBaseController extends Pane {
fxController = (FXController) annotation;
isController = true;
}
// 添加赋予是否为窗口的逻辑
if (annotation.annotationType().equals(FXWindow.class)) {
isWindow = true;
}
}
//load fxml file to show panel in scene builder
if(isController && FXPlusApplication.IS_SCENE_BUILDER == true) {
if (isController && FXPlusApplication.IS_SCENE_BUILDER == true) {
FXMLLoaderPlus fxmlLoader = new FXMLLoaderPlus(getClass().getClassLoader().getResource(fxController.path()));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
fxmlLoader.setShow(true);
System.out.println("?");
// System.out.println("?");
try {
fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void initialize() {
}
public String getName() {
if("".equals(name)){
return StringUtils.getBaseClassName(getClass().getSimpleName());
}else{
return StringUtils.getBaseClassName(getClass().getSimpleName()) +"#"+name;
/**
* 唤起舞台
*/
public void showStage() {
if (isWindow) {
this.stage.show();
}
}
public void closeStage() {
if (isWindow) {
this.stage.close();
}
}
public String getName() {
if ("".equals(name) || name == null) { // 原本无“name == null”判断条件会出错
return StringUtils.getBaseClassName(getClass().getSimpleName());
} else {
return StringUtils.getBaseClassName(getClass().getSimpleName()) + "#" + name;
}
}
public void doInit(){}
public void setName(String name) {
this.name = name;
@@ -93,12 +103,12 @@ public class FXBaseController extends Pane {
isController = controller;
}
public boolean isWindows() {
return isWindows;
public boolean isWindow() {
return isWindow;
}
public void setWindows(boolean windows) {
isWindows = windows;
public void setWindow(boolean window) {
isWindow = window;
}
public Stage getStage() {

View File

@@ -4,10 +4,11 @@ import cn.edu.scau.biubiusuisui.annotation.FXField;
import javafx.beans.property.Property;
/**
* 将Controller中的JavaFX的field包装成FXFieldWrapper
* @Author jack
* @Date:2019/6/28 10:03
*/
public class FXFieldWarpper {
public class FXFieldWrapper {
private FXField fxField;

View File

@@ -1,7 +1,6 @@
package cn.edu.scau.biubiusuisui.entity;
import cn.edu.scau.biubiusuisui.proxy.FXEntityProxy;
import javafx.beans.property.Property;
import java.util.LinkedList;
import java.util.List;
@@ -44,5 +43,4 @@ public class FXPlusContext {
public static void setProxyByBeanObject(Object object,FXEntityProxy fxEntityProxy){
beanMap.put(object,fxEntityProxy);
}
}

View File

@@ -1,7 +1,6 @@
package cn.edu.scau.biubiusuisui.example.actionDemo;
import cn.edu.scau.biubiusuisui.annotation.FXScan;
import cn.edu.scau.biubiusuisui.annotation.FXSender;
import cn.edu.scau.biubiusuisui.config.FXPlusApplication;
import javafx.application.Application;
import javafx.stage.Stage;

View File

@@ -2,27 +2,25 @@ package cn.edu.scau.biubiusuisui.example.actionDemo;
import cn.edu.scau.biubiusuisui.annotation.FXBind;
import cn.edu.scau.biubiusuisui.annotation.FXController;
import cn.edu.scau.biubiusuisui.annotation.FXData;
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import java.text.SimpleDateFormat;
import java.net.URL;
import java.util.ResourceBundle;
/**
* @Author jack
* @Date:2019/7/27 1:43
*/
@FXController(path = "actionDemo.fxml")
@FXWindow(title = "actionDemo")
public class MainController extends FXBaseController {
@FXController(path = "actionDemo/actionDemo.fxml")
@FXWindow(title = "actionDemo", mainStage = true)
public class MainController extends FXBaseController implements Initializable {
@FXML
@FXBind("text=${@toUs(time.text)}")
private Label us;
@@ -31,28 +29,43 @@ public class MainController extends FXBaseController {
@FXBind("text=${@toJp(time.text)}")
private Label jp;
@FXML
private TextField time;
@FXML
@FXBind("text=${@toUk(time.text)}")
private Label uk;
public String toUs(String value){
@FXML
private TextField time;
public String toUs(String value) {
double money = Double.valueOf(value);
double percent = 0.1454;
return String.valueOf(money * percent);
}
public String toJp(String value){
public String toJp(String value) {
double money = Double.valueOf(value);
double percent = 15.797;
return String.valueOf(money * percent);
}
public String toUk(String value){
public String toUk(String value) {
double money = Double.valueOf(value);
double percent = 0.1174;
return String.valueOf(money * percent);
}
@Override
public void initialize(URL location, ResourceBundle resources) {
time.setText("0");
time.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if (null == newValue || "".equals(newValue)) {
time.setText("0");
} else if (!newValue.matches("^[0-9]*$")) {
time.setText(oldValue);
}
}
});
}
}

View File

@@ -5,13 +5,10 @@ import cn.edu.scau.biubiusuisui.annotation.FXController;
import cn.edu.scau.biubiusuisui.annotation.FXData;
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import java.util.ArrayList;
@@ -19,29 +16,29 @@ import java.util.ArrayList;
* @Author jack
* @Date:2019/7/27 1:43
*/
@FXController(path = "listDemo.fxml")
@FXWindow(title = "actionDemo",mainStage = true)
@FXController(path = "listDemo/listDemo.fxml")
@FXWindow(title = "listDemo", mainStage = true)
public class MainController extends FXBaseController {
private static int count = 0;
@FXData
User user = new User();
@FXML
@FXBind("items=${@toList(user.names)}")
private ListView<String> list;
private ListView<String> userNameListView;
public ObservableList hello(){
return FXCollections.observableList(new ArrayList<String>(){{add("hello");}});
}
public ObservableList toList(ArrayList list){
return FXCollections.observableList(list);
}
@FXML
public void addName(){
user.addNames("hello");
public void addUserName() {
user.addNames("Jack\t" + (count++));
}
public ObservableList toList(ArrayList list) {
if (list == null) {
return null;
}
return FXCollections.observableList(list);
}
}

View File

@@ -17,20 +17,20 @@ public class User {
@FXField
private String password;
public User() {
names.add("hello ");
names.add("test");
}
public void addNames(String name){
names.add(name);
}
@FXField
private ArrayList<String> names = new ArrayList<>();
public User() {
// names.add("hello ");
// names.add("test");
}
public void addNames(String name) {
names.add(name);
}
public String getName() {
return name;
}

View File

@@ -0,0 +1,20 @@
package cn.edu.scau.biubiusuisui.example.mqDemo;
import cn.edu.scau.biubiusuisui.annotation.FXScan;
import cn.edu.scau.biubiusuisui.config.FXPlusApplication;
import javafx.application.Application;
import javafx.stage.Stage;
/**
* @author suiyu_yang
* @description
* @date 2019/12/8 13:17
* @email suiyu_yang@163.com
*/
@FXScan(base = "cn.edu.scau.biubiusuisui.example.mqDemo")
public class MQDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
FXPlusApplication.start(MQDemo.class);
}
}

View File

@@ -0,0 +1,36 @@
package cn.edu.scau.biubiusuisui.example.mqDemo;
import cn.edu.scau.biubiusuisui.annotation.FXController;
import cn.edu.scau.biubiusuisui.annotation.FXReceiver;
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
/**
* @author suiyu_yang
* @description 主界面
* @date 2019/12/8 13:17
* @email suiyu_yang@163.com
*/
@FXController(path = "mqDemo/main.fxml")
@FXWindow(mainStage = true, title = "MQDemo")
public class MainController extends FXBaseController {
@FXML
private TextArea outTA;
/**
* 接收者必须指定要订阅的[发送者类名:方法名]
* 发送函数的返回值会注入到接收函数的参数中
*
* @param msg
*/
@FXReceiver(name = "TopBarController:sendToMain")
public void handleTopBar(String msg) {
// TODO: 2019/12/8
// 处理导航栏的点击事件
outTA.appendText(msg + "\n");
}
}

View File

@@ -0,0 +1,47 @@
package cn.edu.scau.biubiusuisui.example.mqDemo;
import cn.edu.scau.biubiusuisui.annotation.FXController;
import cn.edu.scau.biubiusuisui.annotation.FXSender;
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
import javafx.fxml.FXML;
/**
* @author suiyu_yang
* @description 导航栏示例
* @date 2019/12/8 13:17
* @email suiyu_yang@163.com
*/
@FXController(path = "mqDemo/topBar.fxml")
public class TopBarController extends FXBaseController {
@FXML
public void indexClick() {
sendToMain("点击[首页]");
}
@FXML
public void scoreClick() {
sendToMain("点击[积分中心]");
}
@FXML
public void questionClick() {
sendToMain("点击[问答中心]");
}
@FXML
public void selfClick() {
sendToMain("点击[个人中心]");
}
/**
* 系统会通过发射信号,调用所有订阅这个发射信号函数的方法,从而响应信号
*
* @param msg
* @return
*/
@FXSender //标注为信号发射函数
public String sendToMain(String msg) {
return msg;
}
}

View File

@@ -0,0 +1,16 @@
package cn.edu.scau.biubiusuisui.example.redirectDemo;
import cn.edu.scau.biubiusuisui.annotation.FXController;
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
/**
* @author suiyu_yang
* @description
* @date 2019/12/4 21:00
* @email suiyu_yang@163.com
*/
@FXController(path = "redirectDemo/dialog.fxml")
@FXWindow(title = "弹窗")
public class DialogController extends FXBaseController {
}

View File

@@ -0,0 +1,43 @@
package cn.edu.scau.biubiusuisui.example.redirectDemo;
import cn.edu.scau.biubiusuisui.annotation.FXController;
import cn.edu.scau.biubiusuisui.annotation.FXRedirect;
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
import javafx.fxml.FXML;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
/**
* @author suiyu_yang
* @description
* @date 2019/12/3 11:53
* @email suiyu_yang@163.com
*/
@FXController(path = "redirectDemo/login.fxml")
@FXWindow(title = "redirectDemo", mainStage = true)
public class LoginController extends FXBaseController {
@FXML
private TextField usernameTF;
@FXML
private PasswordField passwordPF;
@FXML
public void registerClick() {
System.out.println("点击注册.....");
redirectToRegister();
}
@FXRedirect
public String redirectToRegister() {
return "RegisterController";
}
@FXML
@FXRedirect(close = false) //弹窗
public String redirectToDialog() {
return "DialogController";
}
}

View File

@@ -0,0 +1,20 @@
package cn.edu.scau.biubiusuisui.example.redirectDemo;
import cn.edu.scau.biubiusuisui.annotation.FXScan;
import cn.edu.scau.biubiusuisui.config.FXPlusApplication;
import javafx.application.Application;
import javafx.stage.Stage;
/**
* @author suiyu_yang
* @description 测试重定向功能的Application
* @date 2019/12/3 11:52
* @email suiyu_yang@163.com
*/
@FXScan(base = "cn.edu.scau.biubiusuisui.example.redirectDemo")
public class RedirectDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
FXPlusApplication.start(RedirectDemo.class);
}
}

View File

@@ -0,0 +1,46 @@
package cn.edu.scau.biubiusuisui.example.redirectDemo;
import cn.edu.scau.biubiusuisui.annotation.FXController;
import cn.edu.scau.biubiusuisui.annotation.FXRedirect;
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
import javafx.fxml.FXML;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
/**
* @author suiyu_yang
* @description
* @date 2019/12/4 00:07
* @email suiyu_yang@163.com
*/
@FXController(path = "redirectDemo/register.fxml")
@FXWindow(title = "register")
public class RegisterController extends FXBaseController {
@FXML
private TextField usernameTF;
@FXML
private TextField emailTF;
@FXML
private PasswordField passwordPF;
@FXML
private PasswordField confirmPasswordPF;
@FXML
public void registerClick() {
}
@FXML
public void loginClick() {
redirectToLogin();
}
@FXRedirect
public String redirectToLogin() {
return "LoginController";
}
}

View File

@@ -0,0 +1,42 @@
package cn.edu.scau.biubiusuisui.example.redirectDemo;
import cn.edu.scau.biubiusuisui.annotation.FXController;
import cn.edu.scau.biubiusuisui.annotation.FXRedirect;
import cn.edu.scau.biubiusuisui.annotation.FXWindow;
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import java.net.URL;
import java.util.ResourceBundle;
/**
* @author suiyu_yang
* @description 登录成功的Controller
* @date 2019/12/3 12:43
* @email suiyu_yang@163.com
*/
@FXController(path = "redirectDemo/success.fxml")
@FXWindow(title = "success")
public class SuccessController extends FXBaseController implements Initializable {
@FXML
private Label usernameLabel;
@FXML
private Label passwordLabel;
@FXML
@FXRedirect
public String redirectToLogin() {
return "LoginController";
}
@Override
public void initialize(URL location, ResourceBundle resources) {
}
}

View File

@@ -12,13 +12,13 @@ import cn.edu.scau.biubiusuisui.expression.data.ExpressionParser;
import cn.edu.scau.biubiusuisui.function.FXWindowParser;
import cn.edu.scau.biubiusuisui.messageQueue.MessageQueue;
import cn.edu.scau.biubiusuisui.proxy.FXControllerProxy;
import cn.edu.scau.biubiusuisui.stage.StageManager;
import javafx.collections.ObservableMap;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URL;
@@ -92,13 +92,14 @@ public class FXControllerFactory {
FXBaseController fxBaseController = null;
FXBaseController fxControllerProxy = null;
if (fxController != null) {
String name = fxController.path();
fxmlPath = clazz.getClassLoader().getResource(name);
String fxmlPathName = fxController.path();
fxmlPath = clazz.getClassLoader().getResource(fxmlPathName);
FXMLLoaderPlus fxmlLoader = new FXMLLoaderPlus(fxmlPath);
// create a cn.edu.scau.biubiusuisui.proxy for monitoring methods
fxBaseController = (FXBaseController) beanBuilder.getBean(clazz); //获取controller实例
parseData(fxBaseController);
if (fxBaseController != null) {
FXControllerProxy controllerProxy = new FXControllerProxy();
fxControllerProxy = (FXBaseController) controllerProxy.getInstance(fxBaseController); //产生代理从而实现赋能
@@ -114,8 +115,8 @@ public class FXControllerFactory {
fxBaseController.setName(parent.getId());
}
ObservableMap namespace = fxmlLoader.getNamespace();
addDataInNameSpace(namespace, fxBaseController);
scanBind(namespace, fxBaseController);
addDataInNameSpace(namespace, fxBaseController); //处理fxBaseController里面的@FXData
scanBind(namespace, fxBaseController); //处理@FXBind
register(fxBaseController, fxControllerProxy);
} catch (IOException exception) {
throw new RuntimeException(exception);
@@ -136,28 +137,48 @@ public class FXControllerFactory {
*/
private static void register(FXBaseController fxBaseController, FXBaseController fxBaseControllerProxy) {
FXPlusContext.addController(fxBaseController); //保存
MessageQueue.getInstance().registerCosumer(fxBaseController, fxBaseControllerProxy); // 添加进入消息队列 信号功能
MessageQueue.getInstance().registerConsumer(fxBaseController, fxBaseControllerProxy); // 添加进入消息队列 信号功能
}
private static Stage createWindow(FXWindow fxWindow, FXBaseController fxControllerProxy) {
/**
* 为有FXWindow注解的类创建Stage
*
* @param fxWindow
* @param fxBaseControllerProxy
* @return
*/
private static Stage createWindow(FXWindow fxWindow, FXBaseController fxBaseControllerProxy) {
Stage stage = new Stage();
fxControllerProxy.setStage(stage);
double preWidth = fxWindow.preWidth() == 0 ? fxControllerProxy.getPrefWidth() : fxWindow.preWidth();
double preHeight = fxWindow.preHeight() == 0 ? fxControllerProxy.getPrefHeight() : fxWindow.preHeight();
Scene scene = new Scene(fxControllerProxy, preWidth, preHeight);
fxBaseControllerProxy.setStage(stage);
double preWidth = fxWindow.preWidth() == 0 ? fxBaseControllerProxy.getPrefWidth() : fxWindow.preWidth();
double preHeight = fxWindow.preHeight() == 0 ? fxBaseControllerProxy.getPrefHeight() : fxWindow.preHeight();
Scene scene = new Scene(fxBaseControllerProxy, preWidth, preHeight);
stage.setScene(scene);
windowAnnotationParser.parse(stage, fxControllerProxy, fxWindow);
stage.show();
return stage;
windowAnnotationParser.parse(stage, fxBaseControllerProxy, fxWindow);
StageManager.getInstance().registerWindow(fxBaseControllerProxy); //注册舞台
if (fxWindow.mainStage() == true) { //当是主舞台时先show为敬
// System.out.println("FXControllerFactory: "+(fxControllerProxy.getStage() == null));
fxBaseControllerProxy.showStage();
}
return stage;
}
private FXControllerFactory() {
}
public static void loadMainStage(Class clazz, BeanBuilder beanBuilder) {
/**
* 加载舞台
* 原函数名为loadMainStage(Class clazz, BeanBuilder beanBuilder)
*
* @param clazz
* @param beanBuilder
*/
public static void loadStage(Class clazz, BeanBuilder beanBuilder) {
FXWindow declaredAnnotation = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
if ( declaredAnnotation != null && declaredAnnotation.mainStage() == true ) {
//只有当用了FXWindow注解才会注册Stage
if (declaredAnnotation != null) {
getFXWindow(clazz, null, beanBuilder);
}
}
@@ -179,45 +200,50 @@ public class FXControllerFactory {
FXBaseController fxBaseController = getFxBaseController(clazz, controllerName, beanBuilder);
return fxBaseController;
}
public static Stage getFXWindow(Class clazz){
public static Stage getFXWindow(Class clazz) {
FXWindow fxWindow = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
if(fxWindow !=null){
if (fxWindow != null) {
FXBaseController fxController = getFXController(clazz, null, BEAN_BUILDER);
return createWindow(fxWindow, fxController);
}else{
return null;
}
}
public static Stage getFXWindow(Class clazz, BeanBuilder beanBuilder) {
FXWindow fxWindow = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
if(fxWindow !=null){
FXBaseController fxController = getFXController(clazz, null, beanBuilder);
return createWindow(fxWindow, fxController);
}else{
return null;
}
}
public static Stage getFXWindow(Class clazz, String controllerName) {
FXWindow fxWindow = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
if(fxWindow !=null){
FXBaseController fxController = getFXController(clazz, controllerName, BEAN_BUILDER);
return createWindow(fxWindow, fxController);
}else{
} else {
return null;
}
}
public static Stage getFXWindow(Class clazz, String controllerName, BeanBuilder beanBuilder){
public static Stage getFXWindow(Class clazz, BeanBuilder beanBuilder) {
FXWindow fxWindow = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
if(fxWindow !=null){
FXBaseController fxController = getFXController(clazz, controllerName, beanBuilder);
if (fxWindow != null) {
FXBaseController fxController = getFXController(clazz, null, beanBuilder);
return createWindow(fxWindow, fxController);
}else{
} else {
return null;
}
}
private static void parseData(Object object) {
Class clazz = object.getClass();
public static Stage getFXWindow(Class clazz, String controllerName) {
FXWindow fxWindow = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
if (fxWindow != null) {
FXBaseController fxController = getFXController(clazz, controllerName, BEAN_BUILDER);
return createWindow(fxWindow, fxController);
} else {
return null;
}
}
public static Stage getFXWindow(Class clazz, String controllerName, BeanBuilder beanBuilder) {
FXWindow fxWindow = (FXWindow) clazz.getDeclaredAnnotation(FXWindow.class);
if (fxWindow != null) {
FXBaseController fxController = getFXController(clazz, controllerName, beanBuilder);
return createWindow(fxWindow, fxController);
} else {
return null;
}
}
private static void parseData(Object fxControllerObject) {
Class clazz = fxControllerObject.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
FXData annotation = field.getAnnotation(FXData.class);
@@ -225,9 +251,9 @@ public class FXControllerFactory {
field.setAccessible(true);
//建立代理
try {
Object fieldValue = field.get(object);
Object objectProxy = FXEntityFactory.warpFxBean(fieldValue);
field.set(object, objectProxy);
Object fieldValue = field.get(fxControllerObject);
Object fieldValueProxy = FXEntityFactory.wrapFxBean(fieldValue);
field.set(fxControllerObject, fieldValueProxy);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
@@ -270,7 +296,7 @@ public class FXControllerFactory {
private static void parseBind(ObservableMap namespace, Object object, Field field) {
FXBind fxBind = field.getAnnotation(FXBind.class);
field.setAccessible(true);
ExpressionParser expressionParser = new ExpressionParser(namespace,object);
ExpressionParser expressionParser = new ExpressionParser(namespace, object);
if (fxBind != null) {
String[] expressions = fxBind.value();
try {
@@ -286,10 +312,10 @@ public class FXControllerFactory {
}
}
private boolean isFXWindow(Class clazz){
if(clazz.getDeclaredAnnotation(FXWindow.class)!=null){
private static boolean isFXWindow(Class clazz) {
if (clazz.getDeclaredAnnotation(FXWindow.class) != null) {
return true;
}else{
} else {
return false;
}
}

View File

@@ -1,7 +1,7 @@
package cn.edu.scau.biubiusuisui.factory;
import cn.edu.scau.biubiusuisui.annotation.FXField;
import cn.edu.scau.biubiusuisui.entity.FXFieldWarpper;
import cn.edu.scau.biubiusuisui.entity.FXFieldWrapper;
import cn.edu.scau.biubiusuisui.entity.FXPlusContext;
import cn.edu.scau.biubiusuisui.proxy.FXEntityProxy;
import cn.edu.scau.biubiusuisui.utils.ClassUtils;
@@ -11,8 +11,8 @@ import javafx.collections.FXCollections;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.Map;
/**
* @Author jack
@@ -20,28 +20,29 @@ import java.util.List;
*/
public class FXEntityFactory {
private FXEntityFactory(){}
public static Object warpFxBean(Class clazz){
return warpFxBean(clazz, new FXBuilder());
private FXEntityFactory() {
}
public static Object warpFxBean(Class clazz, BeanBuilder beanBuilder) {
public static Object wrapFxBean(Class clazz) {
return wrapFxBean(clazz, new FXBuilder());
}
public static Object wrapFxBean(Class clazz, BeanBuilder beanBuilder) {
Object object = null;
object = beanBuilder.getBean(clazz);
if(object !=null){
return warpFxBean(object);
}else {
if (object != null) {
return wrapFxBean(object);
} else {
return null;
}
}
public static Object warpFxBean(Object object){
public static Object wrapFxBean(Object object) {
FXEntityProxy fxEntityProxy = new FXEntityProxy();
Object objectProxy = null;
try {
objectProxy = fxEntityProxy.getInstance(object);
processFXEntityProxy(object,objectProxy,fxEntityProxy);
objectProxy = fxEntityProxy.getInstance(object); // 初始化代理类
processFXEntityProxy(object, objectProxy, fxEntityProxy);
FXPlusContext.setProxyByBeanObject(objectProxy, fxEntityProxy);
} catch (IllegalAccessException e) {
e.printStackTrace();
@@ -49,28 +50,27 @@ public class FXEntityFactory {
return objectProxy;
}
private static void processFXEntityProxy(Object entity, Object proxy,FXEntityProxy fxEntityProxy) throws IllegalAccessException {
Map<String, FXFieldWarpper> fxFieldWarpperMap = new HashMap<>();
Field []fields = entity.getClass().getDeclaredFields();
for(Field field:fields){
Annotation annotation = ClassUtils.getAnnotationInList( FXField.class,field.getDeclaredAnnotations());
if(annotation != null){
private static void processFXEntityProxy(Object entity, Object proxy, FXEntityProxy fxEntityProxy) throws IllegalAccessException {
Map<String, FXFieldWrapper> fxFieldWrapperMap = new HashMap<>();
Field[] fields = entity.getClass().getDeclaredFields();
for (Field field : fields) {
Annotation annotation = ClassUtils.getAnnotationInList(FXField.class, field.getDeclaredAnnotations());
if (annotation != null) {
Property property = null;
field.setAccessible(true);
FXField fxField = (FXField)annotation;
FXFieldWarpper fieldWarpper = new FXFieldWarpper();
fieldWarpper.setFxField(fxField);
fieldWarpper.setType(field.getType());
if(field.get(entity) == null){
property = getFieldDefalutProperty(field);
}else{
property = getFieldProperty(entity, field);
FXField fxField = (FXField) annotation;
FXFieldWrapper fieldWrapper = new FXFieldWrapper();
fieldWrapper.setFxField(fxField);
fieldWrapper.setType(field.getType());
if (field.get(entity) == null) {
property = getFieldDefalutProperty(field);
} else {
property = getFieldProperty(entity, field);
}
if(property !=null) {
property.addListener((object,oldVal,newVal)->{
if(!fxField.readOnly()) {
if(!List.class.isAssignableFrom(field.getType())) {
if (property != null) {
property.addListener((object, oldVal, newVal) -> {
if (!fxField.readOnly()) {
if (!List.class.isAssignableFrom(field.getType())) {
try {
field.set(proxy, newVal);
} catch (IllegalAccessException e) {
@@ -80,63 +80,62 @@ public class FXEntityFactory {
}
});
}
fieldWarpper.setProperty(property);
fxFieldWarpperMap.put(field.getName(), fieldWarpper);
fieldWrapper.setProperty(property);
fxFieldWrapperMap.put(field.getName(), fieldWrapper);
}
}
fxEntityProxy.setFxFieldWarpperMap(fxFieldWarpperMap);
fxEntityProxy.setFxFieldWrapperMap(fxFieldWrapperMap);
}
private static Property getFieldProperty(Object object,Field field) throws IllegalAccessException {
private static Property getFieldProperty(Object object, Field field) throws IllegalAccessException {
Class type = field.getType();
Object value = field.get(object);
Property property = null;
if(Boolean.class.equals(type) || boolean.class.equals(type)){
if (Boolean.class.equals(type) || boolean.class.equals(type)) {
property = new SimpleBooleanProperty((Boolean) value);
}else if(Double.class.equals(type)||double.class.equals(type)){
} else if (Double.class.equals(type) || double.class.equals(type)) {
property = new SimpleDoubleProperty((Double) value);
}else if (Float.class.equals(type) || float.class.equals(type)){
} else if (Float.class.equals(type) || float.class.equals(type)) {
property = new SimpleFloatProperty((Float) value);
}else if(Integer.class.equals(type) || int.class.equals(type)){
} else if (Integer.class.equals(type) || int.class.equals(type)) {
property = new SimpleIntegerProperty((Integer) value);
}else if(Long.class.equals(type) || long.class.equals(property)){
} else if (Long.class.equals(type) || long.class.equals(property)) {
property = new SimpleLongProperty((Long) value);
}else if(String.class.equals(type)){
} else if (String.class.equals(type)) {
property = new SimpleStringProperty((String) value);
}else if(List.class.isAssignableFrom(type)){
property = new SimpleListProperty(FXCollections.observableList((List)value));
}else if(Object.class.isAssignableFrom(type)){
} else if (List.class.isAssignableFrom(type)) {
property = new SimpleListProperty(FXCollections.observableList((List) value));
} else if (Object.class.isAssignableFrom(type)) {
property = new SimpleObjectProperty(value);
}
return property;
}
private static Property getFieldDefalutProperty(Field field) throws IllegalAccessException{
private static Property getFieldDefalutProperty(Field field) throws IllegalAccessException {
Class type = field.getType();
Property property = null;
if(Boolean.class.equals(type) || boolean.class.equals(type)){
if (Boolean.class.equals(type) || boolean.class.equals(type)) {
property = new SimpleBooleanProperty();
}else if(Double.class.equals(type)||double.class.equals(type)){
} else if (Double.class.equals(type) || double.class.equals(type)) {
property = new SimpleDoubleProperty();
}else if (Float.class.equals(type) || float.class.equals(type)){
} else if (Float.class.equals(type) || float.class.equals(type)) {
property = new SimpleFloatProperty();
}else if(Integer.class.equals(type) || int.class.equals(type)){
} else if (Integer.class.equals(type) || int.class.equals(type)) {
property = new SimpleIntegerProperty();
}else if(Long.class.equals(type) || long.class.equals(property)){
} else if (Long.class.equals(type) || long.class.equals(property)) {
property = new SimpleLongProperty();
}else if(String.class.equals(type)){
} else if (String.class.equals(type)) {
property = new SimpleStringProperty();
}else if(List.class.isAssignableFrom(type)){
} else if (List.class.isAssignableFrom(type)) {
property = new SimpleListProperty();
}else if(Object.class.isAssignableFrom(type)){
} else if (Object.class.isAssignableFrom(type)) {
property = new SimpleObjectProperty();
}
return property;
}
}

View File

@@ -11,17 +11,17 @@ import javafx.stage.Stage;
*/
public class FXWindowParser {
public void parse(Stage stage, Pane fxControllerProxy, FXWindow fxWindow){
public void parse(Stage stage, Pane fxControllerProxy, FXWindow fxWindow) {
stage.setTitle(fxWindow.title());
if(fxWindow.resizable()){
if (fxWindow.resizable()) {
stage.setResizable(false);
}
if(fxWindow.draggable()) {
final int RESIZE_WIDTH = 5;// 判定是否为调整窗口状态的范围与边界距离
EventHandler dragWindowHandler= new DragWindowHandlerImpl(stage,fxWindow.minWidth(),fxWindow.minHeight(),fxControllerProxy,fxWindow.resizable());
if (fxWindow.draggable()) {
final int RESIZE_WIDTH = 5;// 判定是否为调整窗口状态的范围与边界距离
EventHandler dragWindowHandler = new DragWindowHandlerImpl(stage, fxWindow.minWidth(), fxWindow.minHeight(), fxControllerProxy, fxWindow.resizable());
fxControllerProxy.setOnMousePressed(dragWindowHandler);
fxControllerProxy.setOnMouseDragged(dragWindowHandler);
fxControllerProxy.setOnMouseMoved(dragWindowHandler);

View File

@@ -19,31 +19,32 @@ import java.util.concurrent.ConcurrentHashMap;
public class MessageQueue {
private static Map<String, List<FXMethodEntity>> receivers = new ConcurrentHashMap<>();
private static Map<String, List<FXMethodEntity>> receivers = new ConcurrentHashMap<>(); //Map<主题,订阅了主题的所有方法>
private static MessageQueue messageQueue = null;
private MessageQueue(){ }
private MessageQueue() {
}
public static synchronized MessageQueue getInstance(){
if(messageQueue == null){
public static synchronized MessageQueue getInstance() {
if (messageQueue == null) {
messageQueue = new MessageQueue();
}
return messageQueue;
}
public void registerCosumer(FXBaseController fxBaseController,FXBaseController fxBaseControllerProxy){
public void registerConsumer(FXBaseController fxBaseController, FXBaseController fxBaseControllerProxy) {
Class clazz = fxBaseController.getClass();
Method [] methods = clazz.getDeclaredMethods();
for(Method method : methods){
Annotation[]annotations = method.getDeclaredAnnotations();
for(Annotation annotation : annotations){
if(FXReceiver.class.equals(annotation.annotationType())){
FXReceiver receiver = (FXReceiver)annotation;
FXMethodEntity fxMethodEntity = new FXMethodEntity(fxBaseControllerProxy,method);
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
Annotation[] annotations = method.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
if (FXReceiver.class.equals(annotation.annotationType())) {
// System.out.println("FXReceiver");
FXReceiver receiver = (FXReceiver) annotation;
FXMethodEntity fxMethodEntity = new FXMethodEntity(fxBaseControllerProxy, method);
List<FXMethodEntity> fxMethodEntities = receivers.get(receiver.name());
if(fxMethodEntities == null){
if (fxMethodEntities == null) {
fxMethodEntities = new ArrayList<>();
}
fxMethodEntities.add(fxMethodEntity);
@@ -53,7 +54,7 @@ public class MessageQueue {
}
}
public void sendMsg(String id,Object msg) {
public void sendMsg(String id, Object msg) {
List<FXMethodEntity> lists = receivers.get(id);
if (lists != null) {
for (FXMethodEntity fxMethodEntity : lists) {

View File

@@ -1,9 +1,10 @@
package cn.edu.scau.biubiusuisui.proxy;
import cn.edu.scau.biubiusuisui.annotation.FXRedirect;
import cn.edu.scau.biubiusuisui.annotation.FXSender;
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
import cn.edu.scau.biubiusuisui.messageQueue.MessageQueue;
import net.sf.cglib.beans.BeanCopier;
import cn.edu.scau.biubiusuisui.stage.StageManager;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
@@ -13,7 +14,6 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
*
* This proxy class intercept Methods that has special annotation such as
* FXSender which is a mark for message queue
*
@@ -26,9 +26,9 @@ public class FXControllerProxy implements MethodInterceptor {
FXBaseController target;
public Object getInstance(FXBaseController target) {
this.target = target;
// System.out.println(target.toString());
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
@@ -40,26 +40,34 @@ public class FXControllerProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object o1 = methodProxy.invokeSuper(o, objects);
Annotation []annotations = method.getDeclaredAnnotations();
for(Annotation annotation : annotations){
if(FXSender.class.equals(annotation.annotationType())){
FXSender fxSender = (FXSender)annotation;
String name = target.getName() +":";
if("".equals(fxSender.name())){
name += method.getName();
}else{
name += fxSender.name();
Object o1 = methodProxy.invokeSuper(o, objects); //获取该方法运行后的结果
Annotation[] annotations = method.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
if (FXSender.class.equals(annotation.annotationType())) { // 拦截是否发送消息函数
FXSender fxSender = (FXSender) annotation;
// System.out.println("FXSender");
String name = target.getName() + ":";
// System.out.println("FXControllerProxy:" + name);
if ("".equals(fxSender.name())) {
name += method.getName();
} else {
name += fxSender.name();
}
MessageQueue.getInstance().sendMsg(name,o1);
MessageQueue.getInstance().sendMsg(name, o1);
}
if (FXRedirect.class.equals((annotation.annotationType()))) { //拦截是否重定向函数
FXRedirect fxRedirect = (FXRedirect) annotation;
if (fxRedirect.close()) { //关闭原窗口
StageManager.getInstance().closeStage(target.getName());
}
StageManager.getInstance().redirectTo(o1);
}
}
return o1;
}
private void inject(Object target,Object proxy){
private void inject(Object target, Object proxy) {
Class clazz = target.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {

View File

@@ -1,6 +1,6 @@
package cn.edu.scau.biubiusuisui.proxy;
import cn.edu.scau.biubiusuisui.entity.FXFieldWarpper;
import cn.edu.scau.biubiusuisui.entity.FXFieldWrapper;
import cn.edu.scau.biubiusuisui.utils.StringUtils;
import javafx.beans.property.*;
import net.sf.cglib.proxy.Enhancer;
@@ -17,7 +17,7 @@ import java.util.Map;
public class FXEntityProxy implements MethodInterceptor {
Object target;
private Map<String, FXFieldWarpper> fxFieldWarpperMap;
private Map<String, FXFieldWrapper> fxFieldWrapperMap;
public Object getInstance(Object target) {
this.target = target;
@@ -39,20 +39,20 @@ public class FXEntityProxy implements MethodInterceptor {
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object o1 = methodProxy.invokeSuper(o, objects);
Object o1 = methodProxy.invokeSuper(o, objects); //获取该方法运行后的结果
String methodName = method.getName();
String fieldName = null;
if (methodName.length() >= 3) {
fieldName = StringUtils.toInstanceName(methodName.substring(3));
fieldName = StringUtils.toInstanceName(methodName.substring(3)); // 该method有可能是getter和setter方法进行处理
} else {
return o1;
}
FXFieldWarpper fxFieldWarpper = fxFieldWarpperMap.get(fieldName);
FXFieldWrapper fxFieldWrapper = fxFieldWrapperMap.get(fieldName);
Property property = getPropertyByFieldName(fieldName);
if(fxFieldWarpper == null || property == null){
if (fxFieldWrapper == null || property == null) {
return o1;
}
Class type = fxFieldWarpper.getType();
Class type = fxFieldWrapper.getType();
if (methodName.startsWith("set")) {
if(Boolean.class.equals(type) || boolean.class.equals(type)){
((SimpleBooleanProperty)property).set((Boolean)objects[0]);
@@ -86,17 +86,17 @@ public class FXEntityProxy implements MethodInterceptor {
}
public Property getPropertyByFieldName(String name) {
if(fxFieldWarpperMap.get(name) ==null){
if (fxFieldWrapperMap.get(name) == null) {
return null;
}
return fxFieldWarpperMap.get(name).getProperty() ;
return fxFieldWrapperMap.get(name).getProperty();
}
public Map<String, FXFieldWarpper> getFxFieldWarpperMap() {
return fxFieldWarpperMap;
public Map<String, FXFieldWrapper> getFxFieldWrapperMap() {
return fxFieldWrapperMap;
}
public void setFxFieldWarpperMap(Map<String, FXFieldWarpper> fxFieldWarpperMap) {
this.fxFieldWarpperMap = fxFieldWarpperMap;
public void setFxFieldWrapperMap(Map<String, FXFieldWrapper> fxFieldWrapperMap) {
this.fxFieldWrapperMap = fxFieldWrapperMap;
}
}

View File

@@ -0,0 +1,44 @@
package cn.edu.scau.biubiusuisui.stage;
import cn.edu.scau.biubiusuisui.entity.FXBaseController;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author suiyu_yang
* @description 舞台管理器
* @date 2019/12/3 15:43
* @email suiyu_yang@163.com
*/
public class StageManager {
private static StageManager stageManager = null;
private static Map<String, FXBaseController> windows = new ConcurrentHashMap<>(); //
private StageManager() {
}
public static synchronized StageManager getInstance() {
if (stageManager == null) {
stageManager = new StageManager();
}
return stageManager;
}
public void registerWindow(FXBaseController fxBaseControllerProxy) {
if (fxBaseControllerProxy.isWindow()) {
// System.out.println("StageController: "+(fxBaseControllerProxy.getStage() == null));
windows.put(fxBaseControllerProxy.getName(), fxBaseControllerProxy);
}
}
public void closeStage(String controllerName) {
windows.get(controllerName).closeStage();
}
public void redirectTo(Object controller) {
System.out.println("跳转->" + controller);
windows.get(controller).showStage();
}
}

View File

@@ -14,6 +14,6 @@ public class BeanUtil {
if(fxEntityProxy == null){
return null;
}
return fxEntityProxy.getFxFieldWarpperMap().get(fieldName).getProperty();
return fxEntityProxy.getFxFieldWrapperMap().get(fieldName).getProperty();
}
}

View File

@@ -13,22 +13,22 @@ import java.util.List;
* @Date:2019/6/25 5:20
*/
public class ClassUtils {
private ClassLoader cl;
private ClassLoader classLoader;
public ClassUtils() {
cl = getClass().getClassLoader();
classLoader = getClass().getClassLoader();
}
private List<String> getAllFXControllerClassName(String base, List<String> nameList) {
String splashPath = StringUtils.dotToSplash(base);
URL url = cl.getResource(splashPath);
URL url = classLoader.getResource(splashPath);
String filePath = StringUtils.getRootPath(url);
List<String> names = null;
names = readFromDirectory(filePath);
for (String name : names) {
if (isClassFile(name)) {
nameList.add(toFullyQualifiedName(name, base));
} else if (isDirectory(name)){
} else if (isDirectory(name)) {
nameList = getAllFXControllerClassName(base + "." + name, nameList);
}
}
@@ -49,9 +49,11 @@ public class ClassUtils {
private static boolean isClassFile(String name) {
return name.endsWith(".class");
}
private static boolean isDirectory(String name){
private static boolean isDirectory(String name) {
return !name.contains(".");
}
private static List<String> readFromDirectory(String path) {
File file = new File(path);
String[] names = file.list();
@@ -63,8 +65,8 @@ public class ClassUtils {
}
public static boolean hasDeclaredAnnotation(Class clazz, Class annotation){
if(annotation == null){
public static boolean hasDeclaredAnnotation(Class clazz, Class annotation) {
if (annotation == null) {
return false;
}
if (hasAnnotationInList(annotation, clazz.getDeclaredAnnotations())) return true;
@@ -72,7 +74,7 @@ public class ClassUtils {
}
public static boolean hasAnnotation(Class clazz, Class annotation) {
if(annotation == null){
if (annotation == null) {
return false;
}
if (hasAnnotationInList(annotation, clazz.getAnnotations())) return true;
@@ -80,16 +82,16 @@ public class ClassUtils {
}
public static boolean hasAnnotationInList(Class annotation, Annotation[] annotations2) {
if(getAnnotationInList(annotation,annotations2) == null){
if (getAnnotationInList(annotation, annotations2) == null) {
return false;
}else{
} else {
return true;
}
}
public static Annotation getAnnotationInList(Class annotation,Annotation[]annotations){
if(annotations == null || annotation == null){
return null;
public static Annotation getAnnotationInList(Class annotation, Annotation[] annotations) {
if (annotations == null || annotation == null) {
return null;
}
for (Annotation annotation1 : annotations) {
if (annotation1.annotationType().equals(annotation)) {
@@ -99,11 +101,11 @@ public class ClassUtils {
return null;
}
public static void copyField(Object target,Object base){
public static void copyField(Object target, Object base) {
Class clazz = base.getClass();
Class targetClass = target.getClass();
Field []fields = clazz.getDeclaredFields();
for(Field field:fields){
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
// Field field1 = targetClass.getField(field.getName());

View File

@@ -4,6 +4,7 @@ package cn.edu.scau.biubiusuisui.utils;
* @Author jack
* @Date:2019/6/25 3:46
*/
import java.net.URL;
public class StringUtils {
@@ -61,21 +62,34 @@ public class StringUtils {
return trimmed.substring(splashIndex);
}
public static String getBaseClassName(String name){
public static String getBaseClassName(String name) {
int index = name.indexOf("$");
if(index == -1){
if (index == -1) {
return name;
}
return name.substring(0,index);
// System.out.println(name.substring(0,index));
return name.substring(0, index);
}
public static String toInstanceName(String name){
/**
* Object -> object ; Student -> student
*
* @param name
* @return
*/
public static String toInstanceName(String name) {
String result = name.substring(0, 1).toLowerCase().concat(name.substring(1));
return result;
}
public static String toClassName(String name){
/**
* object -> Object ; student -> Student
*
* @param name
* @return
*/
public static String toClassName(String name) {
String result = name.substring(0, 1).toUpperCase().concat(name.substring(1));
return result;
}

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.Pane?>
<fx:root prefHeight="191.0" prefWidth="607.0" type="Pane" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cn.edu.scau.biubiusuisui.example.actionDemo.MainController">
<children>
<TextField fx:id="time" layoutX="108.0" layoutY="28.0" prefHeight="28.0" prefWidth="330.0" />
<Label fx:id="us" layoutX="108.0" layoutY="75.0" prefHeight="24.0" prefWidth="330.0" text="US:" />
<Label fx:id="jp" layoutX="108.0" layoutY="107.0" prefHeight="24.0" prefWidth="330.0" text="JP:" />
<Label fx:id="uk" layoutX="108.0" layoutY="142.0" prefHeight="24.0" prefWidth="330.0" text="UK:" />
<Label layoutX="67.0" layoutY="77.0" text="US" />
<Label layoutX="69.0" layoutY="109.0" text="JP" />
<Label layoutX="66.0" layoutY="144.0" text="UK" />
</children>
</fx:root>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.Pane?>
<fx:root prefHeight="191.0" prefWidth="607.0" type="Pane" xmlns="http://javafx.com/javafx/8.0.171"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="cn.edu.scau.biubiusuisui.example.actionDemo.MainController">
<children>
<TextField fx:id="time" layoutX="108.0" layoutY="28.0" prefHeight="28.0" prefWidth="330.0"/>
<Label fx:id="us" layoutX="108.0" layoutY="75.0" prefHeight="24.0" prefWidth="330.0" text="US:"/>
<Label fx:id="jp" layoutX="108.0" layoutY="107.0" prefHeight="24.0" prefWidth="330.0" text="JP:"/>
<Label fx:id="uk" layoutX="108.0" layoutY="142.0" prefHeight="24.0" prefWidth="330.0" text="UK:"/>
<Label layoutX="67.0" layoutY="77.0" text="US"/>
<Label layoutX="69.0" layoutY="109.0" text="JP"/>
<Label layoutX="66.0" layoutY="144.0" text="UK"/>
</children>
</fx:root>

View File

@@ -3,10 +3,9 @@
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.Pane?>
<fx:root prefHeight="600.0" prefWidth="800.0" type="Pane" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cn.edu.scau.biubiusuisui.example.listDemo.MainController">
<children>
<ListView fx:id="list" layoutX="32.0" layoutY="62.0" prefHeight="489.0" prefWidth="728.0" />
<Button layoutX="691.0" layoutY="564.0" mnemonicParsing="false" onAction="#addName" text="Button" />
</children>
<children>
<ListView fx:id="userNameListView" layoutX="144.0" layoutY="46.0" prefHeight="457.0" prefWidth="423.0"/>
<Button layoutX="602.0" layoutY="489.0" mnemonicParsing="false" onAction="#addUserName" text="addUserName"/>
</children>
</fx:root>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import cn.edu.scau.biubiusuisui.example.mqDemo.TopBarController?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0"
prefWidth="600.0" type="Pane" xmlns="http://javafx.com/javafx/10.0.2-internal"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="cn.edu.scau.biubiusuisui.example.mqDemo.MainController">
<children>
<VBox prefHeight="400.0" prefWidth="600.0">
<children>
<TopBarController/>
<TextArea fx:id="outTA" editable="false" prefHeight="350.0" prefWidth="600.0" wrapText="true"/>
</children>
</VBox>
</children>
</fx:root>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="50.0"
prefWidth="600.0" type="Pane" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="cn.edu.scau.biubiusuisui.example.mqDemo.TopBarController">
<children>
<HBox alignment="CENTER" prefHeight="50.0" prefWidth="600.0" spacing="20.0">
<children>
<Button mnemonicParsing="false" onAction="#indexClick" prefHeight="50.0" prefWidth="100.0" text="首页"/>
<Button mnemonicParsing="false" onAction="#scoreClick" prefHeight="50.0" prefWidth="100.0" text="积分中心"/>
<Button mnemonicParsing="false" onAction="#questionClick" prefHeight="50.0" prefWidth="100.0"
text="问答中心"/>
<Button mnemonicParsing="false" onAction="#selfClick" prefHeight="50.0" prefWidth="100.0" text="个人中心"/>
</children>
</HBox>
</children>
</fx:root>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.text.Font?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0"
prefWidth="400.0" type="Pane" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label layoutX="103.0" layoutY="100.0" text="这是一个弹窗......">
<font>
<Font size="24.0"/>
</font>
</Label>
</children>
</fx:root>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0"
prefWidth="800.0" type="Pane" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="cn.edu.scau.biubiusuisui.example.redirectDemo.LoginController">
<children>
<VBox alignment="CENTER" layoutX="265.0" layoutY="100.0" prefHeight="300.0" prefWidth="250.0" spacing="10.0">
<children>
<Label alignment="CENTER" prefHeight="50.0" prefWidth="250.0" text="登录">
<font>
<Font size="27.0"/>
</font>
</Label>
<HBox alignment="CENTER" prefHeight="50.0" prefWidth="200.0">
<children>
<Label alignment="CENTER" prefHeight="50.0" prefWidth="50.0" text="用户名:"/>
<TextField fx:id="usernameTF"/>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="50.0" prefWidth="200.0">
<children>
<Label alignment="CENTER" prefHeight="50.0" prefWidth="50.0" text="密码:"/>
<PasswordField fx:id="passwordPF"/>
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="50.0" prefWidth="200.0">
<children>
<Label onMouseClicked="#registerClick" prefHeight="50.0" text="还没有账户,去注册" underline="true">
<HBox.margin>
<Insets right="10.0"/>
</HBox.margin>
</Label>
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="50.0" prefWidth="200.0">
<children>
<Button mnemonicParsing="false" onAction="#redirectToDialog" text="测试弹窗的按钮">
<HBox.margin>
<Insets right="20.0"/>
</HBox.margin>
</Button>
</children>
</HBox>
</children>
</VBox>
</children>
</fx:root>

View File

@@ -0,0 +1,8 @@
#content {
alignment: center;
}
#content .label {
-fx-pref-height: 50;
-fx-pref-width: 100;
}

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0"
prefWidth="600.0" stylesheets="@register.css" type="Pane" xmlns="http://javafx.com/javafx/8.0.171"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="cn.edu.scau.biubiusuisui.example.redirectDemo.RegisterController">
<children>
<VBox alignment="CENTER" layoutX="100.0" layoutY="55.0" prefHeight="350.0" prefWidth="400.0">
<children>
<HBox prefHeight="50.0" prefWidth="200.0">
<children>
<Label alignment="CENTER" prefHeight="50.0" prefWidth="404.0" text="注册">
<font>
<Font size="24.0"/>
</font>
</Label>
</children>
</HBox>
<VBox id="content" alignment="CENTER" prefHeight="350.0" prefWidth="400.0">
<children>
<HBox alignment="CENTER" prefHeight="50.0" prefWidth="200.0">
<children>
<Label text="用户名:"/>
<TextField fx:id="usernameTF"/>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="50.0" prefWidth="200.0">
<children>
<Label text="电子邮箱:"/>
<TextField fx:id="emailTF"/>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="50.0" prefWidth="200.0">
<children>
<Label text="密码:"/>
<PasswordField fx:id="passwordPF"/>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="50.0" prefWidth="200.0">
<children>
<Label text="确认密码:"/>
<PasswordField fx:id="confirmPasswordPF"/>
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="50.0" prefWidth="200.0">
<children>
<Label minWidth="150.0" onMouseClicked="#loginClick" prefWidth="151.0" text="已有账号,前往登录"
underline="true"/>
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="50.0" prefWidth="200.0">
<children>
<Button mnemonicParsing="false" onAction="#registerClick" text="注册">
<HBox.margin>
<Insets right="50.0"/>
</HBox.margin>
</Button>
</children>
</HBox>
</children>
</VBox>
</children>
</VBox>
</children>
</fx:root>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0"
prefWidth="600.0" type="Pane" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="cn.edu.scau.biubiusuisui.example.redirectDemo.SuccessController">
<children>
<VBox alignment="CENTER" layoutX="158.0" layoutY="80.0" prefHeight="300.0" prefWidth="250.0" spacing="10.0">
<children>
<Label alignment="CENTER" prefHeight="50.0" prefWidth="250.0" text="登录成功">
<font>
<Font size="27.0"/>
</font>
</Label>
<HBox alignment="CENTER" prefHeight="50.0" prefWidth="200.0">
<children>
<Label alignment="CENTER" prefHeight="50.0" prefWidth="50.0" text="用户名:"/>
<Label fx:id="usernameLabel" alignment="CENTER" prefHeight="50.0" prefWidth="150.0"/>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="50.0" prefWidth="200.0">
<children>
<Label alignment="CENTER" prefHeight="50.0" prefWidth="50.0" text="密码:"/>
<Label fx:id="passwordLabel" alignment="CENTER" prefHeight="50.0" prefWidth="150.0"/>
</children>
</HBox>
</children>
</VBox>
<Button layoutX="421.0" layoutY="367.0" mnemonicParsing="false" onAction="#redirectToLogin" text="返回主界面"/>
</children>
</fx:root>