JAVAFX8开发过程中的问题记录

起源

上Java课的时候没有好好学,到后来自学一段时间才真正算是入门,不过听说Java不适合做桌面程序,所以对Swing这一块根本都没有看,而且也忽略了线程和文件IO那一块,到找工作和实际工作的时候才后悔莫及,不过幸好后来接触到的Android和J2EE慢慢地把这部分欠缺弥补回来了。听说有JavaFX这个东西的是在大三实训的时候,需要基于Java做一个类似局域网聊天工具的桌面程序,隔壁老师建议他带的几个小组使用JavaFX做界面,成果汇报的时候我惊呆了:这是个什么东西啊,按钮上的汉字居然不像Swing那样难看了,风格居然和bootstrap或者Mac OS有几分相似,从此对JavaFX有了一种特殊的关注和喜爱。

据说JAVAFX和当初的Applet都是为了和Flash一争高下,但是并不能。JAVAFX可以做出非常漂亮的RIA程序,于是我决定试一下。实训回来后我尝试着做一些程序,但是都是了解了一些皮毛,做了一个文本编辑器,连Swing JOptionPane那样的模态窗口都不知道如何实现,校招开始了,最后只能草草收场。毕设的时候用Java做声纹识别,打算界面用JavaFX做,结果后来觉得本来时间就不多,如果把那么多的时间花费在开发界面上有点不划算,所以又放弃了。如今JDK1.8都出了,基于JDK1.8的JavaFX8也出了,据了解到JavaFX已经过去一年多了,也工作了一段时间,和几个人合租,正好需要一个记录和结算集体支出的软件,灵机一动,奋战四个周末,终于完成,记录在开发过程中的一些问题以备后面查询。

开发准备

-工具:JDK1.8 + E(fx)clipse + Windows8
-数据库:Access
-辅助设计:JavaFX Scene Builder 2.0
E(fx)clipse是专门针对JavaFX开发者设计的一个Eclipse版本,也可以用纯净的Eclipse安装JavaFX插件即可。
数据库使用Access主要是看中了他的移植性好,开销小,程序也不需要太复杂的存储和查询。
JavaFX Scene Builder可以通过拖动组件来设计界面并保存为fxml格式供程序使用,非常方便。

数据库

数据库设计非常简单,四张表:user、category、record、sumtime,分别用来储存用户、分类、记录和结算时间等信息。逻辑非常简单,登录后根据不同的身份分配权限,对支出记录做增删改查操作,结算时显示参与结算的用户应得或应出的金额就对了。
不过在调试数据库连接的时候出了一个大问题:以前使用ODBC的方式可以像这样连接Access数据库的

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
String dbur1 = "jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=d://a1.mdb";
Connection conn = DriverManager.getConnection(dbur1, "username", "password");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from Table1");
while (rs.next()) {  System.out.println(rs.getString(1));
}
rs.close();
stmt.close();
conn.close();  

这个sun.jdbc.odbc.JdbcOdbcDriver也不要下载额外的jar,它就在jre/lib/rt.jar里面,但是JDK1.8之后Java不再支持ODBC连接,所以总会报ClassNotFoundException : sun.jdbc.odbc.JdbcOdbcDriver,最后找到了解决办法:通过JDBC方式连接,但是要下载第三方包Access_JDBC30.jar,连接方式也要换成AccessDriver方式连接,一下子就高大上了

String strurl="jdbc:Access:///C:/x.mdb";
try {Class.forName("com.hxtt.sql.access.AccessDriver");conn=DriverManager.getConnection(strurl);sta = conn.createStatement();
} catch (ClassNotFoundException | SQLException e) {e.printStackTrace();
}

开发到中后期的时候,发现老是会报错:HXTT Access Version 5.1 For Evaluation Purpose allows executing not more than 50 queries once.查了下,原来这个包不是官方的,没有限制的版本是要给钱的,不给钱从AccessDriver加载开始,查询次数不能超过50次,据说单次查询结果还不能超过1000条。我找了找看看有没有替代的解决办法,发现JDK1.8 Access JDBC解决方案仅此一家,而不使用JDK1.8的后果就是不能使用JavaFX的新特性。难道要换Mysql?可是我找了破解版的jar,就继续用Accesss咯~

