Winform拉窗帘效果关机程序

  • 一:项目结构

  •  二:核心代码
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);
        }
    }
}
  • 三:效果展示
  •  

     

     

posted @ 2025-04-22 16:46  后跳  阅读(13)  评论(0)    收藏  举报