本节概要
本节将实现账目记录的添加。
前期准备
在本节中实现记录的添加将用到分类信息的查询,所以在dao包下创建ClassificationDao.java类,代码如下:
package AccountSystem.dao;
import AccountSystem.bean.Classification;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class ClassificationDao {
/**
* 通过收入或支出类型获取所有的分类信息
*
* @param classificationType 收入或支出分类
* @return 返回得到的分类信息
*/
public List<Classification> selectByType(String classificationType) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
List<Classification> classificationList = new ArrayList<Classification>();
try {
//获得数据的连接
conn = JDBCUtils.getConnection();
//获得Statement对象
stmt = conn.createStatement();
// 拼接SQL语句
String sql = "select * from tb_classification where cType='" + classificationType + "';";
//发送SQL语句
rs = stmt.executeQuery(sql);
while (rs.next()) {
Classification classification = new Classification();
classification.setcId(rs.getInt(1));
classification.setcName(rs.getString(2));
classification.setcType(rs.getString(3));
classificationList.add(classification);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.release(rs, stmt, conn);
}
return classificationList;
}
}
实现界面
要先完成一个添加功能在JavaFX中,首先是创建FXML视图文件,接着是创建与之相关的Controller控制器类,然后是在MainApp创建加载FXML视图文件的方法,最后是在某个事件中进行调用。
在view包下创建addAccountFrame.fxml文件,并使用Scene Builder设计界面,各控件属性和事件方法参考下面代码:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="AccountSystem.controller.AddAccountFrameController">
<children>
<VBox alignment="CENTER" focusTraversable="true" layoutX="137.0" prefHeight="400.0" prefWidth="326.0"
spacing="20.0">
<children>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Label fx:id="descriptionLabel" text="添加"/>
</children>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0">
<children>
<Label text="类型:"/>
<HBox alignment="CENTER_LEFT" prefHeight="30.0" prefWidth="240.0" spacing="50.0">
<children>
<RadioButton fx:id="outputRadioButton" mnemonicParsing="false"
onAction="#outputRadioButtonEvent" text="支出">
<toggleGroup>
<ToggleGroup fx:id="group"/>
</toggleGroup>
</RadioButton>
<RadioButton fx:id="inputRadioButton" mnemonicParsing="false"
onAction="#inputRadioButtonEvent" text="收入" toggleGroup="$group"/>
</children>
</HBox>
</children>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0">
<children>
<Label text="金额:"/>
<TextField fx:id="moneyTextField" prefHeight="30.0" prefWidth="240.0" promptText="请填入金额:"/>
</children>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0">
<children>
<Label text="分类:"/>
<ComboBox fx:id="classificationComboBox" onAction="#classificationComboBoxEvent"
prefHeight="30.0" prefWidth="240.0" promptText="请选择分类:"/>
</children>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0">
<children>
<Label text="备注:"/>
<TextArea fx:id="memoTextArea" prefHeight="200.0" prefWidth="240.0" promptText="请填入备注:"/>
</children>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0">
<children>
<Label text="日期:"/>
<DatePicker fx:id="datePickerTextField" prefHeight="30.0" prefWidth="240.0"
promptText="请选择日期:"/>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Button fx:id="addButton" mnemonicParsing="false" onAction="#addButtonEvent" text="添加"/>
</children>
</HBox>
</children>
<opaqueInsets>
<Insets/>
</opaqueInsets>
<padding>
<Insets bottom="20.0"/>
</padding>
</VBox>
</children>
</AnchorPane>
然后在controller包下创建AddAccountFrameController.java类,并从Scene Builder中将控件对象和事件方法复制到该类中:
package AccountSystem.controller;
import AccountSystem.bean.Classification;
import AccountSystem.bean.Record;
import AccountSystem.bean.Session;
import AccountSystem.dao.ClassificationDao;
import AccountSystem.dao.RecordDao;
import AccountSystem.tools.PublicTools;
import AccountSystem.tools.SimpleTools;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import java.util.List;
/**
* 添加账目界面控制器
*
* @author lck100
*/
public class AddAccountFrameController {
private PublicTools publicTools = new PublicTools();
@FXML
private String selectedRadioButton = null;
@FXML
private String selectedCoboboxItem = null;
@FXML
private Label descriptionLabel;
@FXML
private RadioButton outputRadioButton;
@FXML
private DatePicker datePickerTextField;
@FXML
private TextField moneyTextField;
@FXML
private RadioButton inputRadioButton;
@FXML
private TextArea memoTextArea;
@FXML
private ComboBox<?> classificationComboBox;
/**
* “添加”按钮的事件监听器
*
* @param actionEvent 事件
*/
@FXML
public void addButtonEvent(ActionEvent actionEvent) {
}
/**
* “支出”单选按钮的事件监听器
*
* @param actionEvent 事件
*/
public void outputRadioButtonEvent(ActionEvent actionEvent) {
}
/**
* “收入”单选按钮的事件监听器
*
* @param actionEvent 事件
*/
public void inputRadioButtonEvent(ActionEvent actionEvent) {
}
/**
* ”分类“下拉列表框的事件监听器
*
* @param actionEvent 事件
*/
public void classificationComboBoxEvent(ActionEvent actionEvent) {
}
}
代码说明:
可以看到上面有四个事件监听器方法,其中添加按钮的事件处理很好理解就是当用户输入信息后就将记录插入到数据库表中,但是其他三个方法可能不明白为什么要监听它们。其中”支出“和”收入“单选按钮的监听都是差不多的,因为”支出“有很多不同的分类,而这些分类就显示在下面的下拉列表框中,同样”收入“的所有分类也显示在下面的下拉列表框中,因为不可能将收入和支出分类都显示在一起,那么上面的两个单选按钮的设定将毫无意义,也就没有了收入和支出之分。
因此当用户选中”收入“单选按钮时,就将收入的所有分类名称填充到下面的下拉列表框中;当用户选中“支出”单选按钮时,就将支出的所有分类名称填充到下面的下拉列表框中,从而使用户得以分开选择所属分类。
下拉列表框的监听事件就是为了动态获取用户所选择的分类名称。
下面将演示单选按钮的监听变化:
点击“添加”菜单项弹出添加界面如下(此时两个单选按钮都未被选择,因此下拉列表框也没有值):
选中“支出”单选按钮,下面的分类全都是“支出”的分类名称:
选中“收入”单选按钮,下面的分类全都是“收入”的分类名称:
写完了视图界面和控制器,接着就是加载FXML视图界面了,在MainApp.java中添加如下方法加载addAccountFrame.fxml文件:
/**
* 操作结果:添加账目界面
*/
public Scene initAddFrame() {
try {
Parent page = FXMLLoader.load(getClass().getResource("view/addAccountFrame.fxml"));
Stage mainFrameStage = new Stage();
mainFrameStage.setTitle("添加账目");
mainFrameStage.setResizable(true);
mainFrameStage.setAlwaysOnTop(false);
mainFrameStage.initModality(Modality.APPLICATION_MODAL);
mainFrameStage.initOwner(primaryStage);
Scene scene = new Scene(page);
mainFrameStage.setScene(scene);
mainFrameStage.show();
return scene;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
然后是在MainPageController.java中的添加菜单项事件中进行调用:
/**
* ”添加“菜单项的事件监听器
*
* @param actionEvent 事件
*/
@FXML
public void addMenuItemEvent(ActionEvent actionEvent) {
// 刷新界面数据
initialize();
// 调用添加账目界面
mainApp.initAddFrame();
}
运行项目就可以看到添加界面,但是没有任何事件处理,只有界面。
添加功能
添加功能的实现在AddAccountFrameController的addButtonEvent()方法中,代码如下:
// 类型
String type = selectedRadioButton;
// 金额,把从文本框得到的string类型数据转换为float类型
float money = Float.parseFloat(moneyTextField.getText());
// 分类
String classification = selectedCoboboxItem;
// 备注
String memo = memoTextArea.getText();
// 日期
String date = datePickerTextField.getValue().toString();
// 将用户输入的数据封装到Record实体类中
Record record = new Record(Session.getUser().getUserId(), type, money, classification, memo, date);
// 实例化RecordDao对象
RecordDao recordDao = new RecordDao();
// 添加数据到数据库
boolean b = recordDao.addRecord(record);
// 对添加操作的结果进行判断处理
if (b) {
SimpleTools.informationDialog(Alert.AlertType.INFORMATION, "提示", "信息", "添加账目成功!");
// 清空用户选择
outputRadioButton.setSelected(false);
inputRadioButton.setSelected(false);
moneyTextField.setText("");
classificationComboBox.getItems().clear();
memoTextArea.setText("");
datePickerTextField.getEditor().setText("");
} else {
SimpleTools.informationDialog(Alert.AlertType.ERROR, "提示", "错误", "添加账目失败!");
}
代码说明:获取用户输入的信息,然后封装到Record实体类对象中,调用RecordDao中的addRecord()进行添加操作,然后并对添加结果进行判断处理。
”支出“单选按钮的事件处理如下:
/**
* “支出”单选按钮的事件监听器
*
* @param actionEvent 事件
*/
public void outputRadioButtonEvent(ActionEvent actionEvent) {
// 获取支出分类的所有信息
List<Classification> classificationList = new ClassificationDao().selectByType("支出");
// 实例化一个一维数组
String[] classificationNames = new String[classificationList.size()];
// 将查询得到的分类名称装到一维数组中
for (int i = 0; i < classificationList.size(); i++) {
classificationNames[i] = classificationList.get(i).getcName();
}
// 给下拉列表框添加选项
publicTools.public_addComboBoxItems(classificationComboBox, classificationNames);
// 获取单选按钮项
selectedRadioButton = outputRadioButton.getText();
// 设置descriptionLabel文本内容
descriptionLabel.setText("添加" + outputRadioButton.getText());
}
代码说明:通过ClassificationDao类的selectByType()方法获取支出的所有分类名称,并将其转换成一个一维数组,然后调用PublicTools类中的public_addComboBoxItems()方法进行填充数据,并将所选中的单选按钮值赋给一个变量,然后在”添加“事件处理中使用。
”收入“单选按钮的事件处理如下:
/**
* “收入”单选按钮的事件监听器
*
* @param actionEvent 事件
*/
public void inputRadioButtonEvent(ActionEvent actionEvent) {
// 获取收入分类的所有信息
List<Classification> classificationList = new ClassificationDao().selectByType("收入");
// 实例化一个一维数组
String[] classificationNames = new String[classificationList.size()];
// 将查询得到的分类名称装到一维数组中
for (int i = 0; i < classificationList.size(); i++) {
classificationNames[i] = classificationList.get(i).getcName();
}
// 给下拉列表框添加选项
publicTools.public_addComboBoxItems(classificationComboBox, classificationNames);
// 获取单选按钮项
selectedRadioButton = inputRadioButton.getText();
//设置descriptionLabel文本内容
descriptionLabel.setText("添加" + inputRadioButton.getText());
}
”分类“下拉列表框的事件处理如下:
/**
* ”分类“下拉列表框的事件监听器
*
* @param actionEvent 事件
*/
public void classificationComboBoxEvent(ActionEvent actionEvent) {
//只处理选中的状态
selectedCoboboxItem = (String) classificationComboBox.getSelectionModel().selectedItemProperty().getValue();
}
所有逻辑代码完成,现在是运行项目,测试功能:
然后可以在主界面查看添加成功的记录:
可搜索微信公众号【Java实例程序】或者扫描下方二维码关注公众号获取更多。
注意:在公众号后台回复【20200324】可获取本章的源码 。