Hello World!

package application;import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;public class Main extends Application {@Overridepublic void start(Stage primaryStage) {try {BorderPane root = new BorderPane();Scene scene = new Scene(root,400,400);scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());primaryStage.setScene(scene);primaryStage.show();} catch(Exception e) {e.printStackTrace();}}public static void main(String[] args) {launch(args);}
}

这是用E(fx)clipse新建JavaFX应用自动生成的一个例子,运行结果如下图:

主要界面和功能

登录界面

主界面

设置界面


记账界面

结算界面

问题记录

配置文件

配置文件用properties文件记录,然而整个系统可配置的东西就是数据库路径,因此properties文件里面只有一个property:db.path,可以通过登录界面右上角的黄色按钮配置。其实这种小工具连数据库都可以不要,所有东西都用properties文件存储,不过这样风险很高,频繁操作文件效率也不高,当记录足够多的时候可能不太方便,这些都是我猜的,所以就还是用数据库存储吧。

模态窗口

很早之前为模态窗口发愁,以为JavaFX根本就不可能实现模态窗口,用Swing的时候直接使用JOptionPane就可以调用各种模态窗口,搜索一番并结合API,发现这样做就可以实现模态窗口

public class Add{private Stage stage;public Add(Stage stage) {this.stage = stage;final Stage primaryStage = new Stage();primaryStage.initStyle(StageStyle.UNDECORATED);primaryStage.initModality(Modality.APPLICATION_MODAL);primaryStage.initOwner(stage);primaryStage.getIcons().add(new Image(getClass().getResourceAsStream( "greenorange.png" )));String filename = "add.fxml";Pane page;try {page = (Pane) FXMLLoader.load(getClass().getResource(filename));Scene scene = new Scene(page);primaryStage.setScene(scene);primaryStage.show();} catch (IOException e) {e.printStackTrace();}}
}

只要使用

primaryStage.initModality(Modality.APPLICATION_MODAL);
primaryStage.initOwner(stage);//stage为父窗口stage

就能设置此窗体属性为模态,并且用new Add(PARENT_WINDOW_STAGE)调用时,将父窗口的stage作为参数传入就OK了

去掉Windows默认窗体样式

如果在Mac上使用JavaFx,窗体样式和content应该比较和谐,但是在windows上却不那么和谐了,在初始化Stage的时候调用

primaryStage.initStyle(StageStyle.UNDECORATED);

就可以去掉窗口,不过去掉之后窗口无法拖动、最大化和最小化,需要自己添加按钮实现。然而在实现拖动的时候又出了个大问题:OnDragged监听器在鼠标每次移动后会重新计算窗口的位置,导致窗口会先将左上角移动到鼠标位置之后再跟随鼠标移动,这个用户体验太不好了。最后找到原因:实现窗口拖拽需要监听两个事件,一个是鼠标按下时(OnMousePressed),另一个是鼠标拖拽时(OnMouseDragged)。前者记录鼠标位置相对于stage的横纵坐标,后者用于重新定位。然而之前实现拖拽的时候鼠标按下用的OnMouseClicked,Press和Click的区别是,前者是点击下去还未弹起就触发,后者是弹起后再触发,因为拖拽过程中一直没有弹起,所以之前还未记录鼠标的初始位置就开始了拖拽,导致相对坐标始终为(0,0),当然先要对其左上角再拖动了,具体代码如下:

