当前位置: 首页 > news >正文

JavaFX进阶:学生管理系统结构讲解,复合布局集成,表格数据显示

系统介绍
我们会通过一个学生管理系统来学习
其中 , 分为两个角色
老师 Teacher
public class Teacher {
private Integer id;
private String name;
private String password;
private String gender;
}
学生 Student
public class Student {
private Integer id;
private String name;
private String password;
private String gender;
private String address;
private String hobby;
}

在该系统中 , 主要完成老师管理学生的功能 , 在这节课中 , 主要完成以下操作

登录页面搭建

新建 MyLogin.java ,完成登录界面排版

 

完整代码

public void start(Stage primaryStage) throws Exception {
//新建布局
GridPane gridPane = new GridPane();
//设置居中方式
gridPane.setAlignment(Pos.CENTER);
//调整间隙
gridPane.setHgap(10);
gridPane.setVgap(10);
//新建文本标签:用户名
Label l1 = new Label("老师名称");
//新建输入框
TextField name = new TextField();
//新建文本标签:用户密码
Label l2 = new Label("老师密码");
//新建密码框
PasswordField pwd = new PasswordField();
//登录按钮的创建
Button login = new Button("登录");
//前往注册按钮的创建
Button goRegister = new Button("前往注册");
//添加控件进行位置绑定
gridPane.add(l1, 0, 0);
gridPane.add(name, 1, 0);
gridPane.add(l2, 0, 1);
gridPane.add(pwd, 1, 1);
gridPane.add(login, 0, 2);
gridPane.add(goRegister, 1, 2);
//生成场景并完成布局绑定,同时设定场景大小
Scene scene = new Scene(gridPane, 300, 200);
//主容器标题设置
primaryStage.setTitle("登录页面");
//给主容器绑定场景(让场景显示出来)
primaryStage.setScene(scene);
//不要忘了这一行,让主容器显示
primaryStage.show();
}

 

