在托盘版里 双击托盘图标 时,弹出一个小窗口,用 WinForms + Chart 控件 绘制最近 N 次的内存使用率曲线图。
完整实现思路
- 主窗体隐藏到托盘(之前的逻辑不变)。
- 内存采集时,把数据保存到一个队列(比如最多存 50 次)。
- 双击托盘图标,弹出
ChartForm
窗口,显示折线图。
代码示例
Form1.cs
(主窗体)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Timers;
namespace MemoryTrayApp
{
public partial class Form1 : Form
{
private NotifyIcon notifyIcon;
private ContextMenuStrip contextMenu;
private System.Timers.Timer timer;
private PerformanceCounter memCounter;
// 保存最近 50 次内存数据
private Queue<int> memoryData = new Queue<int>();
public Form1()
{
InitializeComponent();
InitTray();
InitMonitor();
}
private void InitTray()
{
// 托盘右键菜单
contextMenu = new ContextMenuStrip();
var exitItem = new ToolStripMenuItem("退出");
exitItem.Click += (s, e) => { Application.Exit(); };
contextMenu.Items.Add(exitItem);
// 托盘图标
notifyIcon = new NotifyIcon
{
Icon = SystemIcons.Information,
ContextMenuStrip = contextMenu,
Visible = true,
Text = "内存监控程序"
};
// 双击显示图表
notifyIcon.DoubleClick += (s, e) =>
{
ChartForm chartForm = new ChartForm(memoryData);
chartForm.Show();
};
}
private void InitMonitor()
{
memCounter = new PerformanceCounter("Memory", "% Committed Bytes In Use");
timer = new System.Timers.Timer(3000); // 每 3 秒
timer.Elapsed += Timer_Elapsed;
timer.AutoReset = true;
timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
float memUsage = memCounter.NextValue();
int usage = (int)memUsage;
// 保存数据(最多 50 个点)
if (memoryData.Count >= 50)
memoryData.Dequeue();
memoryData.Enqueue(usage);
// 写日志
string log = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} 内存使用率: {usage}%";
File.AppendAllText(@"C:\MemoryLog.txt", log + Environment.NewLine);
// 更新托盘图标
UpdateTrayIcon(usage);
}
catch (Exception ex)
{
File.AppendAllText(@"C:\MemoryLog.txt", "错误: " + ex.Message + Environment.NewLine);
}
}
private void UpdateTrayIcon(int usage)
{
Bitmap bmp = new Bitmap(32, 32);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Transparent);
// 背景圆圈
g.FillEllipse(Brushes.White, 0, 0, 32, 32);
g.DrawEllipse(Pens.Black, 0, 0, 32, 32);
// 文本(内存使用率)
string text = usage.ToString();
Font font = new Font("Arial", text.Length <= 2 ? 14 : 10, FontStyle.Bold);
SizeF size = g.MeasureString(text, font);
g.DrawString(text, font, Brushes.Red,
(32 - size.Width) / 2, (32 - size.Height) / 2);
}
Icon icon = Icon.FromHandle(bmp.GetHicon());
notifyIcon.Icon = icon;
notifyIcon.Text = $"内存使用率: {usage}%";
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.WindowState = FormWindowState.Minimized;
this.ShowInTaskbar = false;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
notifyIcon.Visible = false;
timer?.Dispose();
memCounter?.Dispose();
base.OnFormClosing(e);
}
}
}
ChartForm.cs
(显示内存曲线的窗体)
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace MemoryTrayApp
{
public class ChartForm : Form
{
private Chart chart;
private Queue<int> memoryData;
public ChartForm(Queue<int> data)
{
this.memoryData = new Queue<int>(data);
this.Text = "内存使用率趋势";
this.Width = 600;
this.Height = 400;
chart = new Chart();
chart.Dock = DockStyle.Fill;
ChartArea area = new ChartArea("Area");
area.AxisX.Title = "时间点";
area.AxisY.Title = "内存使用率 (%)";
area.AxisY.Maximum = 100;
chart.ChartAreas.Add(area);
Series series = new Series("内存使用率");
series.ChartType = SeriesChartType.Line;
series.BorderWidth = 2;
int i = 0;
foreach (var val in memoryData)
{
series.Points.AddXY(i++, val);
}
chart.Series.Add(series);
this.Controls.Add(chart);
}
}
}
🔹效果
- 程序仍然常驻托盘,图标实时显示当前内存百分比。
- 双击托盘图标 → 会弹出一张 内存使用率曲线图,显示最近 50 次数据(大约 2.5 分钟的历史)。
- 曲线每次打开时会根据已有数据绘制。