public class Login extends Application{private Pane animationPane;private Double stageDragInitialX;private Double stageDragInitialY;@Overridepublic void start(Stage primaryStage) throws Exception {primaryStage.initStyle(StageStyle.UNDECORATED);primaryStage.getIcons().add(new Image(getClass().getResourceAsStream( "greenorange.png" )));String filename = "login.fxml";Pane page = (Pane) FXMLLoader.load(getClass().getResource(filename));initControls(page);//初始化控件addListener(primaryStage);//为控件添加监听器Scene scene = new Scene(page);primaryStage.setScene(scene);primaryStage.show();private void initControls(Pane page) {animationPane = (Pane) page.getChildren().get(0);}private void addListener(Stage primaryStage) {animationPane.setOnMouseDragged(new EventHandler<MouseEvent>() {@Overridepublic void handle(MouseEvent event) {primaryStage.setX(event.getScreenX() - stageDragInitialX);primaryStage.setY(event.getScreenY() - stageDragInitialY);}});animationPane.setOnMousePressed(new EventHandler<MouseEvent>() {@Overridepublic void handle(MouseEvent event) {stageDragInitialX = event.getScreenX() - primaryStage.getX();stageDragInitialY = event.getScreenY() - primaryStage.getY();}});}
}

TableView刷新

程序里使用了很多次TableView,JavaFX的TableView不像Jquery-easyUI那样一行一行来加载的,而是通过一列一列来加载的,多用几次就知道该怎么做了。TableView的数据源是一个ObservableList,只要是Observable的属性,只要属性值改变,引用这个属性的对象也会立刻加载新的属性,所以TableView刷新不需要像Android ListView那样需要notify一下。但是按照这个原理有时候并不能正常刷新,比如要重新加载整个table,使用OLD_OBSERVABLE_LIST = NEW_OBSERVABLE_LIST 这样是不行的,即使再次使用TableView.setItems(NEW_OBSERVABLE_LIST)也不会刷新。我的解决办法是,如果新的数据集和就旧的数据集长度一样就使用FXCollection.copy()函数,或者先clear再一个个加进去,后者特别适用于长度不同的情况。最后我发现不是不刷新,而是数据集更新方式不对,直接在List层面赋值不会有任何效果,但是直接改动List里面的元素会刷新,前面的解决方法就是变态地更改List里面的元素,而且使用TableView.refresh()可以直接强制刷新,也就是说使用TableView.setItems(NEW_OBSERVABLE_LIST)之后再使用TableView.refresh()就可以强制刷新!

CallBack函数

Javascript何以非常简单的实现callback功能,但是Java不能把method作为参数传递,因此回调函数一般通过实现接口的方法实现,之前从来没有尝试过callback函数,这次自定义了一个CallBack接口,定义一个callBack()函数,将不同的实现了CallBack接口的对象作为参数传入各种模态窗口,完成某一个操作时调用特定的CallBack接口的callBack()方法,这样模态窗口就成了一个正真公用的类,而不涉及具体业务逻辑。

总结

-没使用统一的权限存储管理,而是用代码根据用户名来判断用户权限。
-很多Application的公用方法,比如初始化组件、添加监听器、拖拽功能等没有通过Override方式实现,比如可以写一个BaseApplication extends Application,在BaseApplication预定义或者初步实现一些方法,所有新的Application全部extends BaseApplication,通过覆盖父方法实现更丰富的功能。
-公用方法提取粗糙,比如OKCancelDialog完全不用独立写一个方法,而是像JOptionPane一样通过静态方法调用,而且可以使用返回值,让更多的业务逻辑代码在业务类实现。

JavaFX8开发过程中的问题记录相关推荐

  1. 开发过程中的异常记录

    1.Tomcat 无法访问 使用了网络代理,没有勾选'跳过本地代理'的那个选项导致Tomcat无法访问 2.文件删除失败的问题 开发中,写了一个文件删除方法,在项目中使用用于删除解析过的csv文件和x ...

  2. Asp.net开发过程中,我们会遇到很多Exception

    在Asp.net开发过程中,我们会遇到很多Exception,不处理这些Exception的话会出现很难看的页面. 还有一些我们未预料到的Exception,当发生Exception时,我们也必须进行 ...

  3. 项目开发过程中的收获与思考

    2013年7月,我正式毕业了,到公司入职,也就正式成为了一名菜鸟程序员.到今天,2014年1月3日,目前主要的工作是公司一个项目中的一个功能模块,到我进入项目组算起,已经过了四个月了.因此,想写点东西 ...

  4. 对复杂业务组件在实际开发过程中被调用的反思