登录按钮的事件设置
使用 setOnAction 完成事件设置
login.setOnAction(a -> {
})
完成数据取值操作
String username = name.getText();
String password = pwd.getText();
实现数据库验证逻辑
//此处是模拟实现
if ("root".equals(username) && "root123".equals(password)) {
}else{
}
Alert 进阶
之前我们讲过了 Alert 的基本使用 , 现在可以进行进阶操作了 👨‍🏭
public Alert(Alert.AlertType,String,ButtonType...) {
通过分析 Alert 的构造函数:
第一个参数 , 弹框的类型 , 第一次课程中有分析 , 主要是图标的不同
public static enum AlertType {
NONE,
INFORMATION,
WARNING,
CONFIRMATION,
ERROR;
}

 第二个参数,弹框的提示信息

第三个参数,一个按钮可变数组,用于弹框下方显示的按钮

public static final ButtonType APPLY;
public static final ButtonType OK;
public static final ButtonType CANCEL;
public static final ButtonType CLOSE;
public static final ButtonType YES;
public static final ButtonType NO;
public static final ButtonType FINISH;
public static final ButtonType NEXT;
public static final ButtonType PREVIOUS;

 可以可以通过给构造函数中传入多个按钮来自定义弹框

Alert alert = new Alert(Alert.AlertType.ERROR, "登录失败,请重
试",ButtonType.OK,ButtonType.NO,ButtonType.CLOSE);

当调用了弹框的 showAndWait() 方法后,我们会接收到弹框被调用的按钮

Optional<ButtonType> type = alert.showAndWait();

 我们只要做判断,就可以知道选择的按钮了,然后在执行相关的操作

if(type.get()==ButtonType.OK){
}
if(type.get()==ButtonType.NO){
}
if(type.get()==ButtonType.CLOSE){
}
注册页面搭建
使用网格布局搭建页面

完整代码

@Override
public void start(Stage primaryStage) throws IOException {
//新建布局
GridPane gridPane = new GridPane();
//设置居中方式
gridPane.setAlignment(Pos.CENTER);
//调整间隙
gridPane.setHgap(20);
gridPane.setVgap(20);
//文本标签
Label l1 = new Label("老师名称");
Label l2 = new Label("老师密码");
Label l3 = new Label("老师性别");
//输入框
TextField f1 = new TextField();
PasswordField f2 = new PasswordField();
//性别
ToggleGroup group = new ToggleGroup();
RadioButton men = new RadioButton("图标");
RadioButton miss = new RadioButton("图标");
men.setToggleGroup(group);
miss.setToggleGroup(group);
men.setSelected(true);
HBox h1 = new HBox();
h1.getChildren().addAll(men, miss);
//登录按钮的创建
Button register = new Button("注册");
Button cancel = new Button("取消");
//用户名
gridPane.add(l1, 0, 0);
gridPane.add(f1, 1, 0);
//用户密码
gridPane.add(l2, 0, 1);
gridPane.add(f2, 1, 1);
//用户性别
gridPane.add(l3, 0, 2);
gridPane.add(h1, 1, 2);
//按钮
gridPane.add(register, 0, 3);
gridPane.add(cancel, 1, 3);
//生成场景并完成布局绑定,同时设定场景大小
Scene scene = new Scene(gridPane, 400, 300);
//主容器标题设置
primaryStage.setTitle("网格登录");
//给主容器绑定场景(让场景显示出来)
primaryStage.setScene(scene);
//不要忘了这一行,让主容器显示
primaryStage.show();
}

 

切换与新开
现在我们需要给 前往登录 按钮设置点击事件 , 目的是点击它能够打开注册界面 , 所以我们需要了解如何进行页面新开与跳转
场景切换
根据之前的介绍 ,FX 的构成部分分为
Stage 舞台
Scene 场景 , 可以理解为舞台上的节目 , 一个舞台可以呈现多个节目 , 对于场景的切换 , 就是将舞台的场景进行重新设置
setScene(Scene) 就可以完成了

 

我们可以通过代码来实践:
构建两个场景 , 分别放置不同的内容
FlowPane flow01=new FlowPane();
Label l1 = new Label("我是场景一");
flow01.getChildren().add(l1);
Scene s1 = new Scene(flow01);
FlowPane flow02=new FlowPane();
Label l2 = new Label("我是场景二");
flow02.getChildren().add(l2);
Scene s2 = new Scene(flow02);
给场景一放置一个按钮控件 , 当我们点击按钮的时候 , 将舞台场景切换为场景二
Button btn=new Button("切换场景二");
btn.setOnAction(a->{
primaryStage.setScene(s2);
});
flow01.getChildren().add(btn);
设置场景一为默认显示
primaryStage.setScene(s1);
默认视图:

点击按钮后:

 

完整代码

@Override
public void start(Stage primaryStage) throws Exception {
FlowPane flow01=new FlowPane();
Label l1 = new Label("我是场景一");
flow01.getChildren().add(l1);
Scene s1 = new Scene(flow01);
FlowPane flow02=new FlowPane();
Label l2 = new Label("我是场景二");
flow02.getChildren().add(l2);
Scene s2 = new Scene(flow02);
Button btn=new Button("切换场景二");
btn.setOnAction(a->{
primaryStage.setScene(s2);
});
flow01.getChildren().add(btn);
primaryStage.setScene(s1);
primaryStage.show();
}

 

新开窗口
进行到这里 , 同学们应该对于这个 Stage Scene 大概明白的差不多了
一个 Stage 就是一个窗口 , Scene 就是该窗口中显示的内容 , 如果需要新开一个窗口 , 那就意味存在多个舞台 Stage
完成功能:点击按钮新开注册页面
删除注册页面的 main 方法或者是里面的 launch() 方法 , 因为该方法是 JavaFX 程序的入口 , 项目必须有且只需要一个
public class MyRegister extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
//此处省略了页面搭建代码
}
}
编写登录页面 前往注册 点击事件
goRegister.setOnAction(a -> {
try {
//在该处实例化注册页面并调用start方法
//该方法需要一个Stage舞台对象 我们可以直接实例化一个给他
//也可以直接把 primaryStage 给它
new MyRegister().start(new Stage());
} catch (Exception e) {
e.printStackTrace();
}
});

此处会出来两个界面 ,如果需要关闭登录界面,可以调用 对应舞台的 close() 方法

primaryStage.close();

 完整代码

//前往注册按钮的创建
Button goRegister = new Button("前往注册");
goRegister.setOnAction(a -> {
try {
new MyRegister().start(new Stage());
primaryStage.close();
} catch (Exception e) {
e.printStackTrace();
}
});
首页搭建

布局分析

 

结构对比

 

所以搭建整体布局为

BorderPane borderPane = new BorderPane();

 

