
using Timer = System.Windows.Forms.Timer;
namespace Shutdown
{
public partial class MainForm : Form
{
// 拖拽状态和高度
private bool dragging = false;
private int initialY;
private int dragHeight = 0;
private Image curtainImage;
// 定时器用于轮询鼠标状态(检测全局鼠标操作)
private Timer timer = new Timer();
// 系统托盘图标
private NotifyIcon notifyIcon;
private PictureBox previewPictureBox;
public MainForm()
{
// 启用双缓冲,减少绘图抖动
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
// 初始化预览窗体
// -------------------------------
// 窗体初始化设置
// -------------------------------
// 全屏、无边框、始终置顶、且不在任务栏中显示
this.FormBorderStyle = FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
this.TopMost = true;
this.ShowInTaskbar = false;
// 使用独特的颜色作为背景,再设置该颜色为透明色(注意图片中不要出现该颜色)
this.BackColor = Color.Magenta;
this.TransparencyKey = Color.Magenta;
// -------------------------------
// 加载自定义窗帘图片(请将“curtain.jpg”放在可执行文件目录,或修改图片路径)
// -------------------------------
try
{
// 获取可执行文件所在路径,然后构造图片路径
string imagePath = System.IO.Path.Combine(Application.StartupPath, "Img", "0d7d8d691e644989b72ddda5f695aca2.jpg");
curtainImage = Image.FromFile(imagePath);
}
catch (Exception ex)
{
MessageBox.Show("加载图片失败: " + ex.Message);
}
// -------------------------------
// NotifyIcon 设置
// -------------------------------
notifyIcon = new NotifyIcon();
notifyIcon.Icon = SystemIcons.Application;
notifyIcon.Text = "Curtain App";
notifyIcon.Visible = true;
// 为托盘图标添加右键菜单,方便退出程序
var contextMenu = new ContextMenuStrip();
contextMenu.Items.Add("设置图片", null, SetImage_Click);
// 调用自定义方法添加“选择图片目录”子菜单
AddImagesToMenuBySubDirectory(contextMenu);
contextMenu.Items.Add("退出", null, (s, e) => Application.Exit());
notifyIcon.ContextMenuStrip = contextMenu;
// -------------------------------
// 定时器设置(轮询间隔 20 毫秒)
// -------------------------------
timer.Interval = 20;
timer.Tick += Timer_Tick;
timer.Start();
// 注册 Paint 事件以实时绘制窗帘效果
this.Paint += MainForm_Paint;
}
/// <summary>
/// 动态加载 Img 文件夹及其子目录下的所有图片,并构造“选择图片目录”子菜单
/// 同时为每个图片菜单项添加鼠标悬停(预览)事件
/// </summary>
private void AddImagesToMenuBySubDirectory(ContextMenuStrip contextMenu)
{
string rootImgDir = Path.Combine(Application.StartupPath, "Img");
if (!Directory.Exists(rootImgDir))
{
MessageBox.Show($"目录 {rootImgDir} 不存在!");
return;
}
// 创建主菜单项:“选择图片目录”
ToolStripMenuItem imageDirMenu = new ToolStripMenuItem("选择图片目录");
// 1. 处理根目录下直接存在的图片
string[] rootImages = Directory.GetFiles(rootImgDir, "*.*")
.Where(s => s.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase)
|| s.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase)
|| s.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
.ToArray();
if (rootImages.Length > 0)
{
ToolStripMenuItem defaultMenuItem = new ToolStripMenuItem("图片目录");
foreach (string imgFile in rootImages)
{
try
{
Image img = Image.FromFile(imgFile);
string fileName = Path.GetFileName(imgFile);
ToolStripMenuItem fileMenuItem = new ToolStripMenuItem(fileName, img);
// 设置点击事件:点击后将预览图设置为窗帘图片
fileMenuItem.Click += (s, e) =>
{
curtainImage = img;
MessageBox.Show($"已设置图片: {fileName}");
};
defaultMenuItem.DropDownItems.Add(fileMenuItem);
}
catch (Exception ex)
{
MessageBox.Show($"加载图片 {Path.GetFileName(imgFile)} 失败: {ex.Message}");
}
}
imageDirMenu.DropDownItems.Add(defaultMenuItem);
}
// 2. 处理 Img 文件夹下的子目录
string[] subDirs = Directory.GetDirectories(rootImgDir);
foreach (string dir in subDirs)
{
string dirName = Path.GetFileName(dir);
ToolStripMenuItem subDirMenu = new ToolStripMenuItem(dirName);
string[] imageFiles = Directory.GetFiles(dir, "*.*")
.Where(s => s.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase)
|| s.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase)
|| s.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
.ToArray();
foreach (string imgFile in imageFiles)
{
try
{
Image img = Image.FromFile(imgFile);
string fileName = Path.GetFileName(imgFile);
ToolStripMenuItem fileMenuItem = new ToolStripMenuItem(fileName, img);
fileMenuItem.Click += (s, e) =>
{
curtainImage = img;
MessageBox.Show($"已设置图片: {fileName}");
};
subDirMenu.DropDownItems.Add(fileMenuItem);
}
catch (Exception ex)
{
MessageBox.Show($"加载图片 {Path.GetFileName(imgFile)} 失败: {ex.Message}");
}
}
if (subDirMenu.DropDownItems.Count > 0)
{
imageDirMenu.DropDownItems.Add(subDirMenu);
}
}
contextMenu.Items.Add(imageDirMenu);
}
private void SetImage_Click(object? sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "图片文件 (*.png;*.jpg;*.jpeg)|*.png;*.jpg;*.jpeg";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
try
{
curtainImage = Image.FromFile(openFileDialog.FileName);
MessageBox.Show("图片设置成功!");
}
catch (Exception ex)
{
MessageBox.Show("加载图片失败: " + ex.Message);
}
}
}
private void Timer_Tick(object sender, EventArgs e)
{
// 当没有处于拖拽状态时,监测是否在屏幕顶部开始拖拽
if (!dragging && Control.MouseButtons == MouseButtons.Left)
{
// 判断全局鼠标位置(例如 Y 坐标小于等于 10 像素可视为顶部)
if (Cursor.Position.Y <= 10)
{
dragging = true;
initialY = Cursor.Position.Y;
}
}
if (dragging)
{
// 实时更新拖拽距离,作为窗帘下拉的高度。
dragHeight = Cursor.Position.Y - initialY;
// 强制重绘窗体,以显示最新的“窗帘”状态
this.Invalidate();
// 如果松开鼠标,则结束拖拽
if (Control.MouseButtons != MouseButtons.Left)
{
dragging = false;
// 如果拖拽接近屏幕底部(可设置一定容差,比如距离底部小于 10 像素)
if (Cursor.Position.Y >= Screen.PrimaryScreen.Bounds.Height - 10)
{
MessageBox.Show("xxxx");
}
// 重置拖拽高度并重绘
dragHeight = 0;
this.Invalidate();
}
}
}
private void MainForm_Paint(object sender, PaintEventArgs e)
{
// 当处于拖拽过程中且图片资源可用时绘制窗帘效果
if (dragHeight > 0 && curtainImage != null)
{
// 绘制区域:屏幕宽度(全屏)和拖拽产生的高度
Rectangle destRect = new Rectangle(0, 0, Screen.PrimaryScreen.Bounds.Width, dragHeight);
Rectangle srcRect = new Rectangle(0, 0, curtainImage.Width, curtainImage.Height);
e.Graphics.DrawImage(curtainImage, destRect, srcRect, GraphicsUnit.Pixel);
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
// 程序退出时释放托盘图标资源
notifyIcon.Dispose();
base.OnFormClosing(e);
}
}
}
- 三:效果展示
-

