目录
前言
在我学习了JavaSE 和 基本的数据结构以及多线程的知识后,我想着做些什么东西来巩固我所写的知识。于是我就做了实际中我们用电脑可以使用到的功能,实时统计CPU的占有率并绘制曲线,统计磁盘某个文件目录下子目录、子文件所占空间的大小 。
项目所用技术与平台
所用技术:JavaSE/javafx
平台与环境:Windows 10/jdk1.8/idea
项目功能
显示 CPU 占有率
文件目录扫描
项目模块分析
主要分为UI模块和逻辑模块。
UI部分主程序用来加载fxml文件,Controller 主要功能是把UI和逻辑部分关联起来,再就是进行两个Tab页的设计。
逻辑部分主要实现两个功能:1. CPU占用率的获取 2. 磁盘目录的扫描
项目细节实现
UI模块
1. 主函数
package com.bq.gui;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/*
主程序:继承Application类 重写start()方法
*/
public class FileAndOSMonitorApp extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
//Stage:舞台 Scene:场景
//1. 加载.fxml文件
FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().
getResource("FOMonitor_tab.fxml"));
//2. 真正的加载
Parent root = loader.load();
//加载磁盘空间统计 把统计页面加载到主舞台
FileAndOSMonitorController controller = loader.getController();
controller.setPrimaryStage(primaryStage);
//3. 创建Scene对象 即场景
Scene scene = new Scene(root, 800, 600);
//4. 给stage设置标题
primaryStage.setTitle("FileAndOSMonitor");
//5. 将scene添加到stage
primaryStage.setScene(scene);
//关闭时停止程序
primaryStage.setOnCloseRequest(event -> controller.shutdown());
//6. 展示
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
对主函数进行了一些解释,其实主函数更多像一个死套路,继承Application类 重写start()方法,主要目的是进行资源的加载。
2. 磁盘空间扫描Tab页设计
要用自己设计的 UI 替换工程自动生成的 .fxml 文件。 UI 的主题框架是通过 fxml 来描述。UI 交互比较简单,只有两个 tab 页。fxml 中所有元素名称都是 JavaFX 中的类名或者是类的属性名。元素的属性是 JavaFX中类的属性。 这个 UI 主框架包含两个 tab 页,用到的控件是<TabPane> 和 <Tab> 。 <TabPane> 代表 tab 页所在的容器面板, 代表一个个的 tab 页。
CPU 占有率 = CPU 执行程序时间 / 统计周期时间。CPU 占有率 Tab 页主要是通过 <LineChart> 控件绘制曲线图,x 轴 和 y 轴都用 <NumberAxis> 控 件。通过 <Tab> 控件的 onSelectionChanged 属性设置监听事件的方法:handleCPUSelectionChanged。
描述一下,磁盘空间扫描Tab页所用的重要控件:
1. <VBox></VBox>:为垂直布局,布局面板为将多个节点排列在一列中提供了一个简单的方法。
2. <HBox></HBox>:为水平布局,布局面板为将多个节点排列在一行中提供了一个简单的方法。
3. <TabPane> </TabPane>:页签面板,是一种标签页控件。
4. <Tab></Tab>:每个Tab页就可以响应一个页面,可以进行页面间的切换。
5. <LineChart></LineChart>:网格控件,用来显示实时显示cpu占有率。
6. <GridPane></GridPane>:单元格控件,用来显示系统资源的获取情况。
7. <Text></Text>:可编辑的文本页。
8. <Lable></Lable>:标签页。
总体的布局可以由下图表示:
3. 文件目录统计Tab页设计
磁盘扫描 Tab 页主要是用到了 <TreeTableView> 控件,绘制一个树形表格。另外设计了一个<Button> 控件来选择文件目录,通 <Button> 控件的 onAction 属性设置监听事件的方法: handleSelectFile。
主要有两个重要的控件:
1. <Button></Button>:按钮组件,会有具体的响应方法。
2.<TreeTableView></TreeTableView>:树表组件,既有树的特性,又有表的特性。用于文件目录的树形结构的查看。
总体的布局可以由下图表示:
4. Controller 模块
Controller 主要是用于处理 UI 事件,需要将此类添加到 .fxml 文件中,我用到的顶级容器是 <VBox> ,通过 fx:controller 属性设置 Controller 类的包路径,方法如下:
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.bq.gui.FileAndOSMonitorController">
</VBox>
在 Controller 中,我们需要处理两个事件:CPU 占有率和目录结构统计,详情见github,大致流程如下:
// 磁盘目录扫描事件处理方法
public void handleSelectFile(ActionEvent actionEvent) {
// 1. 打开文件选择对话框
// 2. 开启磁盘目录扫描线程
// 3. 渲染TreeTableView
}
// CPU 占有率事件处理方法
public void handleCPUSelectionChanged(Event event) {
// 1. 创建一个定时器,每隔一秒获取一次 CPU 资源绘制曲线图
// 2. 绘制 LineChart
}
逻辑模块
1. 系统资源获取模块
系统资源获取采用的是 OperatingSystemMXBean,这是一个 JMX 接口,用于获取运行 JVM 的系统的 资源信息,比如,CPU 占有率,OS 版本,内存大小等等。我们用的是 com.sun.management.OperatingSystemMXBean 类。
绘制 CPU 占有率曲线的核心思想:
1. 每隔一秒对 CPU 占有率进行一次采样,作为数轴的 y 坐标
2. 一共保存 60 秒,即 1 分钟的样本点,时间作为 x 坐标。
3. 用一个数组保存坐标 (x,y),每一次采样,需要把之前采样的坐标点的 x 坐标减 1,这样绘制的时候就会产生移动的效果。
核心代码如下:
//移动数据
private static final int DATA_LENGTH = 60;
private static XYPair[] xyPairs = new XYPair[DATA_LENGTH];
private static int firstIndex = DATA_LENGTH;
private static void moveCPUData(double cpuPercetage){
int movIdx = -1; //移动的坐标
if (firstIndex == 0){
movIdx = firstIndex + 1;
}else
{
movIdx = firstIndex; firstIndex--;
}
for (; movIdx < xyPairs.length; ++movIdx){
xyPairs[movIdx-1].setX(xyPairs[movIdx].getX()-1);
xyPairs[movIdx-1].setY(xyPairs[movIdx].getY());
}
movIdx--;
xyPairs[movIdx] = new XYPair(movIdx, cpuPercetage);
}
2. 文件目录扫描模块
文件目录扫描核心思想是:用递归的方式遍历文件目录结构,统计某个目录下面所有子目录占用总的磁盘空间大小,然后再做一个汇总。
代码片段:
public static void scannerDirectory(FileTreeNode node) {
//获取当前目录或文件列表
File[] files = node.getFile().listFiles();
if (files == null) {
return;
}
//遍历子目录或者文件
for (File file : files) {
FileTreeNode child = new FileTreeNode();
child.setFile(file);
child.setFileName(file.getName());
if (file.isDirectory()) {
//如果是目录继续统计
scannerDirectory(child);
} else {
//如果是普通文件 记录文件大小
child.setTotalLength(file.length());
}
node.setTotalLength(node.getTotalLength() + child.getTotalLength());
node.addChildNode(child);
}
}
项目演示
项目总结
这个项目实现了完整的功能,巩固了我对前面知识的学习。在项目中,我也遇到了一些问题:比如gui程序渲染数据必须在主线程中执行,树表控件的转化等等,也都进行了克服。当然还有很多的不足,需要继续完善。
- 项目优点:引入了 JavaFX 技术,通过图形化 界面展示 CPU 占有率和磁盘空间统计,显得更直观。
- 项目缺点:项目的所实现的功能相对简单,UI 不够美观。
- 项目扩展:还可以把项目写的更完善比如: 增加关于内存使用情况的统计,增加关于网络上下行带宽的统计,美化UI,这是我后面要做的工作。
附:github链接 。