顶部
需要放入多个控件 , 且位于一行 , 可以选择 FlowPane 或者 HBOX
//顶部
FlowPane topPane = new FlowPane();
Label l1 = new Label("学生名称");
TextField f1 = new TextField();
Button b1 = new Button("查询");
topPane.getChildren().addAll(l1, f1, b1);
topPane.setHgap(10); //这里是为了调整控件左右的间隙
topPane.setPadding(new Insets(10)); //这里是为了调整布局上下的间隙 防止太过紧密
borderPane.setTop(topPane);
底部
与顶部类似
//底部
FlowPane bottomPane = new FlowPane();
Button g1 = new Button("增加");
Button g2 = new Button("删除");
Button g3 = new Button("修改");
Button g4 = new Button("退出");
bottomPane.getChildren().addAll(g1, g2, g3, g4);
bottomPane.setHgap(10);
bottomPane.setPadding(new Insets(10));
borderPane.setBottom(bottomPane);
中部

这个部位是表格控件 TableView

TableView tableView = new TableView();
borderPane.setCenter(tableView);

 

我们需要为表格设置列 TableColumn

TableColumn c1 = new TableColumn("学生编号");
TableColumn c2 = new TableColumn("学生名字");
TableColumn c3 = new TableColumn("学生密码");
TableColumn c4 = new TableColumn("学生性别");
TableColumn c5 = new TableColumn("学生地址");
TableColumn c6 = new TableColumn("学生爱好");

 将列绑定到表格控件中

tableView.getColumns().addAll(c1, c2, c3, c4, c5, c6);

表格控件
列值处理器
表格控件的数据可以来源于 List 集合 , 所以我们可以选择从数据库查询出来的学生 Student 对象集合
//StudentDao
public List<Student> list(){
//此处省略代码
}
我们从 Dao 层拿到学生集合之后 , 需要将该集合中的数据绑定到表格控件中 , 所以我们需要给该控件的列进行代码设置
//c1: 学生编号 -> 对应 Student 对象的id属性
c1.setCellValueFactory(new PropertyValueFactory("id"));
//c1: 学生名字 -> 对应 Student 对象的username属性
c2.setCellValueFactory(new PropertyValueFactory("name"));
//c1: 学生密码 -> 对应 Student 对象的password属性
c3.setCellValueFactory(new PropertyValueFactory("password"));
//c1: 学生性别 -> 对应 Student 对象的gender属性
c4.setCellValueFactory(new PropertyValueFactory("gender"));
//c1: 学生地址 -> 对应 Student 对象的address属性
c5.setCellValueFactory(new PropertyValueFactory("address"));
//c1: 学生爱好 -> 对应 Student 对象的hobby属性
c6.setCellValueFactory(new PropertyValueFactory("hobby"));
其中 , new PropertyValueFactory(xx) 这行代码会自动帮助我们从学生对象中取值对应的属性 , 我们只需要改变列的名称与对
应的属性值 xx 即可完成数据显示
数据绑定
//此处为模拟数据,模拟数据库查询出来的List<Student>集合
List<Student> list = new ArrayList<>() {
{
add(new Student(2, "小明", "1234", "女", "湖南省", "打篮球"));
add(new Student(3, "小李", "1234", "女", "湖南省", "打篮球"));
add(new Student(4, "小虎", "1234", "女", "湖南省", "打篮球"));
add(new Student(5, "小鹿", "1234", "女", "湖南省", "打篮球"));
add(new Student(6, "小黑", "1234", "女", "湖南省", "打篮球"));
}
};
//将集合绑定到表格空间中,我们定义在上方的列值处理器会帮助取出对应的属性值并完成赋值
tableView.getItems().addAll(list);
需要注意的点 : 绑定数据的方式
未指定泛型时候 , 必须使用 FXCollections.observableList(list) 对普通的 List 进行转换才能被表格所识别
指定了泛型后 , 可以直接使用 addAll() 方法合并集合

 

完整代码

