本节概要
如果用户想要自定义分类,那么本节就是为了实现该功能,使得用户能够自定义收入和支出分类。
创建界面
首先在view包下创建addClassificationFrame.fxml文件,使用Scene Builder来设计界面,界面中的各个组件的属性和事件方法可以参考下面的代码:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<AnchorPane prefHeight="517.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="AccountSystem.controller.AddClassificationFrameController">
<children>
<TabPane prefHeight="517.0" prefWidth="600.0" tabClosingPolicy="UNAVAILABLE">
<tabs>
<Tab text="支出分类">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<VBox prefHeight="481.0" prefWidth="600.0" spacing="30.0">
<children>
<Label text="添加支出分类" textFill="#7d7d7d">
<font>
<Font size="20.0"/>
</font>
</Label>
<HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0"
spacing="20.0">
<children>
<Label text="分类名称">
<font>
<Font size="28.0"/>
</font>
</Label>
<TextField fx:id="outputClassificationNameTextField"
promptText="输入支出分类名称">
<font>
<Font size="26.0"/>
</font>
</TextField>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="62.0" prefWidth="600.0">
<children>
<Button fx:id="addOutputButton" mnemonicParsing="false"
onAction="#addOutputButtonEvent" prefHeight="42.0"
prefWidth="216.0" text="添加支出">
<font>
<Font size="21.0"/>
</font>
</Button>
</children>
</HBox>
<Label text="支出分类列表" textFill="#7d7d7d">
<font>
<Font size="20.0"/>
</font>
</Label>
<ListView fx:id="outputClassificationListView"
onEditCommit="#outputClassificationListViewCommitEvent"
prefHeight="250.0" prefWidth="600.0">
<contextMenu>
<ContextMenu>
<items>
<MenuItem fx:id="output_editContextMenu" mnemonicParsing="false"
onAction="#output_editContextMenuEvent" text="编辑"/>
<MenuItem fx:id="output_deleteMenuItem" mnemonicParsing="false"
onAction="#output_deleteMenuItemEvent" text="删除"/>
</items>
</ContextMenu>
</contextMenu>
</ListView>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Button fx:id="outputClassificationReturnButton" mnemonicParsing="false"
onAction="#outputClassificationReturnButtonEvent" text="返回">
<font>
<Font size="21.0"/>
</font>
</Button>
</children>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>
</content>
</Tab>
<Tab text="收入分类">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<VBox prefHeight="480.0" prefWidth="600.0" spacing="30.0">
<children>
<Label text="添加收入分类" textFill="#7d7d7d">
<font>
<Font size="20.0"/>
</font>
</Label>
<HBox alignment="CENTER_LEFT" prefHeight="100.0" prefWidth="200.0"
spacing="20.0">
<children>
<Label text="分类名称">
<font>
<Font size="28.0"/>
</font>
</Label>
<TextField fx:id="inputClassificationNameTextField"
promptText="输入收入分类名称">
<font>
<Font size="26.0"/>
</font>
</TextField>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="62.0" prefWidth="600.0">
<children>
<Button fx:id="addInputButton" mnemonicParsing="false"
onAction="#addInputButtonEvent" prefHeight="42.0"
prefWidth="216.0" text="添加收入">
<font>
<Font size="21.0"/>
</font>
</Button>
</children>
</HBox>
<Label text="收入分类列表" textFill="#7d7d7d">
<font>
<Font size="20.0"/>
</font>
</Label>
<ListView fx:id="inputClassificationListView"
onEditCommit="#inputClassificationListViewCommitEvent"
prefHeight="250.0" prefWidth="600.0">
<contextMenu>
<ContextMenu>
<items>
<MenuItem fx:id="input_editContextMenu" mnemonicParsing="false"
onAction="#input_editContextMenuEvent" text="编辑"/>
<MenuItem fx:id="input_deleteContextMenu"
mnemonicParsing="false"
onAction="#input_deleteContextMenuEvent" text="删除"/>
</items>
</ContextMenu>
</contextMenu>
</ListView>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Button fx:id="inputClassificationReturnButton" mnemonicParsing="false"
onAction="#inputClassificationReturnButtonEvent" text="返回">
<font>
<Font size="21.0"/>
</font>
</Button>
</children>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>
</content>
</Tab>
</tabs>
</TabPane>
</children>
</AnchorPane>
接着是在controller创建与之对应的控制器类AddClassificationFrameController.java,bong从Scene Builder中复制该界面中的组件对象和事件方法的代码到该类中:
package AccountSystem.controller;
import AccountSystem.bean.Classification;
import AccountSystem.dao.ClassificationDao;
import AccountSystem.tools.SimpleTools;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.stage.Stage;
import java.util.List;
/**
* 添加分类界面控制器
*
* @author lck100
*/
public class AddClassificationFrameController {
private ClassificationDao classificationDao = new ClassificationDao();
private Stage dialogStage;
public Stage getDialogStage() {
return dialogStage;
}
public void setDialogStage(Stage dialogStage) {
this.dialogStage = dialogStage;
}
@FXML
private TextField inputClassificationNameTextField;
@FXML
private ListView<String> inputClassificationListView;
@FXML
private TextField outputClassificationNameTextField;
@FXML
private ListView<String> outputClassificationListView;
/**
* ”添加支出“按钮的事件监听器
*
* @param event 事件
*/
public void addOutputButtonEvent(ActionEvent event) {
}
/**
* “支出”右键菜单“编辑”的事件监听器
*
* @param event 事件
*/
public void output_editContextMenuEvent(ActionEvent event) {
}
/**
* “支出”右键菜单“删除”的事件监听器
*
* @param event 事件
*/
public void output_deleteMenuItemEvent(ActionEvent event) {
}
/**
* 支出分类界面”返回“按钮的事件监听器
*
* @param event 事件
*/
public void outputClassificationReturnButtonEvent(ActionEvent event) {
}
/**
* ”添加收入“按钮的事件监听器
*
* @param event 事件
*/
public void addInputButtonEvent(ActionEvent event) {
}
/**
* “收入”右键菜单“编辑”的事件监听器
*
* @param event 事件
*/
public void input_editContextMenuEvent(ActionEvent event) {
}
/**
* “收入”右键菜单“删除”的事件监听器
*
* @param event 事件
*/
public void input_deleteContextMenuEvent(ActionEvent event) {
}
/**
* 收入分类界面”返回“按钮的事件监听器
*
* @param event 事件
*/
public void inputClassificationReturnButtonEvent(ActionEvent event) {
}
/**
* “支出”分类列表视图编辑完成的事件监听器
*
* @param stringEditEvent 事件
*/
public void outputClassificationListViewCommitEvent(ListView.EditEvent<String> stringEditEvent) {
}
/**
* 收入分类列表视图编辑完成的事件监听器,按回车键完成对事件的响应
*
* @param stringEditEvent 事件
*/
public void inputClassificationListViewCommitEvent(ListView.EditEvent<String> stringEditEvent) {
}
}
其中的”getDialogStage()”和“setDialogStage()”就是将Stage传到该类中,然后在“返回”按钮事件中调用进行关闭窗口界面。
接着是在MainApp.java中创建方法加载FXML文件:
/**
* 操作结果:”添加分类“查询结果界面
*/
public Scene initAddClassificationFrame() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/addClassificationFrame.fxml"));
AnchorPane page = (AnchorPane) loader.load();
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);
AddClassificationFrameController controller = loader.getController();
controller.setDialogStage(mainFrameStage);
mainFrameStage.showAndWait();
return scene;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
最后是在菜单项事件中调用该方法:
/**
* ”添加分类“菜单项的事件监听器
*
* @param actionEvent 事件
*/
@FXML
public void addClassificationMenuItemEvent(ActionEvent actionEvent) {
// 打开添加分类界面
mainApp.initAddClassificationFrame();
}
运行项目,查看创建完成的界面:
实现功能
首先在“支出分类列表”和“收入分类列表”中显示所有已存在的分类名称,即初始化列表项在initialize()方法中:
/**
* 初始化界面
*/
public void initialize() {
// 获取收入分类的所有信息
List<Classification> inputClassificationList = new ClassificationDao().selectByType("收入");
// 实例化一个一维数组
String[] inputClassificationNames = new String[inputClassificationList.size()];
// 将查询得到的分类名称装到一维数组中
for (int i = 0; i < inputClassificationList.size(); i++) {
inputClassificationNames[i] = inputClassificationList.get(i).getcName();
}
inputClassificationListView.setItems(FXCollections.observableArrayList(inputClassificationNames));
// 获取支出分类的所有信息
List<Classification> outputClassificationList = new ClassificationDao().selectByType("支出");
// 实例化一个一维数组
String[] outputClassificationNames = new String[outputClassificationList.size()];
// 将查询得到的分类名称装到一维数组中
for (int i = 0; i < outputClassificationList.size(); i++) {
outputClassificationNames[i] = outputClassificationList.get(i).getcName();
}
outputClassificationListView.setItems(FXCollections.observableArrayList(outputClassificationNames));
}
下面就是实现“添加”功能了,通过界面上的“添加支出”和“添加收入”来实现,获取界面用户输入的分类名称,然后将其插入到数据库表中并且下面的列表也进行更新显示。
所以“添加支出”按钮的事件监听器代码如下:
/**
* ”添加支出“按钮的事件监听器
*
* @param event 事件
*/
public void addOutputButtonEvent(ActionEvent event) {
// 获取用户输入的支出分类名称
String output = outputClassificationNameTextField.getText();
// 判断用户是否输入为空
if (null == output || "".equals(output)) {
SimpleTools.informationDialog(Alert.AlertType.WARNING, "提示", "警告", "文本框内容不能为空!");
} else {
// 列表视图添加用户输入的支出分类重名
outputClassificationListView.getItems().add(output);
// 封装要添加的分类实体类数据
Classification classification = new Classification(output, "支出");
// 进行添加操作
boolean b = classificationDao.addClassification(classification);
outputClassificationNameTextField.setText("");
}
}
“添加收入”按钮的事件监听器代码如下:
/**
* ”添加收入“按钮的事件监听器
*
* @param event 事件
*/
public void addInputButtonEvent(ActionEvent event) {
// 获取用户输入的收入分类
String input = inputClassificationNameTextField.getText();
// 判断用户是否输入为空
if (null == input || "".equals(input)) {
SimpleTools.informationDialog(Alert.AlertType.WARNING, "提示", "警告", "文本框内容不能为空!");
} else {
// 向列表视图添加收入分类
inputClassificationListView.getItems().add(input);
// 向数据库中添加收入分类
classificationDao.addClassification(new Classification(input, "收入"));
// 清空用户输入
inputClassificationNameTextField.setText("");
}
}
“返回”按钮的功能是退出这个界面,即关闭该Stage,方法代码如下:
/**
* 支出分类界面”返回“按钮的事件监听器
*
* @param event 事件
*/
public void outputClassificationReturnButtonEvent(ActionEvent event) {
// 关闭该界面
dialogStage.close();
}
/**
* 收入分类界面”返回“按钮的事件监听器
*
* @param event 事件
*/
public void inputClassificationReturnButtonEvent(ActionEvent event) {
dialogStage.close();
}
除了添加分类之外,肯定还有删除和编辑分类。
删除分类就是在列表视图中选中要删除的列表项,然后右键单击选中删除,即可删除该项并从数据库中也进行 删除。
所以“支出分类”界面的“删除”右键菜单事件方法如下:
/**
* “支出”右键菜单“删除”的事件监听器
*
* @param event 事件
*/
public void output_deleteMenuItemEvent(ActionEvent event) {
// 获取用户选中的支出分类
String outputItem = (String) outputClassificationListView.getSelectionModel().getSelectedItem();
// 确认用户是否要删除
boolean b = SimpleTools.informationDialog(Alert.AlertType.CONFIRMATION, "确认", "确认", "请问是否确认删除名为" + outputItem + "的支出分类?");
if (b) {
// 从列表视图中移除该分类
outputClassificationListView.getItems().remove(outputItem);
// 从数据库中删除该分类
classificationDao.deleteClassification(new Classification(outputItem, "支出"));
}
}
“收入分类“界面的”删除“右键菜单事件方法如下:
/**
* “收入”右键菜单“删除”的事件监听器
*
* @param event 事件
*/
public void input_deleteContextMenuEvent(ActionEvent event) {
// 获取用户输入的收入分类
String inputItem = (String) inputClassificationListView.getSelectionModel().getSelectedItem();
boolean b = SimpleTools.informationDialog(Alert.AlertType.CONFIRMATION, "确认", "确认", "请问是否确认删除名为" + inputItem + "的收入分类?");
if (b) {
// 向列表视图中移除该收入分类
inputClassificationListView.getItems().remove(inputItem);
// 向数据库中删除该收入分类
classificationDao.deleteClassification(new Classification(inputItem, "收入"));
}
}
而编辑列表项稍微要难些,先要通过右键菜单“编辑”使列表项可以编辑,然后通过“ListView.EditEvent<String>”事件来获取修改后的值进行更新操作。
所以“支出分类”界面的编辑事件代码如下:
/**
* “支出”右键菜单“编辑”的事件监听器
*
* @param event 事件
*/
public void output_editContextMenuEvent(ActionEvent event) {
outputClassificationListView.setCellFactory(TextFieldListCell.forListView());
outputClassificationListView.setEditable(true);
outputClassificationListView.setFocusTraversable(true);
}
/**
* “支出”分类列表视图编辑完成的事件监听器
*
* @param stringEditEvent 事件
*/
public void outputClassificationListViewCommitEvent(ListView.EditEvent<String> stringEditEvent) {
// 获取列表视图选中的原值
String sourceValue = stringEditEvent.getSource().getSelectionModel().getSelectedItem();
// 获取列表视图编辑后的新值
String newValue = stringEditEvent.getNewValue();
// 向列表视图移除原值
outputClassificationListView.getItems().remove(sourceValue);
// 向列表视图添加新值
outputClassificationListView.getItems().add(newValue);
// 向数据库更新值
classificationDao.updateClassification(newValue, sourceValue);
}
“收入分类“界面中的编辑事件代码如下:
/**
* “收入”右键菜单“编辑”的事件监听器
*
* @param event 事件
*/
public void input_editContextMenuEvent(ActionEvent event) {
inputClassificationListView.setCellFactory(TextFieldListCell.forListView());
inputClassificationListView.setEditable(true);
inputClassificationListView.setFocusTraversable(true);
}
/**
* 收入分类列表视图编辑完成的事件监听器,按回车键完成对事件的响应
*
* @param stringEditEvent 事件
*/
public void inputClassificationListViewCommitEvent(ListView.EditEvent<String> stringEditEvent) {
// 获取列表视图选中的原值
String sourceValue = stringEditEvent.getSource().getSelectionModel().getSelectedItem();
// 获取列表视图编辑后的新值
String newValue = stringEditEvent.getNewValue();
// 向列表视图移除原值
inputClassificationListView.getItems().remove(sourceValue);
// 向列表视图添加新值
inputClassificationListView.getItems().add(newValue);
// 向数据库更新值
classificationDao.updateClassification(newValue, sourceValue);
}
添加分类界面的逻辑功能已经实现,能够完成对分类的增加、删除和编辑。
运行代码,测试功能:
可搜索微信公众号【Java实例程序】或者扫描下方二维码关注公众号获取更多。
注意:在公众号后台回复【20200421】可获取本章的源码。