java的ui库分为三代,第一代是awt,第二代是swing,第三代就是javafx了,互相之间是替代关系。桌面开发现在一般用swing和javafx,今天用javafx开发一个简单的日历查询应用。
最终效果如下:
git地址:JavaFX日历实现
javafx开发
javafx开发界面开发有两种方式:
1.通过Java代码来编写。
所有的界面和逻辑都通过Java代码来实现,写的东西比较多。
2.通过JavaFX Scene Builder + Java代码来编写实现。
JavaFX Scene Builder是一种可视化设计工具,它允许通过拖放快速创建应用程序界面。 并且代码创建为XML格式的文件。通过JavaFX Scene Builder拖拽来开发界面,Java来实现逻辑比较简单快速。
下面的实例是通过JavaFX Scene Builder + Java实现的。
下载JavaFX Scene Builder
创建项目
idea新建项目选择Java Fx。
(注意:尽量使用jdk8及8以上,jdk8以下是没有自带javafx的,需要自己引入jar包,自行百度)
建完后的结构如下,Main程序的入口,sample.fxml用于JavaFX Scene Builder拖拽生成界面,Controller用于绑定界面和和处理监听事件:
选择sample.fxml右键open in sceneBuilder,然后选择
然后选择安装好的JavaFX Scene Builder
界面设计
从左上角选择相应的组件到中间进行布局,如图我选择了7个组件,左边是选择的所有组件信息。在中间选择任意一个组件右边都有组件的具体设置,比如长度、宽度、输入框默认提示,组件的名称等。
设置组件的名称,后面Java里会用到:
保存后sample.fxml内容变成如下:
要手动加上 fx:cnotallow="sample.Controller"将sample.fxml文件和Controller文件关联绑定,这样下面写Java代码才能使用fxml里的东西。
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="399.0" prefWidth="627.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<Button fx:id="id_1" layoutX="103.0" layoutY="120.0" mnemonicParsing="false" onAction="#buttonAction1" prefHeight="30.0" prefWidth="119.0" text="获取日历" textFill="#3a6f2e" />
<TextField fx:id="text_1" layoutX="102.0" layoutY="61.0" promptText="请输入年份,如:2021" />
<TextField fx:id="text_2" layoutX="380.0" layoutY="61.0" promptText="请输入月份,如:2" />
<Text layoutX="48.0" layoutY="82.0" strokeType="OUTSIDE" strokeWidth="0.0" text=" 年:" wrappingWidth="35.0" />
<Text layoutX="332.0" layoutY="82.0" strokeType="OUTSIDE" strokeWidth="0.0" text=" 月:" wrappingWidth="35.0" />
<TextArea fx:id="text_3" layoutX="167.0" layoutY="197.0" prefHeight="146.0" prefWidth="274.0" />
</children>
</AnchorPane>
代码:
Controller:
package sample;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable {
@FXML
private Button id_1;
@FXML
private TextField text_1;//从fxml获取组件text_1,用于读取年
@FXML
private TextField text_2;//从fxml获取组件text_2,用于读取月
@FXML
private TextArea text_3;//从fxml获取组件text_3,用于输出
@Override
public void initialize(URL location, ResourceBundle resources)
{}
//点击按钮时触发的事件
public void buttonAction1(ActionEvent actionEvent)
{
String year = text_1.getText();//获取文本框输入的内容
String month = text_2.getText();//获取文本框输入的内容
String result=Service.calculationDate(year,month);
text_3.setText(result);
}
}
service:
package sample;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class Service {
public static String calculationDate(String y, String m) {
char[] yearChar = y.toCharArray();
char[] monthChar = m.toCharArray();
if(null==y||y.length()==0||null==m||m.length()==0){
return "年份或月份不能输入为空。";
}
for (int i = 0; i < yearChar.length; i++) {
boolean isOrNo = Character.isDigit(yearChar[i]);
if (yearChar[0] == '0' || !isOrNo) {
return "年份输入错误,请输入正确的年份。";
}
}
for (int i = 0; i < monthChar.length; i++) {
boolean isOrNo = Character.isDigit(monthChar[i]);
if (yearChar[0] == '0' || !isOrNo) {
return "月份输入错误,请输入正确的月份。";
}
}
int year = Integer.parseInt(y);
int month = Integer.parseInt(m);
if (year < 1900||(year==1900&&month==1)) {
return "年份需要大于等于1900。当年份是1900时,月份需要大于1。";
}
if (month > 12) {
return "月份输入错误,请输入正确的月份。";
}
LocalDate endDate = LocalDate.of(year, month, 1);//设置输入的日期
LocalDate startDate = LocalDate.of(1900, 1, 1);
long sumDay = startDate.until(endDate, ChronoUnit.DAYS);//总相差的天数:3657
/*以上代码计算1900年1月1号到输入的年月的总天数,如输入2018和8,则计算1900.1.1-2018.7.31的天数*/
long xingQi = (sumDay + 1) % 7; //xingQi用来计算输入的月份1号星期几
long everydayXingQi = sumDay + 1;
int monthDay = endDate.lengthOfMonth();//用来接收输入的月份有几天
String result = "日\t一\t二\t三\t四\t五\t六\n";
for (int i = 0; i < xingQi; i++) { //输出每月1号前的空格
result += "\t";
}
for (int i = 1; i <= monthDay; i++) { //输出每个月的天数和控制换行
if (everydayXingQi % 7 == 6) {
result += i + "\n";
} else {
result += i + "\t";
}
everydayXingQi++;
}
return result;
}
}
Main:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
//引用sample.fxml页面布局
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
//设置窗口名称
primaryStage.setTitle("日历");
//设置窗口大小
primaryStage.setScene(new Scene(root, 627, 399));
//固定窗口大小使其无法最大化
primaryStage.setResizable(false);
//设置窗口的图标.
primaryStage.getIcons().add(new Image("/sample/image/rili.jpg"));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
启动项目就ok了。
打成jar包:
当然你也可以把写好的程序打成jar包或exe程序,打包如下:
javaFxText下会生成一个exe文件
文件夹中打开后,双击就可以运行了
但是这个exe文件太难找了,一找找半天,本来想着创建个快捷方式,但是快捷方式只支持绝对路径,没办法,我们可以回到上层目录新建个txt文件输入:
start JavaFxTest\JavaFxTest.exe
exit
start 后面跟自己的文件夹名和exe名。
保存文件后把后缀改为bat
以后双击就能用了。
关于其他打包方式目前还没试,比如先打成jar包,再通过其他工具打成exe文件。
参考:将java打包成exe——在没有jdk或jre的机器上运行Java项目java工具(一):在没有jdk环境的电脑上运行java项目,制作exe文件
如果你对 javaFX 感兴趣,你可以看下我 gitgub上使用 javaFX 开发的一个应用: XTool