//中部
TableView<Student> tableView = new TableView();
borderPane.setCenter(tableView);
TableColumn c1 = new TableColumn("学生编号");
TableColumn c2 = new TableColumn("学生名字");
TableColumn c3 = new TableColumn("学生密码");
TableColumn c4 = new TableColumn("学生性别");
TableColumn c5 = new TableColumn("学生地址");
TableColumn c6 = new TableColumn("学生爱好");
tableView.getColumns().addAll(c1, c2, c3, c4, c5, c6);
//c1: 学生编号 -> 对应 Student 对象的id属性
c1.setCellValueFactory(new PropertyValueFactory("id"));
//c1: 学生名字 -> 对应 Student 对象的username属性
c2.setCellValueFactory(new PropertyValueFactory("name"));
//c1: 学生密码 -> 对应 Student 对象的password属性
c3.setCellValueFactory(new PropertyValueFactory("password"));
//c1: 学生性别 -> 对应 Student 对象的gender属性
c4.setCellValueFactory(new PropertyValueFactory("gender"));
//c1: 学生地址 -> 对应 Student 对象的address属性
c5.setCellValueFactory(new PropertyValueFactory("address"));
//c1: 学生爱好 -> 对应 Student 对象的hobby属性
c6.setCellValueFactory(new PropertyValueFactory("hobby"));
//此处为模拟数据,这里的数据应该是 StudentDao.list()
List<Student> list = new ArrayList<>() {
{
add(new Student(2, "小明", "1234", "女", "湖南省", "打篮球"));
add(new Student(3, "小李", "1234", "女", "湖南省", "打篮球"));
add(new Student(4, "小虎", "1234", "女", "湖南省", "打篮球"));
add(new Student(5, "小鹿", "1234", "女", "湖南省", "打篮球"));
add(new Student(6, "小黑", "1234", "女", "湖南省", "打篮球"));
}
};
//此处为未指定泛型的写法
tableView.setItems(FXCollections.observableList(list));

 

强烈要求:在 TableView 后面指定遍历数据的类型 , TableView<Student>
自定义列值处理器
此处定义在这里是为了进行拓展 , 可自行选择是否需要了解
自定义列
TableColumn <? , String > c7 = new TableColumn ( " 我是拓展列 " );
需要在 TableColumn 后面指定 :
- 第一个 ? 指的是数据集合的类型 , 比如 List < Student > 就可以替换为 Student
- 第二个 String 指的该列显示的数据类型

自定义列处理器

c7 . setCellValueFactory ( row -> {
return new ReadOnlyStringWrapper ( " 我是自定义信息 " );
});J

 

相关文章:

  • HarmonyOS应用开发-网络请求与web组件
  • 电装入股Coherent子公司SiC晶圆制造企业Silicon Carbide LLC
  • 正点原子嵌入式linux驱动开发——Linux Regmap驱动
  • 计算机网络第4章-通用转发和SDN
  • http中的Content-Type类型
  • hdlbits系列verilog解答(always块条件语句)-37
  • Nginx 请求拷贝、请求镜像
  • C语言 || volatile
  • 为什么HTTP用得很好的,开始普及HTTPS呢?
  • react:swr接口缓存
  • [BROADCASTING]tensor的扩散机制
  • Process Monitor 进程监控器 exe监控 windows程序监控
  • gitlab 设置 分支只读
  • Git 安全警告修复手册:解决 `fatal: detected dubious ownership in repository at ` 问题 ️
  • SpringBoot加载测试类属性和配置说明
  • 【笔记】你不知道的JS读书笔记——Promise
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • create-react-app项目添加less配置
  • Django 博客开发教程 16 - 统计文章阅读量
  • echarts的各种常用效果展示
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • JavaScript标准库系列——Math对象和Date对象(二)
  • Javascript弹出层-初探
  • Next.js之基础概念(二)
  • Vue实战(四)登录/注册页的实现
  • vue总结
  • 后端_ThinkPHP5
  • 力扣(LeetCode)22
  • 浅谈Golang中select的用法
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • ​2020 年大前端技术趋势解读
  • !$boo在php中什么意思,php前戏
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #if #elif #endif
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (C语言)球球大作战
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (力扣)循环队列的实现与详解(C语言)
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (顺序)容器的好伴侣 --- 容器适配器
  • (图)IntelliTrace Tools 跟踪云端程序
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .gitignore文件_Git:.gitignore
  • .NET 8 中引入新的 IHostedLifecycleService 接口 实现定时任务
  • .net mvc部分视图
  • .net MVC中使用angularJs刷新页面数据列表
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .NET命名规范和开发约定
  • .php文件都打不开,打不开php文件怎么办
  • /使用匿名内部类来复写Handler当中的handlerMessage()方法
  • @AutoConfigurationPackage的使用