目录
效果图
功能说明
- Java Swing小程序,实时监测系统CPU使用率和内存使用率,每秒刷新一次。
- 程序启动默认位置为屏幕右下角,且默认无法移动。
- 鼠标右击系统托盘图标可弹出菜单栏,菜单栏上有“移动”、“取消”、“退出程序”三个按钮。
- 点击“移动”按钮后,方可移动窗体,此时鼠标若悬浮于窗体之上则变成十字状态,窗体有边界限制,不可移至屏幕外;再次点击该按钮时(此时显示为“固定”按钮)即可固定位置。
- 点击“取消”按钮后隐藏菜单栏。当菜单栏显示时,鼠标左击菜单栏之外的区域也可隐藏菜单栏。
- 点击“退出程序”按钮即可退出该程序。
- 窗体默认隐藏任务栏图标,且设置为置顶显示。
项目与工具
Maven、maven-assembly-plugin、Java 8、jnativehook-2.1.0
项目说明
- 窗体使用JFrame,且自定义样式。
- 菜单栏使用JPopupMenu,“当菜单栏显示时,鼠标左击菜单栏之外的区域也可隐藏菜单栏”的技术点为jnativehook全局监听鼠标左击。详细说明:由于“创建点击图标时的弹出菜单方案二”中,弹出的菜单无法消失,会一直显示,所以需要根据鼠标是否悬浮于菜单上以及鼠标左键是否点击来判断是否需要隐藏菜单:若鼠标不在菜单上并且鼠标左键点击了并且菜单是显示状态,则隐藏菜单。默认设置为鼠标未悬浮于菜单之上、鼠标未点击、菜单未显示。其中,鼠标是否悬浮于菜单上的判断条件包含鼠标是否悬浮于菜单上、鼠标是否悬浮于按钮上。
- 菜单栏创建方案有两种,此项目使用的是方案二JPopupMenu,方案一PopupMenu的代码也保留在项目中(已注释)。简要说明采用方案二的原因:使用PopupMenu创建的菜单栏,无法添加鼠标监听,局限性太大。
目录结构
代码
MouseClicked.java
package cxzgwing.judgement;
public class MouseClicked {
private boolean value;
public MouseClicked(boolean value) {
this.value = value;
}
public boolean isTrue() {
return value;
}
public boolean getValue() {
return value;
}
public synchronized void setValue(boolean value) {
this.value = value;
}
}
MouseOnJPopupMenu.java
package cxzgwing.judgement;
public class MouseOnJPopupMenu {
private boolean value;
public MouseOnJPopupMenu(boolean value) {
this.value = value;
}
public boolean isTrue() {
return value;
}
public boolean getValue() {
return value;
}
public synchronized void setValue(boolean value) {
this.value = value;
}
}
WindowMovable.java
package cxzgwing.judgement;
public class WindowMovable {
private boolean value;
public WindowMovable(boolean value) {
this.value = value;
}
public boolean isTrue() {
return value;
}
public boolean getValue() {
return value;
}
synchronized public void setValue(boolean value) {
this.value = value;
}
}
FrameDragListener.java
package cxzgwing.listener;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import cxzgwing.judgement.WindowMovable;
public class FrameDragListener extends MouseAdapter {
private final JFrame frame;
private WindowMovable windowMovable;
private Point mouseDownCompCoords = null;
// 窗体位置最大横坐标
private int windowMaxX;
// 窗体位置最大纵坐标
private int windowMaxY;
public FrameDragListener(JFrame frame, WindowMovable windowMovable, int windowMaxX,
int windowMaxY) {
this.frame = frame;
this.windowMovable = windowMovable;
this.windowMaxX = windowMaxX;
this.windowMaxY = windowMaxY;
}
@Override
public void mouseReleased(MouseEvent e) {
mouseDownCompCoords = null;
}
@Override
public void mousePressed(MouseEvent e) {
mouseDownCompCoords = e.getPoint();
}
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mouseDragged(MouseEvent e) {
if (!windowMovable.isTrue()) {
mouseDownCompCoords = null;
return;
}
Point currCoords = e.getLocationOnScreen();
int x = currCoords.x - mouseDownCompCoords.x;
int y = currCoords.y - mouseDownCompCoords.y;
if (x < 0) {
x = 0;
}
if (x > windowMaxX) {
x = windowMaxX;
}
if (y < 0) {
y = 0;
}
if (y > windowMaxY) {
y = windowMaxY;
}
frame.setLocation(x, y);
}
@Override
public void mouseEntered(MouseEvent e) {
if (windowMovable.isTrue()) {
frame.setCursor(new Cursor(Cursor.MOVE_CURSOR));
}
}
@Override
public void mouseExited(MouseEvent e) {
if (windowMovable.isTrue()) {
frame.setCursor(Cursor.getDefaultCursor());
}
}
}
TrayIconMouseListener.java
package cxzgwing.listener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
/**
* 任务栏图标鼠标监听
*/
public class TrayIconMouseListener extends MouseAdapter {
private JPopupMenu jPopupMenu;
private int jPopupMenuWidth;
private int jPopupMenuHeight;
public TrayIconMouseListener(JPopupMenu jPopupMenu, int jPopupMenuWidth, int jPopupMenuHeight) {
this.jPopupMenu = jPopupMenu;
this.jPopupMenuWidth = jPopupMenuWidth;
this.jPopupMenuHeight = jPopupMenuHeight;
}
// 仅监听鼠标点击事件
@Override
public void mouseClicked(MouseEvent e) {
switch (e.getButton()) {
// 托盘图标被鼠标右键被点击
case MouseEvent.BUTTON3: {
jPopupMenu.setLocation(e.getX() - jPopupMenuWidth, e.getY() - jPopupMenuHeight);
jPopupMenu.setVisible(true);
break;
}
default: {
break;
}
}
}
}
AppUtil.java
package cxzgwing.utils;
import cxzgwing.judgement.MouseClicked;
import cxzgwing.judgement.MouseOnJPopupMenu;
public class AppUtil {
/**
* 初始化默认状态:鼠标未悬浮于菜单之上、鼠标未点击
*/
public static void initDefaultStatus(MouseOnJPopupMenu mouseOnJPopupMenu,
MouseClicked mouseClicked) {
mouseOnJPopupMenu.setValue(false);
mouseClicked.setValue(false);
}
}
App.java
package cxzgwing;
public class App {
public static void main(String[] args) {
new Window();
}
}
Window.java
package cxzgwing;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.RoundRectangle2D;
import java.lang.management.ManagementFactory;
import java.time.Clock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import org.jnativehook.GlobalScreen;
import org.jnativehook.mouse.NativeMouseEvent;
import org.jnativehook.mouse.NativeMouseInputListener;
import com.sun.awt.AWTUtilities;
import com.sun.management.OperatingSystemMXBean;
import cxzgwing.judgement.MouseClicked;
import cxzgwing.judgement.MouseOnJPopupMenu;
import cxzgwing.judgement.WindowMovable;
import cxzgwing.listener.FrameDragListener;
import cxzgwing.listener.TrayIconMouseListener;
import cxzgwing.utils.AppUtil;
/**
* <p>
* 由于“创建点击图标时的弹出菜单方案二”中,弹出的菜单无法消失,会一直显示,所以需要根据鼠标是否悬浮于菜单上以及鼠标左键是否点<br>
* 击来判断是否需要隐藏菜单:若鼠标不在菜单上并且鼠标左键点击了并且菜单是显示状态,则隐藏菜单。默认设置为鼠标未悬浮于菜单之上、<br>
* 鼠标未点击、菜单未显示
* </P>
*
* @see #initMouseClicked()
* @see #initMouseOnJPopupMenu()
*/
public class Window extends JFrame implements NativeMouseInputListener {
private OperatingSystemMXBean operatingSystemMXBean =
(OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
private Font font;
private MouseOnJPopupMenu mouseOnJPopupMenu;
private MouseClicked mouseClicked;
private WindowMovable windowMovable;
private JPopupMenu jPopupMenu;
private JMenuItem movableButton;
private JMenuItem exitButton;
private JMenuItem cancelButton;
// jPopupMenu width
private static final int WIDTH = 75;
// jPopupMenu height
private static final int HEIGHT = 68;
// 窗体位置最大横坐标
private int windowMaxX;
// 窗体位置最大纵坐标
private int windowMaxY;
public Window() {
// 关闭日志
Logger.getLogger(GlobalScreen.class.getPackage().getName()).setLevel(Level.OFF);
initFont();
initMouseOnJPopupMenu();
initMouseClicked();
initWindowMovable();
initJPopupMenuAndButton();
initWindow();
}
/**
* 初始化字体
*/
private void initFont() {
font = new Font("宋体", Font.PLAIN, 13);
}
/**
* 初始化鼠标是否悬浮于菜单之上,默认设置鼠标未悬浮于菜单之上
*/
private void initMouseOnJPopupMenu() {
mouseOnJPopupMenu = new MouseOnJPopupMenu(false);
}
/**
* 初始化鼠标是否点击,默认设置鼠标左键未点击
*/
private void initMouseClicked() {
mouseClicked = new MouseClicked(false);
}
/**
* 初始化窗体是否可移动, 默认设置窗体不可移动
*/
private void initWindowMovable() {
windowMovable = new WindowMovable(false);
}
/**
* 初始化系统托盘菜单及其按钮
*/
private void initJPopupMenuAndButton() {
// 创建菜单
jPopupMenu = new JPopupMenu();
jPopupMenu.setSize(WIDTH, HEIGHT);
setJPopupMenuMouseListener();
// “移动”按钮
movableButton = new JMenuItem("移动");
movableButton.setFont(font);
setMovableButtonMouseListener();
// “取消”按钮
cancelButton = new JMenuItem("取消");
cancelButton.setFont(font);
setCancelButtonMouseListener();
// “退出程序”按钮
exitButton = new JMenuItem("退出程序");
exitButton.setFont(font);
setExitButtonMouseListener();
// 将按钮添加至菜单
jPopupMenu.add(movableButton);
jPopupMenu.add(cancelButton);
jPopupMenu.add(exitButton);
}
/**
* 设置“取消”按钮鼠标左击监听
*/
private void setCancelButtonMouseListener() {
cancelButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
switch (e.getButton()) {
// JMenuItem被鼠标左键点击
case MouseEvent.BUTTON1: {
if (jPopupMenu.isVisible()) {
cancelButton.setBackground(Color.WHITE);
jPopupMenu.setVisible(false);
}
break;
}
default: {
break;
}
}
}
@Override
public void mouseEntered(MouseEvent e) {
// 设置鼠标悬浮时按钮的背景颜色
cancelButton.setBackground(Color.GRAY);
// 设置鼠标悬浮于菜单之上
mouseOnJPopupMenu.setValue(true);
}
@Override
public void mouseExited(MouseEvent e) {
// 设置鼠标离开后按钮的背景颜色
cancelButton.setBackground(Color.WHITE);
// 设置鼠标未悬浮于菜单之上
mouseOnJPopupMenu.setValue(false);
}
});
}
/**
* 设置菜单的鼠标监听,移入菜单时将鼠标是否悬浮于菜单之上(mouseOnJPopupMenu)设置为true,移出菜单时mouseOnJPopupMenu设置<br>
* 为false。
*/
private void setJPopupMenuMouseListener() {
jPopupMenu.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
mouseOnJPopupMenu.setValue(true);
}
@Override
public void mouseExited(MouseEvent e) {
mouseOnJPopupMenu.setValue(false);
}
});
}
/**
* <p>
* 设置“移动 / 固定”按钮鼠标左击监听
* </P>
*
* <p>
* 窗体默认位置在屏幕右下角,且默认不能移动窗体。 当右击系统托盘弹出菜单后,点击第一个按钮后(此时为“移动”按钮), 即可移<br>
* 动窗体位置, 窗体移动有边界限制,不能移出屏幕外,且此时鼠标若悬浮于窗体之上,则将变为十字状态,菜单中的“移动”按钮变成了<br>
* “固定”按钮。当点击“固定”按钮时,窗体固定在当前位置,无法移动。
* </P>
*/
private void setMovableButtonMouseListener() {
movableButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
switch (e.getButton()) {
// JMenuItem被鼠标左键点击
case MouseEvent.BUTTON1: {
// 点击“移动”后方可移动窗体,点击“固定”后方可固定窗体位置
windowMovable.setValue(!windowMovable.getValue());
if (windowMovable.isTrue()) {
movableButton.setText("固定");
} else {
movableButton.setText("移动");
}
movableButton.setBackground(Color.WHITE);
jPopupMenu.setVisible(false);
break;
}
default: {
break;
}
}
}
@Override
public void mouseEntered(MouseEvent e) {
// 设置鼠标悬浮时按钮的背景颜色
// 注:此处使用系统预设颜色,如果使用new Color,则会出现重影以及两个JMenuItem互相干扰的情况(具体原因不明)
movableButton.setBackground(Color.GRAY);
// 设置鼠标悬浮于菜单之上
mouseOnJPopupMenu.setValue(true);
}
@Override
public void mouseExited(MouseEvent e) {
// 设置鼠标离开后按钮的背景颜色
movableButton.setBackground(Color.WHITE);
// 设置鼠标未悬浮于菜单之上
mouseOnJPopupMenu.setValue(false);
}
});
}
/**
* <p>
* 设置“退出程序”按钮鼠标左击监听
* </p>
*/
private void setExitButtonMouseListener() {
exitButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
switch (e.getButton()) {
// JMenuItem被鼠标左键点击
case MouseEvent.BUTTON1: {
System.exit(0);
break;
}
default: {
break;
}
}
}
@Override
public void mouseEntered(MouseEvent e) {
// 设置鼠标悬浮时按钮的背景颜色
exitButton.setBackground(Color.GRAY);
// 设置鼠标悬浮于菜单之上
mouseOnJPopupMenu.setValue(true);
}
@Override
public void mouseExited(MouseEvent e) {
// 设置鼠标离开后按钮的背景颜色
exitButton.setBackground(Color.WHITE);
// 设置鼠标未悬浮于菜单之上
mouseOnJPopupMenu.setValue(false);
}
});
}
/**
* 初始化窗体,显示CPU使用率和Mem使用率
*/
private void initWindow() {
try {
// 隐藏任务栏图标
this.setType(JFrame.Type.UTILITY);
java.awt.Window win = new java.awt.Window(this);
// 设置为swing默认窗体
JFrame.setDefaultLookAndFeelDecorated(true);
// 设置圆角
AWTUtilities.setWindowShape(win, new RoundRectangle2D.Double(0.0D, 0.0D, win.getWidth(),
win.getHeight(), 26.0D, 26.0D));
// 设置窗口置顶
this.setAlwaysOnTop(true);
// 设置网格包布局
GridBagLayout gridBagLayout = new GridBagLayout();
this.setLayout(gridBagLayout);
// 显示区域独占一行(换行),组件填充显示区域
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER;
gridBagConstraints.fill = GridBagConstraints.BOTH;
// 设置无边框
this.setUndecorated(true);
// 设置背景色
this.setBackground(new Color(0, 0, 0, 85));
// CPU使用率显示标签
String cpuMsg = "CPU: 0.0%";
JLabel cpuJLabel = new JLabel(cpuMsg);
cpuJLabel.setForeground(Color.WHITE);
Font font = new Font("黑体", Font.PLAIN, 16);
cpuJLabel.setFont(font);
gridBagLayout.addLayoutComponent(cpuJLabel, gridBagConstraints);
this.add(cpuJLabel);
// 内存使用率显示标签
String memMsg = "Mem: 0.0%";
JLabel memoryJLabel = new JLabel(memMsg);
memoryJLabel.setForeground(Color.WHITE);
memoryJLabel.setFont(font);
this.add(memoryJLabel);
// 设置窗体大小
this.setSize(100, 40);
// 设置窗体最大位置坐标
initWindowMaxLocation();
// 设置窗体默认位置
setDefaultLocation();
// 设置鼠标监听,可通过鼠标移动窗体位置
// 通过系统托盘菜单中的第一个按钮(移动 / 固定)来控制是否能移动窗体
FrameDragListener frameDragListener =
new FrameDragListener(this, windowMovable, windowMaxX, windowMaxY);
this.addMouseListener(frameDragListener);
this.addMouseMotionListener(frameDragListener);
// 添加窗体状态监听,使窗体一直显示
setWindowAlwaysShow();
// 设置点击关闭按钮退出程序
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// 添加系统托盘
setSystemTray();
// 全局监听鼠标点击
GlobalScreen.registerNativeHook();
GlobalScreen.addNativeMouseListener(this);
// 显示
this.setVisible(true);
// 监控
monitoring(cpuJLabel, memoryJLabel);
} catch (Exception e) {
e.printStackTrace();
}
}
private void initWindowMaxLocation() {
// 获得窗体宽
int windowWidth = this.getWidth();
// 获得窗体高
int windowHeight = this.getHeight();
// 定义工具包
Toolkit kit = Toolkit.getDefaultToolkit();
// 获取屏幕的尺寸
Dimension screenSize = kit.getScreenSize();
// 获取屏幕的宽
int screenWidth = screenSize.width;
// 获取屏幕的高
int screenHeight = screenSize.height;
// 获取任务栏
Insets screenInsets = kit.getScreenInsets(this.getGraphicsConfiguration());
windowMaxX = screenWidth - windowWidth;
windowMaxY = screenHeight - windowHeight - screenInsets.bottom;
}
/**
* 监控
*
* @param cpuJLabel CPU使用率显示标签
* @param memoryJLabel 内存使用率显示标签
*/
private void monitoring(JLabel cpuJLabel, JLabel memoryJLabel) {
int times = 0;
while (true) {
// 获取CPU使用率
String cpuLoad = String.format("%.1f", operatingSystemMXBean.getSystemCpuLoad() * 100);
// 获取内存使用率
double totalPhysicalMemorySize = operatingSystemMXBean.getTotalPhysicalMemorySize();
double freePhysicalMemorySize = operatingSystemMXBean.getFreePhysicalMemorySize();
double value = freePhysicalMemorySize / totalPhysicalMemorySize;
String memoryLoad = String.format("%.1f", (1 - value) * 100);
cpuJLabel.setText("CPU: " + cpuLoad + "%");
memoryJLabel.setText("Mem: " + memoryLoad + "%");
// 每10分钟gc一次
times++;
if (times >= 600) {
times = 0;
System.gc();
}
// System.out.println("CPU: " + cpuLoad + "%, Mem: " + memoryLoad + "%");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
/**
* 添加系统托盘
*/
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"));
// 创建一个托盘图标:new TrayIcon
// 创建点击图标时的弹出菜单方案一:PopupMenu
// TrayIcon trayIcon =
// new TrayIcon(image, "System Monitoring", createPopupMenu(frameMovable));
// trayIcon.addActionListener(e -> System.out.println("addActionListener:
// 托盘图标被右键点击"));
// 创建点击图标时的弹出菜单方案二:JPopupMenu
TrayIcon trayIcon = new TrayIcon(image, "System Monitoring");
trayIcon.addMouseListener(new TrayIconMouseListener(jPopupMenu, WIDTH, HEIGHT));
// 托盘图标自适应尺寸
trayIcon.setImageAutoSize(true);
// 添加托盘图标到系统托盘
tray.add(trayIcon);
} else {
throw new Exception("当前系统不支持系统托盘");
}
} catch (Exception e) {
throw e;
}
}
/**
* 创建点击图标时的弹出菜单方案一:PopupMenu
*
* @return 菜单
*/
private PopupMenu createPopupMenu() {
PopupMenu popupMenu = new PopupMenu();
// 移动 / 固定
MenuItem movableItem = new MenuItem("移动");
movableItem.addActionListener(e -> {
windowMovable.setValue(!windowMovable.getValue());
if (windowMovable.isTrue()) {
movableItem.setLabel("固定");
} else {
movableItem.setLabel("移动");
}
});
popupMenu.add(movableItem);
// 退出
MenuItem exitItem = new MenuItem("退出");
// 点击退出菜单时退出程序
exitItem.addActionListener(e -> System.exit(0));
popupMenu.add(exitItem);
return popupMenu;
}
/**
* 设置窗体默认位置
*/
private void setDefaultLocation() throws Exception {
// 设置窗口相对于指定组件的位置:置于屏幕的中央
// frame.setLocationRelativeTo(null);
// 设置窗体默认在屏幕右下角
this.setLocation(windowMaxX, windowMaxY);
}
/**
* 添加窗体状态监听,使窗体一直显示
*/
private void setWindowAlwaysShow() {
this.addWindowStateListener(e -> {
int newState = e.getNewState();
if (JFrame.ICONIFIED == newState) {
this.setState(JFrame.NORMAL);
}
});
}
/**
* 鼠标点击全局监听,设置隐藏菜单:若鼠标未悬浮于菜单之上(实际为若鼠标未悬浮于菜单或按钮之上)且鼠标左键点击了且菜单为显示<br>
* 状态,则隐藏菜单
*/
@Override
public void nativeMouseClicked(NativeMouseEvent nativeMouseEvent) {
int button = nativeMouseEvent.getButton();
// 鼠标左键点击
if (MouseEvent.BUTTON1 == button) {
mouseClicked.setValue(true);
if (!mouseOnJPopupMenu.isTrue() && mouseClicked.isTrue() && jPopupMenu.isVisible()) {
jPopupMenu.setVisible(false);
// 菜单隐藏后,需要初始化判断状态,设置鼠标未悬浮于菜单之上、鼠标未点击
AppUtil.initDefaultStatus(mouseOnJPopupMenu, mouseClicked);
}
}
}
@Override
public void nativeMousePressed(NativeMouseEvent nativeMouseEvent) {}
@Override
public void nativeMouseReleased(NativeMouseEvent nativeMouseEvent) {}
@Override
public void nativeMouseMoved(NativeMouseEvent nativeMouseEvent) {}
@Override
public void nativeMouseDragged(NativeMouseEvent nativeMouseEvent) {}
}
依赖
<!-- https://mvnrepository.com/artifact/com.1stleg/jnativehook -->
<dependency>
<groupId>com.1stleg</groupId>
<artifactId>jnativehook</artifactId>
<version>2.1.0</version>
</dependency>
GitHub
与本文对应版本的分支为:cxzgwing/system-monitoring at first (github.com)
Gitee
参考链接
[1] 紫伟.java获取系统CPU和内存使用率的三种方法. 2020-04-09 18:38:01
https://blog.csdn.net/qq_41866138/article/details/105386832
[2] 漫漫人生路总会错几步.java swing实现漂亮的弹窗.2018-02-28 13:39
https://www.cnblogs.com/swtjavaspace/articles/8483192.html
[3] xietansheng.JavaSwing_1.3: GridBagLayout(网格袋布局).2017-05-30 23:57:01
https://blog.csdn.net/xietansheng/article/details/72814552
[4] 使一个java swing框架可移动和setUndecorated.2019-01-19
http://www.voidcn.com/article/p-kjyhyaxq-bup.html
原文 https://stackoverflow.com/questions/16046824/making-a-java-swing-frame-movable-and-setundecorated
[5] Java™ Platform, Standard Edition 8 API Specification
https://docs.oracle.com/javase/8/docs/api/index.html
[6] 水岛一凉.java swing最小化_Java Swing - 如何禁用JFrame最小化按钮.2021-02-12 18:45:59
https://blog.csdn.net/weixin_35893552/article/details/114067547
[7] ycb1689.java取任务栏高度的方法汇集.2012-04-26 14:54:11
https://blog.csdn.net/ycb1689/article/details/7514339
[8] xietansheng.JavaSwing_5.6: 系统托盘(System Tray). 2017-10-29 23:46:31
https://blog.csdn.net/xietansheng/article/details/78389278
[9] BeautyEye_Moon.Jframe任务栏图标隐藏.2014-01-02 20:02:00
https://blog.csdn.net/u011697031/article/details/17764345
[10] 晨曦之光Wing.Java全局监听鼠标点击.2021-06-12 22:15:29
https://blog.csdn.net/qq_36533690/article/details/117856307
后记
去年做了一个【Java】简易视频播放器_晨曦之光Wing的博客-CSDN博客,今年做了个Java简易系统监视器,不知道明年会不会有啥子idea了,哈哈哈哈。
此项目历时一周,均在业余时间开发。最开始时萌生了用Java做一个显示电脑CPU使用率和内存使用率的程序,后来一点点查资料、一点点敲代码,一点点想创意、一点点加功能,期间也遇到过艰难时刻,但最后还是挺过来了。现在发现,这个程序其实也不难,在开发过程中也学习到很多知识。感觉开发小程序就是我的乐趣所在,哈哈哈哈。(icon画了我挺久的……)
“山再高,往上攀,总能登顶;路再长,走下去,定能到达”,共勉!