新增英文README,修正部分文件结构

This commit is contained in:
suisui
2020-01-22 02:18:46 +08:00
parent 54dc098123
commit d23cda4f47
39 changed files with 808 additions and 84 deletions

View File

@@ -1,36 +1,692 @@
# JavaFX-Plus # JavaFX-Plus
#### Description [TOC]
自己实现的JavaFX的框架可以简化开发步骤和提高开发效率。
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md ## Introduction
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) The framework is not the framework for beautifying UI, but to simplify the step of developing the JavaFX Application and reduce the component coupling. Precently, the main functions of our framework are shown as follows:
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) ![JavaFX-Plus_en](README.en/JavaFX-Plus_en.png)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
### The Process of Developing
Our project has suspended update from Nov. 25, 2019, and the next release will be updated to 2.0. We try to provides more data binding operations and optimize performance.
- [x] Modularization
- [x] Integration with Spring
- [x] Signal Mechanism
- [x] The conversion of JavaBean and JavaFXBean
- [x] Pluggable function (drag window, etc.)
- [x] Data Binding
- [x] The binding between bean and view
- [x] The binding between view and view
- [x] The binding of functional expression
- [x] Multi-window switching
- [ ]
- [ ] The binding of event annotation
- [ ] The binding of keyboard events
- [ ] Data valication
- [ ] Optimize performance
## Maven Repository
```xml
<dependency>
<groupId>com.gitee.Biubiuyuyu</groupId>
<artifactId>javafx-plus</artifactId>
<version>1.0.0-RELEASE</version>
</dependency>
```
## The Specific Application with Java-Plus
Available from this: [Paper Loader](https://gitee.com/Biubiuyuyu/JavaFX-Demo 'Demo')
## The Detailed Functions of JavaFX-Plus
### Modularization Development
#### Introduction
Generally, many of the interfaces are similar or duplicate in the development of JavaFX application. Therefore it would be much more efficient to package these interfaces into custom controls that can be dragged from SceneBuilder. We propose to divide different interfaces into different sub-modules to reduce coupling and accelerate parallel development. For example, we always divide the interface into the top toolbar, the navigation bar on the left, and the internal bar on the right. If everything is written in one controller, it will cause a lot of bloat, so we want to divide different interfaces and manage them separatelly.
#### How to Create the Module of JavaFX-Plus
- Just new a class extends `FXBaseController` class, and this new class is what we always called Controlelr. The `FXBaseController` extends `Pane` class, and that is the idea behind JavaFX-Plus: Everything is Pane.
- Label this controller with an annotation of `@FXController`, providing the address of FXML file.
- If we want to show the controller into a separate window, we can add a class annotation of `@FXWindow` to label it, with the value of "title" marking the title of the window and "mainStage" marking that if this window is shown as a main stage while starting the application.
The example is shown as follows, which we can get it is easier for us to develop a simple JavaFX application.
![输入图片说明](README.en/controllerConfig.png "controllerConfig.png")
![输入图片说明](README.en/demo1.png "demo1.png")
#### Import the control just generated above in SceneBuilder
![输入图片说明](README.en/modulesAction.gif "modulesAction.gif")
### Integration with Spring
The framework can quickly support integration with Spring, and with one line of code, it can inverse control of instance generation to Spring container management.
The example is shown as follows:
```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"); //start spring
FXPlusApplication.start(SpringDemo.class, new BeanBuilder() {
@Override
public Object getBean(Class type) {
return context.getBean(type);
}
});
}
}
```
### Signal Mechanism
There are two annotations, one is `@FXSender`, which is applied to a method, marking this method as the signal emission method. And we can change the name of this emitting function with the value of "name", which default name is the method name.
The emitting signal will be received by all FXReceiver that subsrcibe to the emitting function, and the return value of the emitting function is passed into the FXReceiver function as a parameter. This sending and receiving relationship is global and can be recevied by any registered controller, not limited to the same controller.
Let's take an example of the implementation of custom compoent navigation top bar, be contained in the main interface. When the user clicks some buttons in the navigation bar, the bar can return information relating the main interface. The example fxml file is shown in the `mqDemo` folder under resources.
1. With the modularity of JavaFX, we designed a simple navigation bar:
```java
@FXController(path = "mqDemo/topBar.fxml")
public class TopBarController extends FXBaseController {
@FXML
public void indexClick() {
sendToMain("Click [Index]");
}
@FXML
public void scoreClick() {
sendToMain("Click [Score Center]");
}
@FXML
public void questionClick() {
sendToMain("Click [Answer Center]");
}
@FXML
public void selfClick() {
sendToMain("Click [Personal Center]");
}
/**
* The application will invoke all methods which subscrib the signal.
* @param msg
* @return
*/
@FXSender //Marks this method as a signal emission method
public String sendToMain(String msg) {
return msg;
}
}
```
2. Then we designed a main page, which contains the navigation bar.
```java
@FXController(path = "mqDemo/main.fxml")
@FXWindow(mainStage = true, title = "MQDemo")
public class MainController extends FXBaseController {
@FXML
private TextArea outTA;
/**
* The name of subscribed signal should be: [FXSenderName:MethodName]
* The return value of signal emission method will be injected as parameter to signal received method
*
* @param msg
*/
@FXReceiver(name = "TopBarController:sendToMain")
public void handleTopBar(String msg) {
// TODO: 2019/12/8
// Handle the mouse click event of navigation bar
outTA.appendText(msg + "\n");
}
}
```
![20191208-194336-signalshow](doc/mqDemo/20191208-194336-signalshow.gif)
### The conversion of JavaBean and JavaFXBean
Generally, we write Java beans of basic types, but the design philosophy of JavaFX beans is that these properties should be `Property` types defined by JavaFX, which is very bad for our development. So how can we use some good methods for JavaFX properties without changing Java beans? The answer is that by reflection we can get the Property corresponding to the primitive type, but currently limited to boolean, double, integer, long, string, float, List, etc.
![输入图片说明](README.en/wrap_JavaBean.png "wrap_JavaBean.png")
We hope we can avoid methods which directly operate on Property related to interfaces during the development, but directly operate on Java bean classes. The example is shown as follows:
```java
@FXController(path = "Main.fxml")
@FXWindow(title = "demo1")
public class MainController extends FXBaseController{
@FXML
Button btn;
@FXML
Label label;
Student student;
int count = 1;
@Override
public void initialize() {
// Get Student from FXEntityFactory
student = (Student) FXEntityFactory.getInstance().createJavaBeanProxy(Student.class);
student.setName("Jack"); // Set name for Student
FXEntityProxy fxEntityProxy = FXPlusContext.getProryByBeanObject(student); //Get the proxy for Student
Property nameProperty = fxEntityProxy.getPropertyByFieldName("name"); //Get corresponding Property
//We can get the Property for List through fxEntityProxy.getPropertyByFieldName("list");
label.textProperty().bind(nameProperty); //bind to property
}
@FXML
@FXSender
public String send(){
student.setName("Jack :" + count);
count++;
return "sending msg";
}
}
```
```java
@FXEntity
public class Student {
@FXField
private String name; //Mark a field to be converted to Property field
private int age;
private String gender;
private String code;
@FXField
private List<String> list = new ArrayList<>();
public String getName() {
return name;
}
// setter & getter
// ...
public void addList(String word){
list.add(word);
}
public void delList(String word){
list.remove(word);
}
}
```
The result show us as follows:
![输入图片说明](README.en/bindhow.gif "bindhow.gif")
We directly operate on Java bean classess, modifying the interface with dynamic binding. And we don't need to convertJava bean to JavaFX bean, which reduce type conversion in development.
### Pluggable function
In our framework, windows are draggable and scalable. In JavaFX, if a window hides its title, the window can not be dragged and scaled. But in JavaFX-Plus, we have resolved this issue with an annotation of `@FXWindow`.
```java
@FXWindow(title = "demo1",dragable = true,style = StageStyle.UNDECORATED)
```
As described in the code above, you can make window with no title draggable and scalable( the default value is draggable).
![输入图片说明](README.en/moveable.gif "moveable.gif")
![输入图片说明](README.en/resizeAble.gif "resizeAble.gif")
### Data Binding
In this section, similar to interface binding in Vue, we use an annotation of `@FXBind`, which should be used on the field of JavaFX controls, marking the binding mode and properties of the marked field. Currently, we have implemented the binding between bean and view, between view and view, and the binding of functional expression.
#### The binding between bean and view
As example shown follows, we binded the name of `Student` to the input text of `TextField`, and binded the password of `Student` to the input text of `PasswordField`, simplify the operation on data transmission. And there are no interface data transmission from interface to controller.
The example is shown as follows:
```java
@FXData
@FXBind(
{
"name=${usr.text}",
"password=${psw.text}"
}
)
Student student = new Student();
@FXML
private PasswordField psw;
@FXML
private Label pswMsg;
@FXML
void login(ActionEvent event) {
System.out.println("user:" + student.getName());
System.out.println("psw:" + student.getPassword());
if ("admin".equals(student.getName()) && "admin".equals(student.getPassword())) {
System.out.println("Ok");
} else {
System.out.println("fail");
}
}
```
The result of simple application as shown follows:
![输入图片说明](README.en/expression.gif "expression.gif")
#### The binding between view and view
```java
@FXBind("text=${psw.text}")
@FXML
private Label pswMsg;//bind the text of Label(pswMsg) to psw
```
The result of simple application as shown follows:
![输入图片说明](README.en/expressionV2V.gif "expressionV2V.gif")
#### The binding of functional expression
The example code is shown at `cn.edu.scau.biubiusuisui.example.listDemo` and `cn.edu.scau.biubiusuisui.actionDemo`, now let's take an example of actionDemo.
1. How to use
As the two usage above, the annotation is used to mark on the controller class of the inteface, like the usage above, with `${}` as the external identifier. But if we bind to the functional expression, we need to put `@` before the name of the method.
```java
@FXBind("text=${@toUs(time.text)}") // bind the text of Label to the return value of toUs() function
private Label us;
```
2. Example code
As code shown follows, we implemented a simple exchange rate converter
```java
@FXController(path = "actionDemo/actionDemo.fxml")
@FXWindow(title = "actionDemo", mainStage = true)
public class MainController extends FXBaseController implements Initializable {
@FXML
@FXBind("text=${@toUs(time.text)}") // bind the text of Label to the return value of toUs() function
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. The result of simple application as shown follows:
![20191210-175409-actionDemo](README.en/actionDemo/20191210-175409-actionDemo.gif)
## Multi-window switching
#### Introduction
In JavaFX application, we always need to switch between multiple windows, such as the login window, click “login” and jump to the login success/fail window. The JavaFX tutorial on multi-window switching on the web is implemented as follows: binding FXML file in Controllers and the window can be switched through show() method. Since our framework already encapsulates the function to bind the FXML file, it is not practical to initialize the Stage and set parameters directly inside Controller. Therefore, in our framework, we design a class named StageController to manage Controllers.
#### Related Annotations
`@FXController`Annotated on a class, to bind FXML file and mark this class as a control.
`@FXWindow`Annotated on a class, to mark this class as a seperate window and it can be redirected only if it is marked as a seperate window.
`@FXRedirect`Annotated on a method, to mark this method to handle redirection.
#### Specification
The JavaFX-Plus stipulates that if we need an annotated with `@FXRedirect` method to handle redirection, the return value must be Stirng property and return the name of registered Controller. For example, if we need redirecting to login success interface whose conttroller named SuccessController, we should write `return "SuccessController"` in the method handling redirection.
#### How to Use
1. The usage of annotation `FXRedirect` as shown follows:
```java
@FXRedirect
public String redirectToRegister() {
return "RegisterController";
}
@FXML
@FXRedirect(close = false)
public String redirectToDialog() {
return "DialogController";
}
```
The boolean value of close marks that if close the current window, and the default value is true, which means that the current window will be closed when redirecting to anothor window.
2. Create the login 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() {
redirectToRegister();
}
@FXRedirect
public String redirectToRegister() {
return "RegisterController";
}
@FXML
@FXRedirect(close = false)
public String redirectToDialog() {
return "DialogController";
}
}
```
3. Design the Controller which will be redirected to.
```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 = "Dialog")
public class DialogController extends FXBaseController {
}
```
#### Example Code
The example code is stored at `cn.edu.scau.biubiusuisui.example.redirectDemo`, and the FXML file is stored in redirectDemo folder under resources.
1. redirect to anothor window(close the current window)
![20191208-125739-close](README.en/redirectDemo/20191208-125739-close.gif)
2. popup an window as a dialog(do not close the current window)
![20191208-125511-not close](README.en/20191208-125511-not_close.gif)
#### Deficiencies
Currently, the JavaFX-Plus does not support the redirection to windows with data, but support redrecting to another window with nothing.
## How to Use JavaFX-Plus
### Annotations
| Name | Usage | Parameter | Remark for Parameter |
| ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| @FXData | in the controller, to mark a Java bean which is a field of controller, and it will be converted to JavaFX bean | fx_id | not necessary, renames the Java bean |
| @FXScan | to scan classes which marked by @FXEntity and @FXController | base | not necessary, marks a directory to scan all classes and the default value is current directory |
| @FXController | to mark a class as a control | path | necessary, marks the path of FXML file |
| @FXWindow | to mark a control to be displayed as a separate window | 1. title<br>2. mainStage<br>3. preHeight, preWidth,minHeight, minWidth<br>4. resizable, draggable<br>5. style | 1. not necessary, marks the title of window<br>2. not necessary, the boolean value marks that if this window is main stage, default value is false<br>3. not necessary, marks the preHeight, preWidth, minHeight, minWidth for this window<br>4. not necessary, the boolean value marks that if this window is resizable or draggable<br>5. not necessary, marks the StageStyle for this window |
| @FXEntity | to mark a Java bean which will be converted to JavaFX bean, and JavaFX-Plus will identify @FXField in it and package it to JavaFX bean | | |
| @FXField | to mark a field in java bean marked by @FXEntity to be reflected to Property type | | |
| @FXSender | to mark a method as sending signal method | name | not necessary, renames the signal |
| @FXReceiver | to mark a method as receiving signal method | name | necessary, marks the subscribed signal |
| @FXRedirect | to mark a method that can redirect to anthor window | close | not necessary, the boolean value marks if close current window; the return value of this method should be the name of redrecting Controller |
### Two Factories and A Context
1. Two Factories
In JavaFX-Plus, all Controller objects and FXEntity objects should be created through factories.
```java
student = (Student) FXEntityFactory.getInstance().wrapFxBean(Student.class); //New a Student through FXEntityFactory
```
The Java beans are created through the factory, and as they are created, the factory proxies the Java beans and wraps the corresponding Property properties.
```java
MainController mainController = (MainController)FXFactory.getFXController(MainController.class);
```
2. A Context
The `FXPlusContext` stores all proxy classes for Controllers and FXEntities which annotated with `@FXController` and `@FXEntity`.
```java
public class FXPlusContext {
private FXPlusContext(){}
private static Map<String, List<FXBaseController>> controllerContext = new ConcurrentHashMap<>(); //a registry of FXController controllers
private static Map<Object, FXEntityProxy> beanMap = new ConcurrentHashMap<>(); // register an Object to 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);
}
}
```
## Start your first JavaFX-Plus Application
1. New the main class.
```java
@FXScan(base = {"cn.edu.scau.biubiusuisui.example"}) // Scan classes annotated by @FXController and @FXEntity and initialize them
public class Demo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
// Other paramters are same as the Application of original JavaFX
// Here we invoke the start method of FXPlusApplication
FXPlusApplication.start(Demo.class);
}
}
```
2. Next, we design a FXML file and a controller class.
```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;
Student student;
@FXML
void addWord(ActionEvent event) {
student.addList("hello" );
}
@FXML
void delWord(ActionEvent event) {
student.delList("hello");
}
@Override
public void initialize() {
// Get the JavaFX bean which is wraped from Java bean in FXEntityFactory
student = (Student) FXEntityFactory.wrapFxBean(Student.class);
Property listProperty = FXPlusContext.getEntityPropertyByName(student, "list");
list.itemsProperty().bind(listProperty);
}
}
```
3. Now we design the Studen class.
```java
@FXEntity
public class Student {
@FXField
private String name;
@FXField
private List<String> list = new ArrayList<>();
public void addList(String word){
list.add(word);
}
public void delList(String word){
list.remove(word);
}
}
```
It should be noted that, the root label of the FXML file must be `fx:root>`.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.Pane?>
<fx:root prefHeight="400.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.MainController">
<children>
<Button fx:id="addBtn" layoutX="432.0" layoutY="83.0" mnemonicParsing="false" onAction="#addWord" text="add" />
<Button fx:id="delBtn" layoutX="432.0" layoutY="151.0" mnemonicParsing="false" onAction="#delWord" text="del" />
<ListView fx:id="list" layoutX="42.0" layoutY="51.0" prefHeight="275.0" prefWidth="334.0" />
</children>
</fx:root>
```
As example code shown above, it is less operation on operating interfaces, and objects we operated are containing basic type. It favors us to convert a normal Java project to a JavaFX project.
The result of our first simple application as shown follows:
![输入图片说明](README.en/helloWorldDemo.gif "helloWorldDemo.gif")

View File

Before

Width:  |  Height:  |  Size: 451 KiB

After

Width:  |  Height:  |  Size: 451 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 KiB

View File

Before

Width:  |  Height:  |  Size: 14 MiB

After

Width:  |  Height:  |  Size: 14 MiB

BIN
README.en/bindhow.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
README.en/demo1.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
README.en/expression.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

BIN
README.en/expressionV2V.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

BIN
README.en/modulesAction.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 KiB

BIN
README.en/moveable.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 977 KiB

View File

Before

Width:  |  Height:  |  Size: 15 MiB

After

Width:  |  Height:  |  Size: 15 MiB

View File

Before

Width:  |  Height:  |  Size: 5.9 MiB

After

Width:  |  Height:  |  Size: 5.9 MiB

View File

Before

Width:  |  Height:  |  Size: 6.5 MiB

After

Width:  |  Height:  |  Size: 6.5 MiB

BIN
README.en/resizeAble.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

BIN
README.en/wrap_JavaBean.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -1,29 +1,6 @@
# JavaFX-Plus # JavaFX-Plus
- [JavaFX-Plus](#javafx-plus) [TOC]
* [前言](#前言)
+ [开发进程](#开发进程)
* [Maven仓库地址](#Maven仓库地址)
* [具体应用](#具体应用)
* [框架功能描述](#框架功能描述)
+ [模块化开发](#模块化开发)
- [介绍](#介绍)
- [如何创建模块](#如何创建模块)
- [scenebuilder中导入刚刚生成的上面的控件](#scenebuilder中导入刚刚生成的上面的控件)
+ [与Spring的融合](#与Spring的融合)
+ [信号机制](#信号机制)
+ [JavaBean与JavaFXBean的转换](#JavaBean与JavaFXBean的转换)
+ [可拔插功能](#可拔插功能)
+ [数据绑定](#数据绑定)
- [Bean和View绑定](#Bean和View绑定)
- [View和View绑定](#View和View绑定)
- [函数表达式绑定](#函数表达式绑定)
+ [多窗口切换功能](#多窗口切换功能)
* [框架的使用](#框架的使用)
+ [内置注解](#内置注解)
+ [两个工厂和一个context](#两个工厂和一个context)
* [创建第一个程序](#创建第一个程序)
@@ -32,7 +9,7 @@
这个框架不是UI美化框架为了简化javaFX项目开发、为了减少项目之间组件耦合而打造的框架。目前框架主要功能如下图所示 这个框架不是UI美化框架为了简化javaFX项目开发、为了减少项目之间组件耦合而打造的框架。目前框架主要功能如下图所示
![JavaFx-Plus](doc/JavaFX-Plus.png) ![JavaFx-Plus](README/JavaFX-Plus.png)
### 开发进程 ### 开发进程
2019年11月25日起项目暂停更新将会下次发布将会升级为2.0版本,到时候将会提供更多数据绑定操作,以及优化性能。 2019年11月25日起项目暂停更新将会下次发布将会升级为2.0版本,到时候将会提供更多数据绑定操作,以及优化性能。
@@ -76,17 +53,17 @@
只要新建一个类继承自FXBaseController而FXBaseController是继承于Pane这就是JavaFX-Plus的设计思想之一切皆为Pane。在类上标上FXController注解提供FXML文件的地址。如果设置为FXWindow那么将会把这个Controller以单独的Window显示这里仅仅几句代码就实现了一个简单的窗口程序。 只要新建一个类继承自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") ![输入图片说明](README/controllerConfig.png "controllerConfig.png")
图2 Controller配置 图2 Controller配置
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/022024_71892db3_2067650.png "demo1.png") ![输入图片说明](README/demo1.png "demo1.png")
图3 显示结果 图3 显示结果
#### scenebuilder中导入刚刚生成的上面的控件 #### scenebuilder中导入刚刚生成的上面的控件
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/022036_e128f313_2067650.gif "modulesAction.gif") ![输入图片说明](README/modulesAction.gif "modulesAction.gif")
图4 模块化操作 图4 模块化操作
@@ -185,13 +162,13 @@ public class MainController extends FXBaseController {
} }
``` ```
![20191208-194336-signalshow](doc/mqDemo/20191208-194336-signalshow.gif) ![20191208-194336-signalshow](README/mqDemo/20191208-194336-signalshow.gif)
### JavaBean与JavaFXBean的转换 ### JavaBean与JavaFXBean的转换
一般我们写的JavaBean都是基本类型的但是JavaFXBean的设计哲学是这些属性都应该是JavaFX定义的Property类型这十分不利于我们的开发我们如何在不修改JavaBean的条件下使用到JavaFX的Property的一些优良方法呢答案是我们通过反射获得基本类型对应的Property目前仅限于booleandoubleintegerlongstringfloatList等基本类型不支持封装对象。 一般我们写的JavaBean都是基本类型的但是JavaFXBean的设计哲学是这些属性都应该是JavaFX定义的Property类型这十分不利于我们的开发我们如何在不修改JavaBean的条件下使用到JavaFX的Property的一些优良方法呢答案是我们通过反射获得基本类型对应的Property目前仅限于booleandoubleintegerlongstringfloatList等基本类型不支持封装对象。
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/095306_9950a9af_2067650.png "微信截图_20190629095237.png") ![输入图片说明](README/wrap_Javabean.png "wrap_Javabean.png")
而本次设计的过程中希望尽量避免操作界面相关的Property等方法而是直接操作JavaBean类。例如下面代码。 而本次设计的过程中希望尽量避免操作界面相关的Property等方法而是直接操作JavaBean类。例如下面代码。
@@ -291,7 +268,7 @@ public class Student {
实现效果是: 实现效果是:
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/022103_bc9aeb7e_2067650.gif "bindhow.gif") ![输入图片说明](README/bindhow.gif "bindhow.gif")
直接操作JavaBean类就会通过动态绑定修改界面不需要讲JavaBean转换为JavaFX Bean可以减少开发中的类型转换。 直接操作JavaBean类就会通过动态绑定修改界面不需要讲JavaBean转换为JavaFX Bean可以减少开发中的类型转换。
@@ -304,10 +281,10 @@ public class Student {
``` ```
就可以让这个没有标题的窗口可以被拖动而且能拉伸(默认打开,可以关闭) 就可以让这个没有标题的窗口可以被拖动而且能拉伸(默认打开,可以关闭)
![输入图片说明](https://images.gitee.com/uploads/images/2019/0630/135524_d0b03d5f_2067650.gif "moveable.gif") ![输入图片说明](README/moveable.gif "moveable.gif")
![输入图片说明](https://images.gitee.com/uploads/images/2019/0630/135637_cb0e0a89_2067650.gif "resizeAble.gif") ![输入图片说明](README/resizeAble.gif "resizeAble.gif")
### 数据绑定 ### 数据绑定
@@ -347,7 +324,7 @@ public class Student {
``` ```
如图所示: 如图所示:
![输入图片说明](https://images.gitee.com/uploads/images/2019/0724/231705_976181ba_2067650.gif "expression.gif") ![输入图片说明](README/expression.gif "expression.gif")
@@ -359,7 +336,7 @@ public class Student {
private Label pswMsg;//任何psw中的内容都会同步到pswMsg中 private Label pswMsg;//任何psw中的内容都会同步到pswMsg中
``` ```
如图所示 如图所示
![输入图片说明](https://images.gitee.com/uploads/images/2019/0724/232237_7e243f15_2067650.gif "expressionV2V.gif") ![输入图片说明](README/expressionV2V.gif "expressionV2V.gif")
@@ -423,7 +400,7 @@ public class MainController extends FXBaseController implements Initializable {
如图所示: 如图所示:
![20191210-175409-actionDemo](doc/actionDemo/20191210-175409-actionDemo.gif) ![20191210-175409-actionDemo](README/actionDemo/20191210-175409-actionDemo.gif)
### 多窗口切换功能 ### 多窗口切换功能
@@ -543,11 +520,11 @@ public class MainController extends FXBaseController implements Initializable {
1. 跳转至另一个窗口(关闭原窗口) 1. 跳转至另一个窗口(关闭原窗口)
![20191208-125739-close](doc/redirectDemo/20191208-125739-close.gif) ![20191208-125739-close](README/redirectDemo/20191208-125739-close.gif)
2. 弹窗形式弹出窗口(不关闭原窗口) 2. 弹窗形式弹出窗口(不关闭原窗口)
![20191208-125511-not close](doc/redirectDemo/20191208-125511-not_close.gif) ![20191208-125511-not close](README/redirectDemo/20191208-125511-not_close.gif)
#### 不足之处 #### 不足之处
@@ -558,17 +535,17 @@ public class MainController extends FXBaseController implements Initializable {
## 框架的使用 ## 框架的使用
### 内置注解 ### 内置注解
| 名字 | 作用 | 参数 | 要求 | | 名字 | 作用 | 参数 | 备注 |
| ------------- | ------------------------------------------------------------ | --------------------------------------- | ---------------------------------------- | | ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------------------------- |
| @FXData | 标明这个普通bean要装配成javafxBean | fx_id | 重新命名 | | @FXData | 标明这个普通bean要装配成javafxBean | fx_id | 重新命名 |
| @FXScan | 扫描@FXEntity和@FXController注解标记的类 | 要扫描的目录 | 默认当前目录之下所有 | | @FXScan | 扫描@FXEntity和@FXController注解标记的类 | 要扫描的目录 | 默认值是当前目录之下所有 |
| @FXController | 标记这个类为控件 | pathfxml文件地址 | 无 | | @FXController | 标记这个类为控件 | pathfxml文件地址 | 无 |
| @FXWindow | 标记这个控件要以单独窗口显示 | title窗口名字,也可以设置窗口长度宽度 | 无 | | @FXWindow | 标记这个控件要以单独窗口显示 | 1. title 设置窗口名字<br/>2. mainStage 标记是否为主舞台<br/>3. preHeight, preWidth 预设长宽度<br/>4. minHeight, minWidth 最小长宽度<br/>5. resizable, draggable 设置可拉伸可拖拽<br/>6. style 设置StageStyle | 无 |
| @FXEntity | 标记JavaBean系统会自动识别@FXField然后包装JavaBean为JavaFXBean | 重命名 | | | @FXEntity | 标记JavaBean系统会自动识别@FXField然后包装JavaBean为JavaFXBean | 重命名 | |
| @FXField | 代表这个属性要映射为Property属性 | | | | @FXField | 代表这个属性要映射为Property属性 | | |
| @FXSender | 信号发送者 | name重命名信号 | | | @FXSender | 信号发送者 | name重命名信号 | |
| @FXReceiver | 信号接收函数 | name订阅的发射者函数名 | 不可空 | | @FXReceiver | 信号接收函数 | name订阅的发射者函数名 | 不可空 |
| @FXRedirect | 标记函数为重定向函数 | close是否关闭当前窗口 | 返回值为某个使用了FXView注解的Controller | | @FXRedirect | 标记函数为重定向函数 | close是否关闭当前窗口 | 返回值为某个使用了FXView注解的Controller |
### 两个工厂和一个context ### 两个工厂和一个context
@@ -716,6 +693,6 @@ public class Student {
从我们代码可以看出我们很少有操作界面的操作并且我们操作的对象都是基本类型的对象这样的操作十分有利于我们将普通的项目转换为JavaFX项目最终运行起来将会是这样 从我们代码可以看出我们很少有操作界面的操作并且我们操作的对象都是基本类型的对象这样的操作十分有利于我们将普通的项目转换为JavaFX项目最终运行起来将会是这样
![输入图片说明](https://images.gitee.com/uploads/images/2019/0629/160249_00f41d22_2067650.gif "helloWorldDemo.gif") ![输入图片说明](README/helloWorldDemo.gif "helloWorldDemo.gif")

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 KiB

BIN
README/JavaFX-Plus_en.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

BIN
README/bindhow.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

BIN
README/controllerConfig.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
README/demo1.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
README/expression.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

BIN
README/expressionV2V.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
README/helloWorldDemo.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

BIN
README/modulesAction.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 KiB

BIN
README/moveable.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 977 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 MiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 MiB

BIN
README/resizeAble.gif Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

BIN
README/wrap_JavaBean.png Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -5,7 +5,7 @@ import java.lang.annotation.*;
/** /**
* @Author jack * @Author jack
* @Date:2019/6/25 1:36 * @Date:2019/6/25 1:36
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) @Target(ElementType.FIELD)
@Inherited @Inherited

View File

@@ -77,6 +77,9 @@ public class FXBaseController extends Pane {
} }
} }
/**
* 关闭舞台
*/
public void closeStage() { public void closeStage() {
if (isWindow) { if (isWindow) {
this.stage.close(); this.stage.close();

View File

@@ -5,6 +5,7 @@ import cn.edu.scau.biubiusuisui.annotation.FXRedirect;
import cn.edu.scau.biubiusuisui.annotation.FXWindow; import cn.edu.scau.biubiusuisui.annotation.FXWindow;
import cn.edu.scau.biubiusuisui.entity.FXBaseController; import cn.edu.scau.biubiusuisui.entity.FXBaseController;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.PasswordField; import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
@@ -30,6 +31,12 @@ public class RegisterController extends FXBaseController {
@FXML @FXML
public void registerClick() { public void registerClick() {
if (validate()) {
UserEntity userEntity = new UserEntity();
userEntity.setUsername(usernameTF.getText());
userEntity.setPassword(passwordPF.getText());
userEntity.setEmail(emailTF.getText());
}
} }
@@ -42,5 +49,33 @@ public class RegisterController extends FXBaseController {
public String redirectToLogin() { public String redirectToLogin() {
return "LoginController"; return "LoginController";
} }
// 校验
private boolean validate() {
boolean retCode = false;
if (null != passwordPF.getText() && null != confirmPasswordPF.getText()) {
if (!passwordPF.getText().equals(confirmPasswordPF.getText())) {
retCode = false;
new Alert(Alert.AlertType.ERROR, "两次密码不一致");
} else {
retCode = true;
}
} else if (null == usernameTF.getText()) {
retCode = false;
new Alert(Alert.AlertType.ERROR, "用户名不能为空");
} else if (null == emailTF.getText()) {
retCode = false;
new Alert(Alert.AlertType.ERROR, "邮箱不能为空");
}
return retCode;
}
private void clearAllInput() {
usernameTF.setText("");
emailTF.setText("");
passwordPF.setText("");
confirmPasswordPF.setText("");
}
} }

View File

@@ -0,0 +1,38 @@
package cn.edu.scau.biubiusuisui.example.redirectDemo;
/**
* @author suiyu_yang
* @description 简单的用户实体
* @date 2020/1/14 22:39
* @email suiyu_yang@163.com
*/
public class UserEntity {
private String username;
private String password;
private String email;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}

View File

@@ -2,6 +2,7 @@ package cn.edu.scau.biubiusuisui.stage;
import cn.edu.scau.biubiusuisui.entity.FXBaseController; import cn.edu.scau.biubiusuisui.entity.FXBaseController;
import java.util.ArrayDeque;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -15,10 +16,21 @@ public class StageManager {
private static StageManager stageManager = null; private static StageManager stageManager = null;
private static Map<String, FXBaseController> windows = new ConcurrentHashMap<>(); // private static Map<String, FXBaseController> windows = new ConcurrentHashMap<>(); //
/**
* @author yangsuiyu
* @description 1.2新增属性
*/
private static ArrayDeque<FXBaseController> windowsStack = new ArrayDeque<>();
private StageManager() { private StageManager() {
} }
/**
* 单例
*
* @return
*/
public static synchronized StageManager getInstance() { public static synchronized StageManager getInstance() {
if (stageManager == null) { if (stageManager == null) {
stageManager = new StageManager(); stageManager = new StageManager();
@@ -28,7 +40,6 @@ public class StageManager {
public void registerWindow(FXBaseController fxBaseControllerProxy) { public void registerWindow(FXBaseController fxBaseControllerProxy) {
if (fxBaseControllerProxy.isWindow()) { if (fxBaseControllerProxy.isWindow()) {
// System.out.println("StageController: "+(fxBaseControllerProxy.getStage() == null));
windows.put(fxBaseControllerProxy.getName(), fxBaseControllerProxy); windows.put(fxBaseControllerProxy.getName(), fxBaseControllerProxy);
} }
} }
@@ -37,8 +48,12 @@ public class StageManager {
windows.get(controllerName).closeStage(); windows.get(controllerName).closeStage();
} }
/**
* 无参数跳转
*
* @param controller
*/
public void redirectTo(Object controller) { public void redirectTo(Object controller) {
// System.out.println("跳转->" + controller);
windows.get(controller).showStage(); windows.get(controller).showStage();
} }
} }