    写这篇文章的初衷是为了记录我在修复项目中一个复杂业务组件中的bug而引起其他依赖这个组件的功能无法使用的过程中,对使用.维护复杂业务组件的一些思考 原文地址 Bug发生原因 我所在的项目组中, 有一个 ...

  5. web开发过程中经常用到的一些公共方法及操作

    进化成为程序猿也有段岁月了,所谓的经验,广度还是依旧,只不过是对于某种功能有了多种实现方式的想法.每天依旧不厌其烦的敲打着代码,每一行代码的回车似乎都有一种似曾相识的感觉.于是乎:粘贴复制,再粘贴再复 ...

  6. 移动应用开发过程中的迭代式原型设计

    \ 主要结论 \ 移动应用原型创建过程中采用迭代式快速开发方法的重要性. \ 可以从对手身上学到什么,如何从他们的失误中获益. \ 如何为你的应用定义USP,如何通过故事板(Storyboarding ...

  7. 软件项目开发过程中主要遇到的核心问题小结

    最近在北京组织管理某银行的现金管理系统项目的开发,对软件项目开发过程中遇到的问题进行一些心得体会小结,怕时间长了没及时写下来时间久了被遗忘了,现在趁项目还在开发过程,把体会相对深刻时,感受到的一些问题 ...

  8. mysql开发问题解决_开发过程中mysql常见问题的解决方法

    本篇文章给大家带来的内容是关于开发过程中mysql常见问题的解决方法,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 记录开发过程中遇到mysql相关的问题以及解决方法,长期更新. 远 ...

  9. 探讨如何确保对日软件外包开发过程中的质量

    2019独角兽企业重金招聘Python工程师标准>>> 摘 要:对日软件外包是目前在国内发展迅速的一个行业,但是由于国界.地域.语言.习俗等差异,导致了对日软件外包的质量得不到保证. ...

最新文章

  1. 并行计算及GPU简介
  2. fastdfs 吗 支持windows_从零搭建分布式文件系统MinIO比FastDFS要更合适
  3. 服务器的虚拟主机用途,服务器的虚拟主机用途
  4. String类型的算法题(获取子串在主串中出现的次数)和(获取两个字符串中最大相同子串)-Java代码实现
  5. 人类高质量编程语言Delphi盛大发布2021新版本RAD Studio 11 Alexandria
  6. tsp问题动态规划python_TSP问题——动态规划
  7. 夏昕的3部开发手册.- -
  8. 局域网共享打印机教程
  9. Mysql启动之报错:The server quit without updating PID file
  10. 乐鑫Esp32学习之旅② 巧用eclipes编辑器,官方教程在Windows下搭建esp32开发环境,打印 “Hello World”。
  11. 聚观早报 | ChatGPT 停止 Plus 付费;李子柒油管广告收益登顶热搜
  12. 微信小程序 java校园二手物品交易系统uniapp
  13. 【前端】【html5/css3】前端学习之路(二)(CSS3新选择器/CSS3盒模型/CSS3过渡效果)
  14. ffmpeg音频视频转换命令笔记
  15. 关于工作经验积累到底是积累的什么?
  16. Lua-cjson使用笔记
  17. android蓝牙 uuld,BLE4.0低功耗蓝牙协议总结
  18. RFID资产管理解决方案-RFID固定资产管理-新导智能
  19. 通达信岛形反转选股公式,选出底部岛形反转形态
  20. 数据库:精通MySQL

热门文章

  1. 微信支付的软件架构也太特么牛逼了吧...
  2. stm32F407 连接 对射式红外对管 样例
  3. 网络游戏(联网进行的多人电子游戏)
  4. java程序设计之网络编程基础教程_Java程序设计之网络编程基础教程
  5. 新中新二代身份证读卡器DKQ-A16D C# Demo 无法运行问题
  6. 【渝粤题库】陕西师范大学151107 管理会计 作业(高起专)
  7. android横屏ui,换个角度看风景 手机产品UI设计之横屏模式(2)
  8. java展示树形结构的两种方式
  9. 创业公司如何设计合伙人股权的进入和退出机制
  10. Linux批量改变图片大小,如何用Pix相册批量转换图片格式和调整大小