Java简易系统监视器system-monitoring:实时显示CPU使用率、内存使用率、笔记本电脑电池剩余电量、时间(时、分、秒)。创建系统托盘,设置系统托盘菜单,窗体置顶显示。通过jna调用dll文件读取电池数据。
目录
效果图
功能说明
项目与工具
项目说明
目录结构
核心代码
Window.java
Menu.java
Dll.java
AppUtil.java
BatteryLabel.java
C++创建dll
BatteryMonitor.h
BatteryMonitor.cpp
依赖
Github
Gitee
参考链接
后记
效果图
功能说明
Java简易系统监视器system-monitoring:实时显示CPU使用率、内存使用率、笔记本电脑电池剩余电量、时间(时、分、秒)。CPU使用率、内存使用率和时间每秒更新一次,笔记本电脑电池剩余电量每15秒更新一次。创建系统托盘,设置系统托盘菜单,窗体置顶显示。系统托盘按钮:
移动(或固定):点击后可移动或固定窗体。刷新:点击可刷新窗体,当窗体显示异常时可使用。布局:可更改窗体布局,可选“单列布局”、“双列布局”。(效果图为双列布局)显示:可选择需要显示的参数,可勾选“CPU”、“内存”、“电量”、“时间”。退出程序:点击可退出程序。
窗体不可移动至屏幕外。窗体大小可根据显示的参数个数自动适配。点击系统托盘后,弹出多级菜单,当鼠标点击非菜单区域,弹出的多级菜单会自动消失。(基于Jframe+JPopupMenu实现)
项目与工具
- 移动(或固定):点击后可移动或固定窗体。刷新:点击可刷新窗体,当窗体显示异常时可使用。布局:可更改窗体布局,可选“单列布局”、“双列布局”。(效果图为双列布局)显示:可选择需要显示的参数,可勾选“CPU”、“内存”、“电量”、“时间”。退出程序:点击可退出程序。
Maven、Java 8、Swing、maven-assembly-plugin(jar-with-dependencies)、jna、dll
项目说明
使用jna调用C++生成的动态链接库dll文件监控电池剩余电量。生成的system-monitoring-2.0.0-jar-with-dependencies.jar需与resources中的images文件夹和BatteryMonitor.dll文件同级。(与代码中读取相关文件路径的写法有关)
目录结构
核心代码
由于代码较多,此处就不全部贴出来了,需要完整代码的小伙伴请移步GitHub或Gitee。
Window.java
package cxzgwing;
import java.awt.*;
import java.time.Clock;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import cxzgwing.judgement.WindowMovable;
import cxzgwing.label.impl.BatteryLabel;
import cxzgwing.label.impl.CpuLabel;
import cxzgwing.label.impl.MemoryLabel;
import cxzgwing.label.impl.TimeLabel;
import cxzgwing.listener.frameDragListener;
import cxzgwing.listener.TrayIconMouseListener;
import cxzgwing.task.BatteryMonitorTask;
import cxzgwing.task.CpuMemoryTimeMonitorTask;
import cxzgwing.task.GCTask;
import cxzgwing.utils.AppUtil;
import cxzgwing.utils.LabelLayout;
import cxzgwing.utils.ThreadUtil;
public class Window extends Jframe {
private Menu menu;
private WindowMovable windowMovable;
private CpuLabel cpuLabel;
private MemoryLabel memoryLabel;
private BatteryLabel batteryLabel;
private TimeLabel timeLabel;
private Font font;
private EmptyBorder emptyBorder;
private GridLayout gridLayout;
// 1-单列布局,2-双列布局
private int labelLayout;
// 窗体位置最大横坐标
private int windowMaxX;
// 窗体位置最大纵坐标
private int windowMaxY;
public Window() throws Exception {
// 初始化窗体是否可移动
windowMovable = new WindowMovable(false);
font = new Font("黑体", Font.PLAIN, 16);
labelLayout = LabelLayout.DOUBLE;
// 设置显示标签边距
emptyBorder = new EmptyBorder(0, 5, 0, 0);
// 设置布局
gridLayout = new GridLayout(2, 2);
// 初始化窗体
initWindow();
// 设置CPU使用率显示标签
initCpuJLabel();
// 内存使用率显示标签
initMemJLabel();
// 电池电量百分比显示标签
initBatteryJLabel();
// 时间显示标签
initTimeJLabel();
// 初始化托盘菜单
initMenu();
// 设置窗体是否可移动监听
setWindowDragListener();
// 添加窗体状态监听,使窗体一直显示
setWindowAlwaysShow();
// 添加系统托盘
setSystemTray();
// 显示
this.setVisible(true);
// 监控
monitoring();
}
private void initMenu() {
menu = new Menu(this, windowMovable, cpuLabel, memoryLabel, batteryLabel, timeLabel);
}
private void initWindow() {
// 隐藏任务栏图标
this.setType(Jframe.Type.UTILITY);
// 设置窗口置顶
this.setAlwaysonTop(true);
// 设置无边框
this.setUndecorated(true);
// 设置背景色
this.setBackground(new Color(0, 0, 0, 80));
// 设置窗体大小
this.setSize(150, 40);
// 设置布局
this.setLayout(gridLayout);
AppUtil.initWindowLocation(this);
}
private void setWindowDragListener() {
// 设置鼠标监听,可通过鼠标移动窗体位置
// 通过系统托盘菜单中的第一个按钮(移动 / 固定)来控制是否能移动窗体
frameDragListener frameDragListener = new frameDragListener(this, windowMovable);
this.addMouseListener(frameDragListener);
this.addMouseMotionListener(frameDragListener);
}
private void initTimeJLabel() {
// 时间显示标签
timeLabel = new TimeLabel(AppUtil.getTime());
timeLabel.setFont(font);
timeLabel.setForeground(Color.WHITE);
timeLabel.setBorder(emptyBorder);
gridLayout.addLayoutComponent("timeLabel", timeLabel);
this.add(timeLabel);
}
private void initBatteryJLabel() {
// 电池电量百分比显示标签
batteryLabel = new BatteryLabel(AppUtil.getBatteryPercent());
batteryLabel.setFont(font);
batteryLabel.setForeground(Color.WHITE);
batteryLabel.setBorder(emptyBorder);
gridLayout.addLayoutComponent("batteryLabel", batteryLabel);
this.add(batteryLabel);
}
private void initMemJLabel() {
// 内存使用率显示标签
memoryLabel = new MemoryLabel(AppUtil.getMemoryLoad());
memoryLabel.setFont(font);
memoryLabel.setForeground(Color.WHITE);
memoryLabel.setBorder(emptyBorder);
gridLayout.addLayoutComponent("memoryLabel", memoryLabel);
this.add(memoryLabel);
}
private void initCpuJLabel() {
// CPU使用率显示标签
cpuLabel = new CpuLabel(AppUtil.getSystemCpuLoad());
cpuLabel.setFont(font);
cpuLabel.setForeground(Color.WHITE);
cpuLabel.setBorder(emptyBorder);
gridLayout.addLayoutComponent("cpuLabel", cpuLabel);
this.add(cpuLabel);
}
private void monitoring() {
ThreadUtil.addTask(new CpuMemoryTimeMonitorTask(cpuLabel, memoryLabel, timeLabel));
ThreadUtil.addTask(new BatteryMonitorTask(batteryLabel));
ThreadUtil.addTask(new GCTask());
}
private void setSystemTray() throws Exception {
try {
if (SystemTray.isSupported()) {
// 获取当前平台的系统托盘
SystemTray tray = SystemTray.getSystemTray();
// 加载一个图片用于托盘图标的显示
Image image = Toolkit.getDefaultToolkit()
.getImage(Clock.class.getResource("/images/system-monitoring-icon.png"));
// 创建点击图标时的弹出菜单方案三:Jframe + JPopupMenu
TrayIcon trayIcon = new TrayIcon(image, "System Monitoring");
trayIcon.addMouseListener(new TrayIconMouseListener(menu));
// 托盘图标自适应尺寸
trayIcon.setImageAutoSize(true);
// 添加托盘图标到系统托盘
tray.add(trayIcon);
} else {
throw new Exception("当前系统不支持系统托盘");
}
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
private void setWindowAlwaysShow() {
this.addWindowStateListener(e -> {
int newState = e.getNewState();
if (Jframe.IConIFIED == newState) {
this.setState(Jframe.NORMAL);
}
});
}
public void setWindowMaxX(int windowMaxX) {
this.windowMaxX = windowMaxX;
}
public void setWindowMaxY(int windowMaxY) {
this.windowMaxY = windowMaxY;
}
public int getWindowMaxX() {
return this.windowMaxX;
}
public int getWindowMaxY() {
return this.windowMaxY;
}
public int getLabelLayout() {
return labelLayout;
}
public void setLabelLayout(int labelLayout) {
this.labelLayout = labelLayout;
}
}
Menu.java
package cxzgwing;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Objects;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import cxzgwing.judgement.WindowMovable;
import cxzgwing.label.LabelAdaptor;
import cxzgwing.label.impl.BatteryLabel;
import cxzgwing.label.impl.CpuLabel;
import cxzgwing.label.impl.MemoryLabel;
import cxzgwing.label.impl.TimeLabel;
import cxzgwing.utils.AppUtil;
import cxzgwing.utils.LabelLayout;
public class Menu {
private Jframe jframe;
private JPopupMenu jPopupMenu;
private Font font;
private Window window;
private WindowMovable windowMovable;
private CpuLabel cpuLabel;
private MemoryLabel memoryLabel;
private BatteryLabel batteryLabel;
private TimeLabel timeLabel;
private static final int WIDTH = 75;
private static final int HEIGHT = 110;
public Menu(Window window, WindowMovable windowMovable, CpuLabel cpuLabel,
MemoryLabel memoryLabel, BatteryLabel batteryLabel, TimeLabel timeLabel) {
this.window = window;
this.windowMovable = windowMovable;
this.cpuLabel = cpuLabel;
this.memoryLabel = memoryLabel;
this.batteryLabel = batteryLabel;
this.timeLabel = timeLabel;
this.font = new Font("宋体", Font.PLAIN, 13);
init();
addJPopupMenuListener();
}
private void hiddenframeIfShowing() {
if (jframe.isShowing()) {
jframe.setVisible(false);
}
}
private void hiddenJPopupMenuIfShowing() {
if (jPopupMenu.isShowing()) {
jPopupMenu.setVisible(false);
}
}
private void addJPopupMenuListener() {
jPopupMenu.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
hiddenframeIfShowing();
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {}
});
}
private void init() {
setJframe();
setJPopupMenu();
}
private void setJPopupMenu() {
jPopupMenu = new JPopupMenu();
jPopupMenu.setSize(WIDTH, HEIGHT);
setMovableJMenu();
setRefreshJMenu();
setLayoutJMenu();
setDisplayJMenu();
setExitJMenu();
}
private void setExitJMenu() {
JMenuItem exitJMenuItem = new JMenuItem("退出程序");
exitJMenuItem.setFont(font);
exitJMenuItem.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
System.exit(0);
}
});
jPopupMenu.add(exitJMenuItem);
}
private void setDisplayJMenu() {
JMenu displayJMenu = new JMenu("显示");
displayJMenu.setFont(font);
JCheckBox cpuJCheckBox = new JCheckBox("CPU");
cpuJCheckBox.setFont(font);
cpuJCheckBox.setSelected(true);
cpuJCheckBox.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
stateChange(cpuLabel, cpuJCheckBox.isSelected());
}
});
JCheckBox memoryJCheckBox = new JCheckBox("内存");
memoryJCheckBox.setFont(font);
memoryJCheckBox.setSelected(true);
memoryJCheckBox.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
stateChange(memoryLabel, memoryJCheckBox.isSelected());
}
});
JCheckBox batteryJCheckBox = new JCheckBox("电量");
batteryJCheckBox.setFont(font);
batteryJCheckBox.setSelected(true);
batteryJCheckBox.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
stateChange(batteryLabel, batteryJCheckBox.isSelected());
}
});
JCheckBox timeJCheckBox = new JCheckBox("时间");
timeJCheckBox.setFont(font);
timeJCheckBox.setSelected(true);
timeJCheckBox.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
stateChange(timeLabel, timeJCheckBox.isSelected());
}
});
displayJMenu.add(cpuJCheckBox);
displayJMenu.add(memoryJCheckBox);
displayJMenu.add(batteryJCheckBox);
displayJMenu.add(timeJCheckBox);
jPopupMenu.add(displayJMenu);
}
private void stateChange(LabelAdaptor label, boolean isSelected) {
// 在复选框除按下鼠标,移除复选框区域后松开鼠标,此时复选框状态不变,无需操作
if ((label.isDisplay() && isSelected) || (!label.isDisplay() && !isSelected)) {
return;
}
label.setDisplay(isSelected);
windowRemoveAll();
reloadWindow();
refreshWindow();
}
private void reloadWindow() {
int count = getDisplayLabelCount();
GridLayout gridLayout = updateWindowLabelLayout(count);
reloadLabel(gridLayout);
}
private void reloadLabel(GridLayout gridLayout) {
// 由于不显示标签时,不读取相关数据,所以重新显示时需要更新数据
if (cpuLabel.isDisplay()) {
cpuLabel.setText(AppUtil.getSystemCpuLoad());
if (LabelLayout.DOUBLE == window.getLabelLayout() && !Objects.isNull(gridLayout)) {
gridLayout.addLayoutComponent("cpuLabel", cpuLabel);
}
window.add(cpuLabel);
}
if (memoryLabel.isDisplay()) {
memoryLabel.setText(AppUtil.getMemoryLoad());
if (LabelLayout.DOUBLE == window.getLabelLayout() && !Objects.isNull(gridLayout)) {
gridLayout.addLayoutComponent("memoryLabel", memoryLabel);
}
window.add(memoryLabel);
}
if (batteryLabel.isDisplay()) {
batteryLabel.setText(AppUtil.getBatteryPercent());
if (LabelLayout.DOUBLE == window.getLabelLayout() && !Objects.isNull(gridLayout)) {
gridLayout.addLayoutComponent("batteryLabel", batteryLabel);
}
window.add(batteryLabel);
}
if (timeLabel.isDisplay()) {
timeLabel.setText(AppUtil.getTime());
if (LabelLayout.DOUBLE == window.getLabelLayout() && !Objects.isNull(gridLayout)) {
gridLayout.addLayoutComponent("timeLabel", timeLabel);
}
window.add(timeLabel);
}
}
private int getDisplayLabelCount() {
int count = 0;
if (cpuLabel.isDisplay()) {
count++;
}
if (memoryLabel.isDisplay()) {
count++;
}
if (batteryLabel.isDisplay()) {
count++;
}
if (timeLabel.isDisplay()) {
count++;
}
return count;
}
private GridLayout updateWindowLabelLayout(int count) {
GridLayout gridLayout = null;
if (LabelLayout.SINGLE == window.getLabelLayout()) {
// 单列布局
window.setSize(window.getWidth(), 20 * count);
} else if (LabelLayout.DOUBLE == window.getLabelLayout()) {
// 双列布局
switch (count) {
case 1:
window.setLayout(gridLayout = new GridLayout(1, 1));
window.setSize(75, 20);
break;
case 2:
window.setLayout(gridLayout = new GridLayout(1, 2));
window.setSize(150, 20);
break;
case 3:
case 4:
window.setLayout(gridLayout = new GridLayout(2, 2));
window.setSize(150, 40);
break;
default:
window.setLayout(gridLayout = new GridLayout(2, 2));
window.setSize(150, 40);
}
}
AppUtil.initWindowLocation(window);
return gridLayout;
}
private void windowRemoveAll() {
window.remove(cpuLabel);
window.remove(memoryLabel);
window.remove(batteryLabel);
window.remove(timeLabel);
}
private void setLayoutJMenu() {
JMenu layoutJMenu = new JMenu("布局");
layoutJMenu.setFont(font);
JMenuItem singleJMenuItem = new JMenuItem("单列布局");
singleJMenuItem.setFont(font);
singleJMenuItem.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
window.setLabelLayout(LabelLayout.SINGLE);
window.setSize(85, 80);
window.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 1));
reloadWindow();
AppUtil.initWindowLocation(window);
refreshWindow();
}
});
JMenuItem doubleJMenuItem = new JMenuItem("双列布局");
doubleJMenuItem.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
window.setLabelLayout(LabelLayout.DOUBLE);
window.setSize(150, 40);
window.setLayout(new GridLayout(2, 2));
reloadWindow();
AppUtil.initWindowLocation(window);
refreshWindow();
}
});
doubleJMenuItem.setFont(font);
layoutJMenu.add(singleJMenuItem);
layoutJMenu.add(doubleJMenuItem);
jPopupMenu.add(layoutJMenu);
}
private void setRefreshJMenu() {
JMenuItem refreshJMenuItem = new JMenuItem("刷新");
refreshJMenuItem.setFont(font);
refreshJMenuItem.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
refreshWindow();
}
});
jPopupMenu.add(refreshJMenuItem);
}
private void refreshWindow() {
window.setVisible(false);
window.setVisible(true);
}
private void setMovableJMenu() {
JMenuItem movableJMenuItem = new JMenuItem("移动");
movableJMenuItem.setFont(font);
movableJMenuItem.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
windowMovable.setValue(!windowMovable.getValue());
if (windowMovable.isTrue()) {
movableJMenuItem.setText("固定");
} else {
movableJMenuItem.setText("移动");
}
}
});
jPopupMenu.add(movableJMenuItem);
}
private void setJframe() {
this.jframe = new Jframe();
// 设置无边框
jframe.setUndecorated(true);
// 隐藏任务栏图标
jframe.setType(Jframe.Type.UTILITY);
// 设置窗口置顶
jframe.setAlwaysonTop(true);
// 设置背景颜色
jframe.setBackground(new Color(255, 255, 255, 255));
// 设置窗体大小
jframe.setSize(WIDTH, HEIGHT);
// 设置布局
jframe.setLayout(new GridLayout(5, 1));
}
public void display(MouseEvent mouseEvent) {
hiddenframeIfShowing();
hiddenJPopupMenuIfShowing();
jframe.setLocation(mouseEvent.getX() - WIDTH, mouseEvent.getY() - HEIGHT);
jframe.setVisible(true);
jPopupMenu.show(jframe, 0, 0);
// System.out.println("Width=" + jPopupMenu.getWidth() + "Height=" +
// jPopupMenu.getHeight());
}
}
Dll.java
package cxzgwing.dll;
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface Dll extends Library {
Dll dll = Native.load("BatteryMonitor", Dll.class);
int BatteryPercent();
}
AppUtil.java
package cxzgwing.utils;
import java.awt.*;
import java.lang.management.ManagementFactory;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import com.sun.management.OperatingSystemMXBean;
import cxzgwing.Window;
import cxzgwing.dll.Dll;
public class AppUtil {
private static OperatingSystemMXBean systemMXBean;
static {
systemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
}
public static String getTime() {
return LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}
public static String getMemoryLoad() {
double totalPhysicalMemorySize = systemMXBean.getTotalPhysicalMemorySize();
double freePhysicalMemorySize = systemMXBean.getFreePhysicalMemorySize();
double value = freePhysicalMemorySize / totalPhysicalMemorySize;
return "M: " + String.format("%.1f", (1 - value) * 100) + "%";
}
public static String getSystemCpuLoad() {
return "C: " + String.format("%.1f", systemMXBean.getSystemCpuLoad() * 100) + "%";
}
public static String getBatteryPercent() {
int value = 225;
try {
value = Dll.dll.BatteryPercent();
} catch (Exception e) {
e.printStackTrace();
}
return "B: " + value + "%";
}
public static void initWindowLocation(Window window) {
// 获得窗体宽
int windowWidth = window.getWidth();
// 获得窗体高
int windowHeight = window.getHeight();
// 定义工具包
Toolkit kit = Toolkit.getDefaultToolkit();
// 获取屏幕的尺寸
Dimension screenSize = kit.getScreenSize();
// 获取屏幕的宽
int screenWidth = screenSize.width;
// 获取屏幕的高
int screenHeight = screenSize.height;
// 获取任务栏
Insets screenInsets = kit.getScreenInsets(window.getGraphicsConfiguration());
window.setWindowMaxX(screenWidth - windowWidth);
window.setWindowMaxY(screenHeight - windowHeight - screenInsets.bottom);
// 设置窗口相对于指定组件的位置:置于屏幕的中央
// frame.setLocationRelativeTo(null);
// 设置窗体默认在屏幕右下角
window.setLocation(window.getWindowMaxX(), window.getWindowMaxY());
}
}
BatteryLabel.java
package cxzgwing.label.impl;
import cxzgwing.label.LabelAdaptor;
public class BatteryLabel extends LabelAdaptor {
private boolean display;
public BatteryLabel(String text) {
this.setText(text);
this.display = true;
}
@Override
public boolean isDisplay() {
return display;
}
@Override
public void setDisplay(boolean display) {
this.display = display;
}
}
C++创建dll
BatteryMonitor.h
#ifdef BATTERYMONITOR_EXPORTS
#define BATTERYMONITOR_API __declspec(dllexport)
#else
#define BATTERYMONITOR_API __declspec(dllimport)
#endif
extern "C" BATTERYMONITOR_API int BatteryPercent();
BatteryMonitor.cpp
#include "pch.h"
#include
#define BATTERYMONITOR_EXPORTS
#include "BatteryMonitor.h"
#include
using namespace std;
BATTERYMONITOR_API int BatteryPercent(){
SYSTEM_POWER_STATUS sysPowerStatus;
GetSystemPowerStatus(&sysPowerStatus);
return (int)sysPowerStatus.BatteryLifePercent;
}
依赖
4.0.0
cxzgwing
system-monitoring
2.0.0
system-monitoring
UTF-8
1.8
1.8
net.java.dev.jna
jna
5.5.0
maven-clean-plugin
3.1.0
maven-resources-plugin
3.0.2
maven-compiler-plugin
3.8.0
maven-surefire-plugin
2.22.1
maven-jar-plugin
3.0.2
maven-install-plugin
2.5.2
maven-deploy-plugin
2.8.2
maven-site-plugin
3.7.1
maven-project-info-reports-plugin
3.0.0
maven-assembly-plugin
cxzgwing.App
jar-with-dependencies
package
assembly
Github
package cxzgwing;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Objects;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import cxzgwing.judgement.WindowMovable;
import cxzgwing.label.LabelAdaptor;
import cxzgwing.label.impl.BatteryLabel;
import cxzgwing.label.impl.CpuLabel;
import cxzgwing.label.impl.MemoryLabel;
import cxzgwing.label.impl.TimeLabel;
import cxzgwing.utils.AppUtil;
import cxzgwing.utils.LabelLayout;
public class Menu {
private Jframe jframe;
private JPopupMenu jPopupMenu;
private Font font;
private Window window;
private WindowMovable windowMovable;
private CpuLabel cpuLabel;
private MemoryLabel memoryLabel;
private BatteryLabel batteryLabel;
private TimeLabel timeLabel;
private static final int WIDTH = 75;
private static final int HEIGHT = 110;
public Menu(Window window, WindowMovable windowMovable, CpuLabel cpuLabel,
MemoryLabel memoryLabel, BatteryLabel batteryLabel, TimeLabel timeLabel) {
this.window = window;
this.windowMovable = windowMovable;
this.cpuLabel = cpuLabel;
this.memoryLabel = memoryLabel;
this.batteryLabel = batteryLabel;
this.timeLabel = timeLabel;
this.font = new Font("宋体", Font.PLAIN, 13);
init();
addJPopupMenuListener();
}
private void hiddenframeIfShowing() {
if (jframe.isShowing()) {
jframe.setVisible(false);
}
}
private void hiddenJPopupMenuIfShowing() {
if (jPopupMenu.isShowing()) {
jPopupMenu.setVisible(false);
}
}
private void addJPopupMenuListener() {
jPopupMenu.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
hiddenframeIfShowing();
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {}
});
}
private void init() {
setJframe();
setJPopupMenu();
}
private void setJPopupMenu() {
jPopupMenu = new JPopupMenu();
jPopupMenu.setSize(WIDTH, HEIGHT);
setMovableJMenu();
setRefreshJMenu();
setLayoutJMenu();
setDisplayJMenu();
setExitJMenu();
}
private void setExitJMenu() {
JMenuItem exitJMenuItem = new JMenuItem("退出程序");
exitJMenuItem.setFont(font);
exitJMenuItem.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
System.exit(0);
}
});
jPopupMenu.add(exitJMenuItem);
}
private void setDisplayJMenu() {
JMenu displayJMenu = new JMenu("显示");
displayJMenu.setFont(font);
JCheckBox cpuJCheckBox = new JCheckBox("CPU");
cpuJCheckBox.setFont(font);
cpuJCheckBox.setSelected(true);
cpuJCheckBox.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
stateChange(cpuLabel, cpuJCheckBox.isSelected());
}
});
JCheckBox memoryJCheckBox = new JCheckBox("内存");
memoryJCheckBox.setFont(font);
memoryJCheckBox.setSelected(true);
memoryJCheckBox.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
stateChange(memoryLabel, memoryJCheckBox.isSelected());
}
});
JCheckBox batteryJCheckBox = new JCheckBox("电量");
batteryJCheckBox.setFont(font);
batteryJCheckBox.setSelected(true);
batteryJCheckBox.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
stateChange(batteryLabel, batteryJCheckBox.isSelected());
}
});
JCheckBox timeJCheckBox = new JCheckBox("时间");
timeJCheckBox.setFont(font);
timeJCheckBox.setSelected(true);
timeJCheckBox.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
stateChange(timeLabel, timeJCheckBox.isSelected());
}
});
displayJMenu.add(cpuJCheckBox);
displayJMenu.add(memoryJCheckBox);
displayJMenu.add(batteryJCheckBox);
displayJMenu.add(timeJCheckBox);
jPopupMenu.add(displayJMenu);
}
private void stateChange(LabelAdaptor label, boolean isSelected) {
// 在复选框除按下鼠标,移除复选框区域后松开鼠标,此时复选框状态不变,无需操作
if ((label.isDisplay() && isSelected) || (!label.isDisplay() && !isSelected)) {
return;
}
label.setDisplay(isSelected);
windowRemoveAll();
reloadWindow();
refreshWindow();
}
private void reloadWindow() {
int count = getDisplayLabelCount();
GridLayout gridLayout = updateWindowLabelLayout(count);
reloadLabel(gridLayout);
}
private void reloadLabel(GridLayout gridLayout) {
// 由于不显示标签时,不读取相关数据,所以重新显示时需要更新数据
if (cpuLabel.isDisplay()) {
cpuLabel.setText(AppUtil.getSystemCpuLoad());
if (LabelLayout.DOUBLE == window.getLabelLayout() && !Objects.isNull(gridLayout)) {
gridLayout.addLayoutComponent("cpuLabel", cpuLabel);
}
window.add(cpuLabel);
}
if (memoryLabel.isDisplay()) {
memoryLabel.setText(AppUtil.getMemoryLoad());
if (LabelLayout.DOUBLE == window.getLabelLayout() && !Objects.isNull(gridLayout)) {
gridLayout.addLayoutComponent("memoryLabel", memoryLabel);
}
window.add(memoryLabel);
}
if (batteryLabel.isDisplay()) {
batteryLabel.setText(AppUtil.getBatteryPercent());
if (LabelLayout.DOUBLE == window.getLabelLayout() && !Objects.isNull(gridLayout)) {
gridLayout.addLayoutComponent("batteryLabel", batteryLabel);
}
window.add(batteryLabel);
}
if (timeLabel.isDisplay()) {
timeLabel.setText(AppUtil.getTime());
if (LabelLayout.DOUBLE == window.getLabelLayout() && !Objects.isNull(gridLayout)) {
gridLayout.addLayoutComponent("timeLabel", timeLabel);
}
window.add(timeLabel);
}
}
private int getDisplayLabelCount() {
int count = 0;
if (cpuLabel.isDisplay()) {
count++;
}
if (memoryLabel.isDisplay()) {
count++;
}
if (batteryLabel.isDisplay()) {
count++;
}
if (timeLabel.isDisplay()) {
count++;
}
return count;
}
private GridLayout updateWindowLabelLayout(int count) {
GridLayout gridLayout = null;
if (LabelLayout.SINGLE == window.getLabelLayout()) {
// 单列布局
window.setSize(window.getWidth(), 20 * count);
} else if (LabelLayout.DOUBLE == window.getLabelLayout()) {
// 双列布局
switch (count) {
case 1:
window.setLayout(gridLayout = new GridLayout(1, 1));
window.setSize(75, 20);
break;
case 2:
window.setLayout(gridLayout = new GridLayout(1, 2));
window.setSize(150, 20);
break;
case 3:
case 4:
window.setLayout(gridLayout = new GridLayout(2, 2));
window.setSize(150, 40);
break;
default:
window.setLayout(gridLayout = new GridLayout(2, 2));
window.setSize(150, 40);
}
}
AppUtil.initWindowLocation(window);
return gridLayout;
}
private void windowRemoveAll() {
window.remove(cpuLabel);
window.remove(memoryLabel);
window.remove(batteryLabel);
window.remove(timeLabel);
}
private void setLayoutJMenu() {
JMenu layoutJMenu = new JMenu("布局");
layoutJMenu.setFont(font);
JMenuItem singleJMenuItem = new JMenuItem("单列布局");
singleJMenuItem.setFont(font);
singleJMenuItem.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
window.setLabelLayout(LabelLayout.SINGLE);
window.setSize(85, 80);
window.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 1));
reloadWindow();
AppUtil.initWindowLocation(window);
refreshWindow();
}
});
JMenuItem doubleJMenuItem = new JMenuItem("双列布局");
doubleJMenuItem.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
window.setLabelLayout(LabelLayout.DOUBLE);
window.setSize(150, 40);
window.setLayout(new GridLayout(2, 2));
reloadWindow();
AppUtil.initWindowLocation(window);
refreshWindow();
}
});
doubleJMenuItem.setFont(font);
layoutJMenu.add(singleJMenuItem);
layoutJMenu.add(doubleJMenuItem);
jPopupMenu.add(layoutJMenu);
}
private void setRefreshJMenu() {
JMenuItem refreshJMenuItem = new JMenuItem("刷新");
refreshJMenuItem.setFont(font);
refreshJMenuItem.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
refreshWindow();
}
});
jPopupMenu.add(refreshJMenuItem);
}
private void refreshWindow() {
window.setVisible(false);
window.setVisible(true);
}
private void setMovableJMenu() {
JMenuItem movableJMenuItem = new JMenuItem("移动");
movableJMenuItem.setFont(font);
movableJMenuItem.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
windowMovable.setValue(!windowMovable.getValue());
if (windowMovable.isTrue()) {
movableJMenuItem.setText("固定");
} else {
movableJMenuItem.setText("移动");
}
}
});
jPopupMenu.add(movableJMenuItem);
}
private void setJframe() {
this.jframe = new Jframe();
// 设置无边框
jframe.setUndecorated(true);
// 隐藏任务栏图标
jframe.setType(Jframe.Type.UTILITY);
// 设置窗口置顶
jframe.setAlwaysonTop(true);
// 设置背景颜色
jframe.setBackground(new Color(255, 255, 255, 255));
// 设置窗体大小
jframe.setSize(WIDTH, HEIGHT);
// 设置布局
jframe.setLayout(new GridLayout(5, 1));
}
public void display(MouseEvent mouseEvent) {
hiddenframeIfShowing();
hiddenJPopupMenuIfShowing();
jframe.setLocation(mouseEvent.getX() - WIDTH, mouseEvent.getY() - HEIGHT);
jframe.setVisible(true);
jPopupMenu.show(jframe, 0, 0);
// System.out.println("Width=" + jPopupMenu.getWidth() + "Height=" +
// jPopupMenu.getHeight());
}
}
Dll.java
package cxzgwing.dll;
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface Dll extends Library {
Dll dll = Native.load("BatteryMonitor", Dll.class);
int BatteryPercent();
}
AppUtil.java
package cxzgwing.utils;
import java.awt.*;
import java.lang.management.ManagementFactory;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import com.sun.management.OperatingSystemMXBean;
import cxzgwing.Window;
import cxzgwing.dll.Dll;
public class AppUtil {
private static OperatingSystemMXBean systemMXBean;
static {
systemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
}
public static String getTime() {
return LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}
public static String getMemoryLoad() {
double totalPhysicalMemorySize = systemMXBean.getTotalPhysicalMemorySize();
double freePhysicalMemorySize = systemMXBean.getFreePhysicalMemorySize();
double value = freePhysicalMemorySize / totalPhysicalMemorySize;
return "M: " + String.format("%.1f", (1 - value) * 100) + "%";
}
public static String getSystemCpuLoad() {
return "C: " + String.format("%.1f", systemMXBean.getSystemCpuLoad() * 100) + "%";
}
public static String getBatteryPercent() {
int value = 225;
try {
value = Dll.dll.BatteryPercent();
} catch (Exception e) {
e.printStackTrace();
}
return "B: " + value + "%";
}
public static void initWindowLocation(Window window) {
// 获得窗体宽
int windowWidth = window.getWidth();
// 获得窗体高
int windowHeight = window.getHeight();
// 定义工具包
Toolkit kit = Toolkit.getDefaultToolkit();
// 获取屏幕的尺寸
Dimension screenSize = kit.getScreenSize();
// 获取屏幕的宽
int screenWidth = screenSize.width;
// 获取屏幕的高
int screenHeight = screenSize.height;
// 获取任务栏
Insets screenInsets = kit.getScreenInsets(window.getGraphicsConfiguration());
window.setWindowMaxX(screenWidth - windowWidth);
window.setWindowMaxY(screenHeight - windowHeight - screenInsets.bottom);
// 设置窗口相对于指定组件的位置:置于屏幕的中央
// frame.setLocationRelativeTo(null);
// 设置窗体默认在屏幕右下角
window.setLocation(window.getWindowMaxX(), window.getWindowMaxY());
}
}
BatteryLabel.java
package cxzgwing.label.impl;
import cxzgwing.label.LabelAdaptor;
public class BatteryLabel extends LabelAdaptor {
private boolean display;
public BatteryLabel(String text) {
this.setText(text);
this.display = true;
}
@Override
public boolean isDisplay() {
return display;
}
@Override
public void setDisplay(boolean display) {
this.display = display;
}
}
C++创建dll
BatteryMonitor.h
#ifdef BATTERYMONITOR_EXPORTS
#define BATTERYMONITOR_API __declspec(dllexport)
#else
#define BATTERYMONITOR_API __declspec(dllimport)
#endif
extern "C" BATTERYMONITOR_API int BatteryPercent();
BatteryMonitor.cpp
#include "pch.h"
#include
#define BATTERYMONITOR_EXPORTS
#include "BatteryMonitor.h"
#include
using namespace std;
BATTERYMONITOR_API int BatteryPercent(){
SYSTEM_POWER_STATUS sysPowerStatus;
GetSystemPowerStatus(&sysPowerStatus);
return (int)sysPowerStatus.BatteryLifePercent;
}
依赖
4.0.0
cxzgwing
system-monitoring
2.0.0
system-monitoring
UTF-8
1.8
1.8
net.java.dev.jna
jna
5.5.0
maven-clean-plugin
3.1.0
maven-resources-plugin
3.0.2
maven-compiler-plugin
3.8.0
maven-surefire-plugin
2.22.1
maven-jar-plugin
3.0.2
maven-install-plugin
2.5.2
maven-deploy-plugin
2.8.2
maven-site-plugin
3.7.1
maven-project-info-reports-plugin
3.0.0
maven-assembly-plugin
cxzgwing.App
jar-with-dependencies
package
assembly
Github
package cxzgwing.utils;
import java.awt.*;
import java.lang.management.ManagementFactory;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import com.sun.management.OperatingSystemMXBean;
import cxzgwing.Window;
import cxzgwing.dll.Dll;
public class AppUtil {
private static OperatingSystemMXBean systemMXBean;
static {
systemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
}
public static String getTime() {
return LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
}
public static String getMemoryLoad() {
double totalPhysicalMemorySize = systemMXBean.getTotalPhysicalMemorySize();
double freePhysicalMemorySize = systemMXBean.getFreePhysicalMemorySize();
double value = freePhysicalMemorySize / totalPhysicalMemorySize;
return "M: " + String.format("%.1f", (1 - value) * 100) + "%";
}
public static String getSystemCpuLoad() {
return "C: " + String.format("%.1f", systemMXBean.getSystemCpuLoad() * 100) + "%";
}
public static String getBatteryPercent() {
int value = 225;
try {
value = Dll.dll.BatteryPercent();
} catch (Exception e) {
e.printStackTrace();
}
return "B: " + value + "%";
}
public static void initWindowLocation(Window window) {
// 获得窗体宽
int windowWidth = window.getWidth();
// 获得窗体高
int windowHeight = window.getHeight();
// 定义工具包
Toolkit kit = Toolkit.getDefaultToolkit();
// 获取屏幕的尺寸
Dimension screenSize = kit.getScreenSize();
// 获取屏幕的宽
int screenWidth = screenSize.width;
// 获取屏幕的高
int screenHeight = screenSize.height;
// 获取任务栏
Insets screenInsets = kit.getScreenInsets(window.getGraphicsConfiguration());
window.setWindowMaxX(screenWidth - windowWidth);
window.setWindowMaxY(screenHeight - windowHeight - screenInsets.bottom);
// 设置窗口相对于指定组件的位置:置于屏幕的中央
// frame.setLocationRelativeTo(null);
// 设置窗体默认在屏幕右下角
window.setLocation(window.getWindowMaxX(), window.getWindowMaxY());
}
}
BatteryLabel.java
package cxzgwing.label.impl;
import cxzgwing.label.LabelAdaptor;
public class BatteryLabel extends LabelAdaptor {
private boolean display;
public BatteryLabel(String text) {
this.setText(text);
this.display = true;
}
@Override
public boolean isDisplay() {
return display;
}
@Override
public void setDisplay(boolean display) {
this.display = display;
}
}
C++创建dll
BatteryMonitor.h
#ifdef BATTERYMONITOR_EXPORTS
#define BATTERYMONITOR_API __declspec(dllexport)
#else
#define BATTERYMONITOR_API __declspec(dllimport)
#endif
extern "C" BATTERYMONITOR_API int BatteryPercent();
BatteryMonitor.cpp
#include "pch.h"
#include
#define BATTERYMONITOR_EXPORTS
#include "BatteryMonitor.h"
#include
using namespace std;
BATTERYMONITOR_API int BatteryPercent(){
SYSTEM_POWER_STATUS sysPowerStatus;
GetSystemPowerStatus(&sysPowerStatus);
return (int)sysPowerStatus.BatteryLifePercent;
}
依赖
4.0.0
cxzgwing
system-monitoring
2.0.0
system-monitoring
UTF-8
1.8
1.8
net.java.dev.jna
jna
5.5.0
maven-clean-plugin
3.1.0
maven-resources-plugin
3.0.2
maven-compiler-plugin
3.8.0
maven-surefire-plugin
2.22.1
maven-jar-plugin
3.0.2
maven-install-plugin
2.5.2
maven-deploy-plugin
2.8.2
maven-site-plugin
3.7.1
maven-project-info-reports-plugin
3.0.0
maven-assembly-plugin
cxzgwing.App
jar-with-dependencies
package
assembly
Github
BatteryMonitor.h
#ifdef BATTERYMONITOR_EXPORTS
#define BATTERYMONITOR_API __declspec(dllexport)
#else
#define BATTERYMONITOR_API __declspec(dllimport)
#endif
extern "C" BATTERYMONITOR_API int BatteryPercent();
BatteryMonitor.cpp
#include "pch.h"
#include
#define BATTERYMONITOR_EXPORTS
#include "BatteryMonitor.h"
#include
using namespace std;
BATTERYMONITOR_API int BatteryPercent(){
SYSTEM_POWER_STATUS sysPowerStatus;
GetSystemPowerStatus(&sysPowerStatus);
return (int)sysPowerStatus.BatteryLifePercent;
}
依赖
4.0.0
cxzgwing
system-monitoring
2.0.0
system-monitoring
UTF-8
1.8
1.8
net.java.dev.jna
jna
5.5.0
maven-clean-plugin
3.1.0
maven-resources-plugin
3.0.2
maven-compiler-plugin
3.8.0
maven-surefire-plugin
2.22.1
maven-jar-plugin
3.0.2
maven-install-plugin
2.5.2
maven-deploy-plugin
2.8.2
maven-site-plugin
3.7.1
maven-project-info-reports-plugin
3.0.0
maven-assembly-plugin
cxzgwing.App
jar-with-dependencies
package
assembly
Github
#include "pch.h" #include#define BATTERYMONITOR_EXPORTS #include "BatteryMonitor.h" #include using namespace std; BATTERYMONITOR_API int BatteryPercent(){ SYSTEM_POWER_STATUS sysPowerStatus; GetSystemPowerStatus(&sysPowerStatus); return (int)sysPowerStatus.BatteryLifePercent; }
依赖
4.0.0
cxzgwing
system-monitoring
2.0.0
system-monitoring
UTF-8
1.8
1.8
net.java.dev.jna
jna
5.5.0
maven-clean-plugin
3.1.0
maven-resources-plugin
3.0.2
maven-compiler-plugin
3.8.0
maven-surefire-plugin
2.22.1
maven-jar-plugin
3.0.2
maven-install-plugin
2.5.2
maven-deploy-plugin
2.8.2
maven-site-plugin
3.7.1
maven-project-info-reports-plugin
3.0.0
maven-assembly-plugin
cxzgwing.App
jar-with-dependencies
package
assembly
Github
GitHub - cxzgwing/system-monitoring: Java Swing applet, real-time monitoring system CPU usage and memory usage.
Gitee
system-monitoring: Java Swing applet, real-time monitoring system CPU usage and memory usage.
参考链接
[1] 晨曦之光Wing.Java简易系统监视器. 2021-06-13 18:08:36
https://blog.csdn.net/qq_36533690/article/details/117881862
[2] xietansheng.Java Swing 图形界面开发(目录).2017-05-30 23:50:42
https://xiets.blog.csdn.net/article/details/72814492
[3] lucky__cc.【Swing】Java Swing JPopupMenu:弹出式菜单. 2019-08-06 22:03:34
https://blog.csdn.net/qq1437722579/article/details/98663286
[4] 艾斯曼.一个找了很久的API函数---GetSystemPowerStatus.2013-01-23 21:47:51
https://blog.csdn.net/wangqiulin123456/article/details/8535809
[5] 晨曦之光Wing.Java调用dll文件.2021-11-10 11:06:51
https://blog.csdn.net/qq_36533690/article/details/121239139
后记
此次是在之前的基础之上修改的,由两个问题引发,一是笔记本电池之前鼓包,买了新电池,想要实时查看电量。二是全屏看视频时有时候想看时间(全屏看视频时,这个窗体会一直显示)。所以就加上了显示电量和时间两个指标。
经过一番查询,发现C++可以读取电池数据,C++创建动态链接库dll文件,再通过Java使用jna调用dll文件。于是就自己干!写C++,做dll!(我发现用C++创建动态链接库dll文件会上瘾,没办法,C++太强大了)
进一步考虑到有些小伙伴可能用台式机,不需要电量信息,甚至不需要CPU使用率或者内存使用率或者时间,干脆就做成动态的算了,于是托盘菜单新增了“显示”按钮,可勾选显示的内容。
考虑到如果只显示一个参数或两个参数,原布局就很丑了,干脆加一个调整布局按钮,于是托盘菜单新增了“布局”按钮,可修改布局。
后面发现,布局和显示混合使用,情况多样,有的情况又很丑了,索性做成了动态布局,窗体根据显示的参数个数自动适配布局。
进一步开发,后来发现已采用的菜单栏的创建方案二使用JPopupMenu会导致多级菜单栏有问题,jPopupMenu.show(Component invoker, int x, int y)需要有Component(不加的话多级菜单的子菜单就弹不出来),但是系统托盘这玩意儿SystemTray它不是Component……所以想了个方法,直接新建一个Jframe,用它来和JPopupMenu绑定,Jframe和JPopupMenu大小一致,且显示和隐藏的状态一致就哦了,然后就大改了……嗯,面目全非、惨不忍睹。
然后发现新方法在弹出系统托盘菜单后,鼠标点击非菜单区域,菜单会自动消失(之前是不会的,所以用了jnativehook做全局鼠标监听,配合鼠标的位置判断,达到该效果),所以就不需要用jnativehook了。
最后为了方便和那什么,封装了Label,用了线程池。



