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开发总结相关推荐

  1. 【JavaFx】eclipse搭建JavaFx开发环境

    JavaFx环境搭建 帮数媒的同学写一个作业,灵机一动想写一个小游戏,花了一点时间写好了基本逻辑,准备写个小界面.习惯了 Idea 和 Scene Builder 开发 JavaFx 项目,但是为了帮 ...

  2. JavaFX开发桌面,移动端,嵌入式权威指南(二)—— 如何应用JavaFX开发用户界面

    目录 概述 编程与声明创建用户界面 以节点为中心的UI的简介 确定舞台是否处于焦点位置 控制舞台的z轴顺序 设置场景中的光标 通过ID找到场景中的节点 从场景访问舞台 向场景内容序列中插入节点 场景中 ...

  3. JavaFX开发桌面,移动端,嵌入式权威指南(一)—— JavaFX桌面入门小项目

    目录 概述 代码 结果 总结 JavaFX应用 舞台和场景 显示图像 显示文字 将文本节点作为组 动画文本向上滚动 概述 JavaFX是用于构建富互联网应用程序的Java库.使用JavaFX开发的应用 ...

  4. 用JavaFx开发一个小游戏

    老婆特喜欢一个叫做ColorLinez的小游戏,但这个叫做WinLinez的小游戏的界面实在太老了,而且很多老婆大人想要的功能都没有,因此我一直想给老婆亲手做一个,她想要的,谁让咱是程序员呢? 我目前 ...

  5. 利用JavaFx开发RIA桌面应用-在线资料

    转载请注明来源-作者@loongshawn:http://blog.csdn.net/loongshawn/article/details/52805751 1.前言 虽说java已经不是主流的桌面应 ...

  6. 利用JavaFx开发RIA桌面应用-文件拖拽

    转载请注明来源-作者@loongshawn:http://blog.csdn.net/loongshawn/article/details/53023429 1 背景 给JavaFx中的TextFie ...

  7. javafx 开发教程与示例

    整理javafx开发知识点 一.开发工具 java 端:idea 界面可视化:JavaFX Scene Builder 2.0 二.开发步骤 1.创建fx工程 2.设计fxml文件的界面 3.创建关联 ...

  8. 利用JavaFx开发RIA桌面应用-构架思路

    转载请注明来源-作者@loongshawn:http://blog.csdn.net/loongshawn/article/details/53174058 背景 最近在给公司其他部门开发桌面应用,起 ...

  9. 【数据库实验】《小型MIS的开发》— JavaFx 开发 民航票务管理系统

    <小型MIS的开发> 需求描述 数据库建表 用户表的 SQL 航班信息表的 SQL 项目演示 GitHub 网址获取源代码 比较重要的知识点 JavaFx 中 spring 工厂如何创建 ...

最新文章

  1. Allan方差分析方法的直观理解
  2. R语言ggplot2可视化分面图(faceting):自定义分面图可视化、ggplot2可视化分面图并移除分面图之间的边框线条(Remove Panel Border Lines in a facet
  3. 操作系统导论中文版 pdf_一分钟带你认识微软操作系统 Windows 10
  4. mysql数据库主从同步
  5. SVN的使用(服务端与客户端)
  6. 来自过气科技网红的2020年终总结
  7. Python中MD5加密字符串
  8. 【温故知新】CSS学习笔记(盒子水平居中方法)
  9. 发现一个好的索引-阳神
  10. HDU - 2243 考研路茫茫——单词情结(AC自动机+矩阵快速幂)
  11. oracle估算大小,Oracle 估算數據庫大小的方法
  12. java编译时文件是什么,JAVA编译出现 进行语法解释时已抵达文件结尾 是什么意思?...
  13. Linux 搜索文件
  14. 车主吐槽某电动车保养割韭菜,却遭其总裁公开恐吓?车主:必须视频道歉
  15. 在TypeScript中使用React钩子
  16. ad焊盘对参考点复制_点对点复制
  17. 瑞萨RH850开发环境搭建
  18. nucleo STM32F072 PWM 测试
  19. PostgreSQL数据库学习手册之大对象
  20. 4.链表LinkedList

热门文章

  1. hndlrsvc.exe
  2. windows下vs2015编译POCO及使用poco操作sqlite
  3. MATLAB中AVP例子学习
  4. 想成为UI设计师都需要学习哪些软件工具
  5. 65.android 简单的写字动画效果
  6. Fabric配置fabric-sample工程目录,并生成证书
  7. RS485转以太网网关BL110之44:实现欧姆龙 PLC CJ/CS/CP 接入阿里云平台
  8. 苹果手机NFC取电 苹果手机亮屏取电方案 IOS NFC取电 苹果手机壳无源方案 iphone来电显示 苹果手机NFC无源方案
  9. HTB-Templated
  10. ViT Patch Embedding理解