javafx开发总结
javafx overview
这学期做的两个java项目(喵photoshop和喵wechat)中,我都承担了不少的javafx代码,现在磕磕绊绊也比较容易写出能跑的东西了。便介绍一下我对javafx的总结。
官方介绍
JavaFX 是一个开源的下一代客户端应用平台,适用于基于Java构建的桌面、移动端和嵌入式系统。 它是许多个人和公司的共同努力的成果,目的是为开发丰富的客户端应用提供一个现代、高效、功能齐全的工具包。
项目结构
IDEA一路default后创建出来的javafx项目如图所示。
在src的package中,javafx程序的入口是Helloapplication,在其中调用了
new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
是从对应的resourses中根据某个布局文件建立一个窗口,并通过一系列如setTitle
, setIcon
等方法进行配置,最后显示出来。
在hello-view.fxml
中有
fx:controller="com.example.demo1.HelloController"
意思是,这个布局文件绑定的控制类是com.example.demo1.HelloController
。
综上所述,javafx项目的重要特点是,布局和功能分离,
综上所述,javafx项目的最基本结构就是,一个布局文件对应一个控制类(控制这个布局文件的某个按钮点击后调用什么方法等),然后从布局文件load一个窗口,进行愉快的交互。
用SceneBuilder创建布局
javafx为创建布局提供了官方的很方便的工具:SceneBuilder,创建一个fxml文件以后右键用SceneBuilder点开,大约如图所示。
我们可以在此拖拽各种部件到各种布局中,个人而言,HBox(里面的组件和子布局水平排列)和VBox(垂直排列)的嵌套可以解决绝大多数问题。
如上图所示布局,是在最外侧的AnchorPane
布局中,放入一个VBox,VBox中放入三个HBox,每个HBox中间放置一个label和一个textfield,最下面的放置两个button,并对每一个布局设置其排列规律为水平垂直居中(如保证“帐号”标签和旁边的输入框在所在的HBox里水平垂直居中),再适当调整Margin(部件之间的距离),如设置“帐号”标签右边有20px的间隔,只需要这寥寥几布操作就可以做出这种基础又实用的布局文件。
在SceneBuilder中保存后的fxml文件实际如下:
就像html一样用嵌套的标签和标签的属性确定出布局样式。还是可以拖拽的plus版,真神奇。
为fxml添加样式
javafx可以使用css样式,前端狂喜。
在SceneBuilder中选中组件就可以在右边添加样式,javafx的css阉割了不少,不过只要配色讲究一些也可以做的比较美观。
如喵photoshop的最左边工具栏,实际上只是一个VBox中紧密排列着数个按钮,并对他们设置了取消圆角和背景颜色而已。(虽然看着很麻烦但是用拖拽很愉快的!)
<Button id="button1" onAction="#choose" prefHeight="38.0" prefWidth="42.0" style="-fx-background-radius: 0;" textFill="WHITE"><graphic><ImageView fitHeight="44.0" fitWidth="28.0" pickOnBounds="true" preserveRatio="true"><image><Image url="https://miaotu-headers.oss-cn-hangzhou.aliyuncs.com/photoshopicons/xuanze.png" /></image></ImageView></graphic>
</Button>
除了行内的css样式,我们同样可以引入css文件,上图中工具栏便引入了css文件。
不如说因为行内css不能写伪类选择器(#button1:focused
代表被选中的button1),所以必须绑定一个css文件。
<VBox id="left" prefHeight="691.0" prefWidth="44.0" style="-fx-background-color: #424874;" stylesheets="@style.css"><Button id="button1"></Button><Button id="button1"></Button><Button id="button1"></Button>
</VBox>
#button1 {-fx-background-color: #424874;
}#button1:focused {-fx-background-color: #A6B1E1;
}
控制类
上面提到,一个布局要绑定一个控制类,比如在喵wechat中,登录注册窗口要有一个单独的控制类,里面写着按下“登录”,“注册”按钮要做什么事;消息列表窗口有一个单独的控制器,里面写着怎么根据当前登录用户的不用而显示不同的用户头像,怎么获取这个用户的好友列表等,更不用谈消息窗口的“发消息”按钮如果没有绑定的控制类就更糟糕了。
我们接下来以最简单的编辑资料布局来谈控制类的用法。
<AnchorPane prefHeight="226.0" prefWidth="377.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.mywechat.Edit"><children><VBox alignment="CENTER" prefHeight="226.0" prefWidth="377.0"><children><HBox alignment="CENTER" prefHeight="60.0" prefWidth="377.0"><children><Label text="个人简介" ></Label><TextField fx:id="intro"/></children></HBox><HBox alignment="CENTER" prefHeight="60.0" prefWidth="377.0"><children><Label text="头像url" ></Label><TextField fx:id="url"/></children></HBox><HBox alignment="CENTER" prefHeight="60.0" prefWidth="377.0"><children><Button mnemonicParsing="false" text="提交" onMouseClicked="#submit" /></children></HBox></children></VBox></children>
</AnchorPane>
从上面的布局文件的关键代码中可以看到,fxml的根节点标签中的
fx:controller="com.mywechat.Edit"
便是为该布局文件绑定控制类的最关键代码。
布局和控制类的交互重点有两:
- 我们在fxml文件里给想要在控制类里引用的组件加一个
fx:id
属性,就可以在控制类里使用它。 - 给欲引起事件的按钮加上
onMouseClicked="#submit"
等,便代表点击后就可以调用控制类的submit方法。
要绑定事件的不只是按钮,可以是很多类型的组件,可以绑定的事件也不只是“鼠标点击”,也可以有“鼠标悬浮”,“鼠标拖拽”等等。
再看如下的控制类的代码,其功能一目了然。
public class Edit {public Chatlistcont parentController=null;public TextField intro;public TextField url;public void initialize(){}public void setParentController(Chatlistcont parentController) {this.parentController = parentController;}public void submit(MouseEvent mouseEvent) {if(JdbcFirstDemo.updateuser(parentController.curname,intro.getText(),url.getText())==0){DialogPane dialog = new DialogPane();dialog.setHeaderText(" 恭喜!");dialog.setContentText(" 修改成功!");Stage dialogStage = new Stage();Scene dialogScene = new Scene(dialog);dialogStage.setScene(dialogScene);dialogStage.setResizable(false);dialogStage.show();parentController.intro.setText(intro.getText());parentController.avatar.setImage(new Image(url.getText()));parentController.update();}}
}
public TextField intro; public TextField url;
是我们为之创建fx:id想要引用的组件,在提交方法中,我们通过intro.getText()
, url.getText()
获得其中的文字,再调用公共静态方法JdbcFirstDemo.updateuser
提交到数据库中。
非常简单又优雅的操作对不对,布局和功能分离,真方便啊。
创建窗口
一个javafx项目可能涉及不止一个窗口,如何建立窗口呢,可以先看看上面的Edit窗口是如何被创建出来的。
public void edit(MouseEvent mouseEvent) {Stage newStage = new Stage();//创建窗口,此时未显示FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("edit.fxml"));//获得布局文件的loadertry {newStage.setScene(new Scene(fxmlLoader.load()));//通过loader生成一个scene,设置到窗口上Edit aa=fxmlLoader.getController();aa.setParentController(this);Users cur=JdbcFirstDemo.getuser(curname);aa.intro.setText(cur.intro);aa.url.setText(cur.avatar);newStage.setTitle("编辑资料");//对窗口进行标题,图标的设置newStage.getIcons().add(new Image("https://miaotu-headers.oss-cn-hangzhou.aliyuncs.com/javachat/avatar/tiantianquan.png"));newStage.show();//显示窗口} catch (IOException e) {e.printStackTrace();}}
由此可见,javafx窗口的结构大概如图所示!
窗口就是窗口,场景存放布局,布局中就是我们在SceneBuilder中拖拽构建后生成的嵌套组织,那些我们所定义的Label
, Button
, HBox
等,他们都继承于Node
,也就是说他们都是各种不同类型的节点,嵌套组织于布局中。
为布局动态添加子节点
我们会经常遇到为布局动态添加字节点的情况,比如:
如果有别的用户上线了,要添加到“当前在线”中,当我们选择关注或者取关某位用户,要动态地添加或者移除“我的关注”。
要操作的子节点我已经做成了布局文件userinfo.fxml
这里我经常是这么处理的,请看关键代码
public VBox all;//是当前在线列表的容器
public void update(){all.getChildren().clear();//先清空容器int len=ret.size();//ret是服务器返回的用户列表for(int i=0;i<len;i++){FXMLLoader loader = new FXMLLoader(HelloApplication.class.getResource("userinfo.fxml"));AnchorPane tmp=null;//userinfo.fxml的根节点是AnchorPanetry {tmp=(AnchorPane) loader.load();} catch (IOException e) {e.printStackTrace();}all.getChildren().add(tmp);}}
getChildren()
方法可以获得节点的子节点列表,可以clear()
或者add()
。通过这种方法可以动态改变布局。
布局load()可以获得控制类实例
这是笨蛋的我宝贵的摸索出的经验!
在开发photoshop的时候,我希望点击外部的容器的“+”就可以通过getChildren().add()
在列表中加上一个从fxml文件加载的子节点(就像上面一样),但是我希望在每个子结点上放一个“-”按钮,点击后可以删除这个图层。
但是若要在布局中删除这个子节点的话,必然不能让这个子节点的控制类自己删除自己,只能先获得它爹,再调用他爹的getChildren.remove()
,但是getChildren
不是公有方法,我一度以为不能通过点击子结点上的删除按钮删除自己,所以在父结点上做了删除按钮,选中要删除的子节点后点击父结点上的按钮再删除。
后来我才知道,javafx有一个很重要的实质,也就是load一次布局就相当于创建了一个控制类实例,如下:
如果我们点击了子节点item上的删除按钮的时候可以获得container的控制类实例,就可以调用父节点删除子节点自己了。
返回那个在线聊天室的例子。
不难看出,聊天室的上面的代码只能达成有几个在线用户就加几个默认样式的userinfo.fxml
的效果,上面的用户头像或者名字不会随着变化,
真正的关键代码应该是如下的:
public VBox all;//是当前在线列表的容器
public void update(){all.getChildren().clear();int len=ret.size();for(int i=0;i<len;i++){FXMLLoader loader = new FXMLLoader(HelloApplication.class.getResource("userinfo.fxml"));AnchorPane tmp=null;try {tmp=(AnchorPane) loader.load();} catch (IOException e) {e.printStackTrace();}Userinfo aa=loader.getController();//获得了子节点的控制类实例!//Userinfo是因为fx:controller="com.mywechat.Userinfo"aa.setParentController(this);//aa.from=curname;aa.socket=this.socket;aa.name.setText(ret.get(i).name);//在父结点中操作子节点很方便!//这样就可以改子节点的名字了aa.intro.setText(ret.get(i).intro);//这样就可以改子节点的自我介绍了aa.avatar.setImage(new Image(ret.get(i).avatar));//这样就可以改子节点的头像了aa.online=true;int len1=retstar.size();all.getChildren().add(tmp);}}
public class Userinfo {public String from;public Label name;public Label intro;public ImageView avatar;private Chatlistcont parentController;//他爹public void setParentController(Chatlistcont parentController) {this.parentController = parentController;}...public void gotostar()//按下关注按钮以后,父节点代表的当前登录用户,关注这个子节点代表的用户{JdbcFirstDemo.staruser(from,name.getText());//在子结点中调用父节点的方法也很方便了!parentController.updatestar();//新关注一个人以后,父容器update一下,刷新UIparentController.update();}
}
一旦掌握了这种在load布局时,就建立控制类实例之间的关系的方法的话。整个javafx项目中的各个节点都可以根据需要像蜘蛛网一样连接在一起,互相调用方法,获得变量都非常非常方便,开发难度会骤减。
手敲代码建立布局
在实际开发中,并不是所有时候都更适合load布局文件来组织布局的。
比如喵photoshop的下面的情况,每选一个不同的工具,下方的工具栏就会显示不同的组件,难道要为十几个工具都建一个fxml专门放在下面吗?显然有点小题大做了。
public HBox down;//下面一长条
public void pen() {//点击钢笔工具以后down.getChildren().clear();Label label1=new Label("钢笔工具");label1.setPadding(new Insets(4,5,0,5));label1.setTextFill(Color.WHITE);Label label2=new Label("选择粗细(px)");label2.setPadding(new Insets(4,5,0,5));label2.setTextFill(Color.WHITE);ColorPicker colorPicker=new ColorPicker();TextArea gangbicuxi=new TextArea();gangbicuxi.setMaxWidth(30);Button enter=new Button("确定");enter.setOnAction(event -> {//点击按钮的事件});down.getChildren().addAll(label1,colorPicker,label2,gangbicuxi,enter);
}
我是这么处理的,直接在方法中也可以定义组件,设置组件的属性,然后
down.getChildren().addAll(label1,colorPicker,label2,gangbicuxi,enter);
就可以让下面的长条变成这样。
fxml加载布局和代码手撸布局基本是可以互相转换的,可以做到彼此可以做到的事情。不过平常用SceneBuilder非常方便罢了。
java+mysql
虽说和javafx没有什么关系,不过这是我第一次在别的语言中用数据库,我觉得非常神奇。
增
public static int adduser(String name1,String password1) {try{//1. 加载驱动Class.forName("com.mysql.cj.jdbc.Driver");//固定写法//2. 用户信息和url//useUnicode=true&characterEncoding=utf8&&useSSL=trueString url="jdbc:mysql://xxxxxxxxxxxxxx.mysql.rds.aliyuncs.com:3306/mywechat?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8";String name = "root";String password = "xxxxxxx";//3. 连接成功,返回数据库对象 connection代表数据库Connection connection= DriverManager.getConnection(url,name,password);//4. 执行SQL的对象 statement 执行SQL的对象Statement statement = connection.createStatement();//5. 执行SQL的对象 去执行SQL String sql="insert into userinfo(username, password) values ('"+name1+"','"+password1+"');";System.out.println(sql);statement.execute(sql);//6. 释放连接statement.close();connection.close();return 0;}catch (Exception e){e.printStackTrace();return 1;}}
删
Statement statement = connection.createStatement();String sql="delete from userstar where username1='"+name1+"' and username2='"+name2+"';";statement.execute(sql);
查
Connection connection= DriverManager.getConnection(url,name,password);//4. 执行SQL的对象 statement 执行SQL的对象Statement statement = connection.createStatement();ArrayList<Users> tmp=new ArrayList<>();//5. 执行SQL的对象 去执行SQL 可能存在结果,查看返回结果String sql="SELECT * FROM userstar WHERE username1='"+name1+"'";//System.out.println(sql);ResultSet resultSet = statement.executeQuery(sql);//返回的结果集,结果集中封装了我们全部查询的结果while(resultSet.next()){String starring=resultSet.getObject("username2").toString();Users ret=getuser(starring);tmp.add(ret);}//6. 释放连接resultSet.close();statement.close();connection.close();
对于增删改这种不需要返回一条条记录的操作,我们只需要这样,返回一个boolean
statement.execute(sql);
对查询操作,需要不同的语句,返回一个结果集
ResultSet resultSet = statement.executeQuery(sql);//返回的结果集,结果集中封装了我们全部查询的结果
while(resultSet.next()){String starring=resultSet.getObject("username2").toString();//balabala}
//释放连接
resultSet.close();
操作数据库比想象的比简单很多,非常方便!
结语
这是我两次贫瘠的javafx开发经验为我带来的一些学习总结,我实在觉得javafx开发起一些小东西很优雅,因为wpf太强大了我学不会,qt也觉得好麻烦…
我开发javafx项目的总时间共不到两天:
大作业答辩前一天晚上通宵从零写到第二天下午答辩喵photoshop;
昨晚从零通宵到现在开发喵wechat。
可以独立开发小的桌面应用的感觉很不错!
javafx开发总结相关推荐
- 【JavaFx】eclipse搭建JavaFx开发环境
JavaFx环境搭建 帮数媒的同学写一个作业,灵机一动想写一个小游戏,花了一点时间写好了基本逻辑,准备写个小界面.习惯了 Idea 和 Scene Builder 开发 JavaFx 项目,但是为了帮 ...
- JavaFX开发桌面,移动端,嵌入式权威指南(二)—— 如何应用JavaFX开发用户界面
目录 概述 编程与声明创建用户界面 以节点为中心的UI的简介 确定舞台是否处于焦点位置 控制舞台的z轴顺序 设置场景中的光标 通过ID找到场景中的节点 从场景访问舞台 向场景内容序列中插入节点 场景中 ...
- JavaFX开发桌面,移动端,嵌入式权威指南(一)—— JavaFX桌面入门小项目
目录 概述 代码 结果 总结 JavaFX应用 舞台和场景 显示图像 显示文字 将文本节点作为组 动画文本向上滚动 概述 JavaFX是用于构建富互联网应用程序的Java库.使用JavaFX开发的应用 ...
- 用JavaFx开发一个小游戏
老婆特喜欢一个叫做ColorLinez的小游戏,但这个叫做WinLinez的小游戏的界面实在太老了,而且很多老婆大人想要的功能都没有,因此我一直想给老婆亲手做一个,她想要的,谁让咱是程序员呢? 我目前 ...
- 利用JavaFx开发RIA桌面应用-在线资料
转载请注明来源-作者@loongshawn:http://blog.csdn.net/loongshawn/article/details/52805751 1.前言 虽说java已经不是主流的桌面应 ...
- 利用JavaFx开发RIA桌面应用-文件拖拽
转载请注明来源-作者@loongshawn:http://blog.csdn.net/loongshawn/article/details/53023429 1 背景 给JavaFx中的TextFie ...
- javafx 开发教程与示例
整理javafx开发知识点 一.开发工具 java 端:idea 界面可视化:JavaFX Scene Builder 2.0 二.开发步骤 1.创建fx工程 2.设计fxml文件的界面 3.创建关联 ...
- 利用JavaFx开发RIA桌面应用-构架思路
转载请注明来源-作者@loongshawn:http://blog.csdn.net/loongshawn/article/details/53174058 背景 最近在给公司其他部门开发桌面应用,起 ...
- 【数据库实验】《小型MIS的开发》— JavaFx 开发 民航票务管理系统
<小型MIS的开发> 需求描述 数据库建表 用户表的 SQL 航班信息表的 SQL 项目演示 GitHub 网址获取源代码 比较重要的知识点 JavaFx 中 spring 工厂如何创建 ...
最新文章
- Allan方差分析方法的直观理解
- R语言ggplot2可视化分面图(faceting):自定义分面图可视化、ggplot2可视化分面图并移除分面图之间的边框线条(Remove Panel Border Lines in a facet
- 操作系统导论中文版 pdf_一分钟带你认识微软操作系统 Windows 10
- mysql数据库主从同步
- SVN的使用(服务端与客户端)
- 来自过气科技网红的2020年终总结
- Python中MD5加密字符串
- 【温故知新】CSS学习笔记(盒子水平居中方法)
- 发现一个好的索引-阳神
- HDU - 2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)
- oracle估算大小,Oracle 估算數據庫大小的方法
- java编译时文件是什么,JAVA编译出现 进行语法解释时已抵达文件结尾 是什么意思?...
- Linux 搜索文件
- 车主吐槽某电动车保养割韭菜,却遭其总裁公开恐吓?车主:必须视频道歉
- 在TypeScript中使用React钩子
- ad焊盘对参考点复制_点对点复制
- 瑞萨RH850开发环境搭建
- nucleo STM32F072 PWM 测试
- PostgreSQL数据库学习手册之大对象
- 4.链表LinkedList
热门文章
- hndlrsvc.exe
- windows下vs2015编译POCO及使用poco操作sqlite
- MATLAB中AVP例子学习
- 想成为UI设计师都需要学习哪些软件工具
- 65.android 简单的写字动画效果
- Fabric配置fabric-sample工程目录,并生成证书
- RS485转以太网网关BL110之44:实现欧姆龙 PLC CJ/CS/CP 接入阿里云平台
- 苹果手机NFC取电 苹果手机亮屏取电方案 IOS NFC取电 苹果手机壳无源方案 iphone来电显示 苹果手机NFC无源方案
- HTB-Templated
- ViT Patch Embedding理解