C# 桌面时钟(透明窗体、定时提醒、开机启动)

C# 桌面时钟(透明窗体、定时提醒、开机启动)

项目结构

DesktopClock/
├── Properties/
│   ├── AssemblyInfo.cs
│   └── Resources.resx
├── Forms/
│   ├── MainForm.cs
│   ├── MainForm.Designer.cs
│   ├── SettingsForm.cs
│   └── AlarmForm.cs
├── Classes/
│   ├── AlarmManager.cs
│   ├── RegistryHelper.cs
│   └── Win32API.cs
├── Icons/
│   ├── clock.ico
│   └── alarm.ico
└── Program.cs

代码实现

1. 主程序入口(Program.cs)

using System;
using System.Windows.Forms;
using DesktopClock.Properties;

namespace DesktopClock
{
    internal static class Program
    {
        /// <summary>
        /// 应用程序的主入口点
        /// </summary>
        [STAThread]
        static void Main()
        {
            // 处理高DPI设置
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            
            // 检查是否已经运行
            bool createdNew;
            using (var mutex = new System.Threading.Mutex(true, "DesktopClock_UniqueMutex", out createdNew))
            {
                if (createdNew)
                {
                    // 首次运行
                    LoadSettings();
                    
                    // 启动主窗体
                    Application.Run(new MainForm());
                }
                else
                {
                    // 程序已经在运行
                    MessageBox.Show("桌面时钟已经在运行中!", "提示", 
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
        }
        
        private static void LoadSettings()
        {
            // 加载用户设置
            if (Settings.Default.UpgradeRequired)
            {
                Settings.Default.Upgrade();
                Settings.Default.UpgradeRequired = false;
                Settings.Default.Save();
            }
        }
    }
}

2. 主窗体(MainForm.cs)

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
using DesktopClock.Classes;
using DesktopClock.Properties;
using System.Drawing.Drawing2D;
using System.Media;

namespace DesktopClock
{
    public partial class MainForm : Form
    {
        // 私有字段
        private bool isDragging = false;
        private Point dragStartPoint;
        private AlarmManager alarmManager;
        private System.Windows.Forms.Timer updateTimer;
        private System.Windows.Forms.Timer secondTimer;
        private NotifyIcon trayIcon;
        private ContextMenuStrip trayMenu;
        
        // 窗体透明度级别
        private float[] opacityLevels = { 0.3f, 0.5f, 0.7f, 0.9f, 1.0f };
        private int currentOpacityIndex = 3; // 默认0.9
        
        // 时钟样式
        private ClockStyle currentStyle = ClockStyle.Digital;
        private Font clockFont;
        private Color clockColor = Color.Lime;
        private Color shadowColor = Color.Black;
        private bool showShadow = true;
        private bool showSeconds = true;
        private bool showDate = true;
        private bool showWeek = true;
        
        // 时钟位置
        private FormPosition savedPosition = new FormPosition();
        
        public MainForm()
        {
            InitializeComponent();
            InitializeComponents();
            LoadSettings();
            InitializeTrayIcon();
            
            // 启动时钟
            StartClocks();
        }
        
        private void InitializeComponents()
        {
            // 设置窗体属性
            this.FormBorderStyle = FormBorderStyle.None;
            this.BackColor = Color.Black;
            this.TransparencyKey = Color.Black;
            this.TopMost = true;
            this.ShowInTaskbar = false;
            this.StartPosition = FormStartPosition.Manual;
            
            // 设置窗体大小
            this.ClientSize = new Size(300, 150);
            
            // 创建定时器
            updateTimer = new System.Windows.Forms.Timer();
            updateTimer.Interval = 1000; // 1秒更新
            updateTimer.Tick += UpdateTimer_Tick;
            
            secondTimer = new System.Windows.Forms.Timer();
            secondTimer.Interval = 100; // 0.1秒更新(用于秒动画)
            secondTimer.Tick += SecondTimer_Tick;
            
            // 创建闹钟管理器
            alarmManager = new AlarmManager();
            alarmManager.AlarmTriggered += AlarmManager_AlarmTriggered;
        }
        
        private void LoadSettings()
        {
            // 加载窗体位置
            savedPosition = Settings.Default.FormPosition;
            if (savedPosition != null && savedPosition.IsValid())
            {
                this.Location = savedPosition.Location;
                this.Size = savedPosition.Size;
            }
            else
            {
                // 默认位置:屏幕右上角
                this.Location = new Point(
                    Screen.PrimaryScreen.WorkingArea.Right - this.Width - 20,
                    20
                );
            }
            
            // 加载透明度设置
            currentOpacityIndex = Settings.Default.OpacityLevel;
            if (currentOpacityIndex >= 0 && currentOpacityIndex < opacityLevels.Length)
            {
                this.Opacity = opacityLevels[currentOpacityIndex];
            }
            else
            {
                this.Opacity = 0.9f;
            }
            
            // 加载时钟样式
            currentStyle = (ClockStyle)Settings.Default.ClockStyle;
            showSeconds = Settings.Default.ShowSeconds;
            showDate = Settings.Default.ShowDate;
            showWeek = Settings.Default.ShowWeek;
            clockColor = Settings.Default.ClockColor;
            
            // 加载字体
            try
            {
                clockFont = new Font(Settings.Default.FontName, Settings.Default.FontSize);
            }
            catch
            {
                clockFont = new Font("Arial", 24);
            }
            
            // 加载开机启动设置
            UpdateStartupMenuItem();
        }
        
        private void SaveSettings()
        {
            Settings.Default.FormPosition = new FormPosition(this.Location, this.Size);
            Settings.Default.OpacityLevel = currentOpacityIndex;
            Settings.Default.ClockStyle = (int)currentStyle;
            Settings.Default.ShowSeconds = showSeconds;
            Settings.Default.ShowDate = showDate;
            Settings.Default.ShowWeek = showWeek;
            Settings.Default.ClockColor = clockColor;
            Settings.Default.FontName = clockFont.Name;
            Settings.Default.FontSize = clockFont.Size;
            Settings.Default.Save();
        }
        
        private void InitializeTrayIcon()
        {
            // 创建托盘图标
            trayIcon = new NotifyIcon();
            trayIcon.Icon = Resources.clock_icon;
            trayIcon.Text = "桌面时钟";
            trayIcon.Visible = true;
            trayIcon.MouseClick += TrayIcon_MouseClick;
            
            // 创建托盘菜单
            trayMenu = new ContextMenuStrip();
            
            // 添加菜单项
            var styleMenu = new ToolStripMenuItem("时钟样式");
            styleMenu.DropDownItems.Add("数字时钟", null, (s, e) => ChangeClockStyle(ClockStyle.Digital));
            styleMenu.DropDownItems.Add("模拟时钟", null, (s, e) => ChangeClockStyle(ClockStyle.Analog));
            styleMenu.DropDownItems.Add("简约时钟", null, (s, e) => ChangeClockStyle(ClockStyle.Minimal));
            
            trayMenu.Items.Add(styleMenu);
            trayMenu.Items.Add(new ToolStripSeparator());
            
            trayMenu.Items.Add("设置透明度", null, (s, e) => ChangeOpacity());
            trayMenu.Items.Add("更改颜色...", null, (s, e) => ChangeColor());
            trayMenu.Items.Add(new ToolStripSeparator());
            
            trayMenu.Items.Add("显示/隐藏秒针", null, (s, e) => ToggleShowSeconds());
            trayMenu.Items.Add("显示/隐藏日期", null, (s, e) => ToggleShowDate());
            trayMenu.Items.Add("显示/隐藏星期", null, (s, e) => ToggleShowWeek());
            trayMenu.Items.Add(new ToolStripSeparator());
            
            // 闹钟管理
            var alarmMenu = new ToolStripMenuItem("闹钟管理");
            alarmMenu.DropDownItems.Add("添加闹钟...", null, (s, e) => AddAlarm());
            alarmMenu.DropDownItems.Add("查看闹钟列表", null, (s, e) => ShowAlarms());
            trayMenu.Items.Add(alarmMenu);
            trayMenu.Items.Add(new ToolStripSeparator());
            
            // 开机启动
            startupMenuItem = new ToolStripMenuItem("开机启动");
            startupMenuItem.Click += StartupMenuItem_Click;
            trayMenu.Items.Add(startupMenuItem);
            
            trayMenu.Items.Add(new ToolStripSeparator());
            trayMenu.Items.Add("退出", null, (s, e) => ExitApplication());
            
            trayIcon.ContextMenuStrip = trayMenu;
        }
        
        private ToolStripMenuItem startupMenuItem;
        
        private void UpdateStartupMenuItem()
        {
            bool isStartup = RegistryHelper.IsAppSetToStartup("DesktopClock");
            startupMenuItem.Checked = isStartup;
            startupMenuItem.Text = isStartup ? "开机启动 ✓" : "开机启动";
        }
        
        private void StartClocks()
        {
            updateTimer.Start();
            secondTimer.Start();
        }
        
        private void UpdateTimer_Tick(object sender, EventArgs e)
        {
            // 检查闹钟
            alarmManager.CheckAlarms();
            
            // 强制重绘
            this.Invalidate();
        }
        
        private void SecondTimer_Tick(object sender, EventArgs e)
        {
            // 只用于模拟时钟的秒针动画
            if (currentStyle == ClockStyle.Analog)
            {
                this.Invalidate();
            }
        }
        
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            
            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
            
            // 根据当前样式绘制时钟
            switch (currentStyle)
            {
                case ClockStyle.Digital:
                    DrawDigitalClock(g);
                    break;
                case ClockStyle.Analog:
                    DrawAnalogClock(g);
                    break;
                case ClockStyle.Minimal:
                    DrawMinimalClock(g);
                    break;
            }
        }
        
        private void DrawDigitalClock(Graphics g)
        {
            DateTime now = DateTime.Now;
            
            // 准备文本
            string timeText = now.ToString(showSeconds ? "HH:mm:ss" : "HH:mm");
            string dateText = now.ToString("yyyy-MM-dd");
            string weekText = GetChineseWeekDay(now.DayOfWeek);
            
            // 计算文本大小
            SizeF timeSize = g.MeasureString(timeText, clockFont);
            SizeF dateSize = showDate ? g.MeasureString(dateText, clockFont) : SizeF.Empty;
            SizeF weekSize = showWeek ? g.MeasureString(weekText, clockFont) : SizeF.Empty;
            
            // 计算总高度
            float totalHeight = timeSize.Height;
            if (showDate) totalHeight += dateSize.Height + 5;
            if (showWeek) totalHeight += weekSize.Height + 5;
            
            // 计算开始位置(垂直居中)
            float startY = (this.ClientSize.Height - totalHeight) / 2;
            float currentY = startY;
            
            // 绘制时间(带阴影效果)
            if (showShadow)
            {
                DrawTextWithShadow(g, timeText, clockFont, 
                    new PointF((this.ClientSize.Width - timeSize.Width) / 2, currentY),
                    clockColor, shadowColor, 2);
            }
            else
            {
                using (Brush brush = new SolidBrush(clockColor))
                {
                    g.DrawString(timeText, clockFont, brush,
                        (this.ClientSize.Width - timeSize.Width) / 2, currentY);
                }
            }
            
            currentY += timeSize.Height + 5;
            
            // 绘制日期
            if (showDate)
            {
                if (showShadow)
                {
                    DrawTextWithShadow(g, dateText, clockFont,
                        new PointF((this.ClientSize.Width - dateSize.Width) / 2, currentY),
                        clockColor, shadowColor, 2);
                }
                else
                {
                    using (Brush brush = new SolidBrush(clockColor))
                    {
                        g.DrawString(dateText, clockFont, brush,
                            (this.ClientSize.Width - dateSize.Width) / 2, currentY);
                    }
                }
                currentY += dateSize.Height + 5;
            }
            
            // 绘制星期
            if (showWeek)
            {
                if (showShadow)
                {
                    DrawTextWithShadow(g, weekText, clockFont,
                        new PointF((this.ClientSize.Width - weekSize.Width) / 2, currentY),
                        clockColor, shadowColor, 2);
                }
                else
                {
                    using (Brush brush = new SolidBrush(clockColor))
                    {
                        g.DrawString(weekText, clockFont, brush,
                            (this.ClientSize.Width - weekSize.Width) / 2, currentY);
                    }
                }
            }
        }
        
        private void DrawAnalogClock(Graphics g)
        {
            DateTime now = DateTime.Now;
            int centerX = this.ClientSize.Width / 2;
            int centerY = this.ClientSize.Height / 2;
            int radius = Math.Min(centerX, centerY) - 20;
            
            // 绘制表盘
            using (Pen pen = new Pen(clockColor, 2))
            {
                g.DrawEllipse(pen, centerX - radius, centerY - radius, 
                    radius * 2, radius * 2);
            }
            
            // 绘制刻度
            for (int i = 0; i < 60; i++)
            {
                double angle = i * 6 * Math.PI / 180;
                int length = (i % 5 == 0) ? 10 : 5;
                int width = (i % 5 == 0) ? 2 : 1;
                
                int x1 = (int)(centerX + (radius - 5) * Math.Sin(angle));
                int y1 = (int)(centerY - (radius - 5) * Math.Cos(angle));
                int x2 = (int)(centerX + (radius - 5 - length) * Math.Sin(angle));
                int y2 = (int)(centerY - (radius - 5 - length) * Math.Cos(angle));
                
                using (Pen pen = new Pen(clockColor, width))
                {
                    g.DrawLine(pen, x1, y1, x2, y2);
                }
            }
            
            // 绘制数字
            for (int i = 1; i <= 12; i++)
            {
                double angle = (i * 30 - 90) * Math.PI / 180;
                int numberRadius = radius - 25;
                int x = (int)(centerX + numberRadius * Math.Cos(angle));
                int y = (int)(centerY + numberRadius * Math.Sin(angle));
                
                string num = i.ToString();
                SizeF size = g.MeasureString(num, new Font(clockFont.FontFamily, 12));
                
                using (Brush brush = new SolidBrush(clockColor))
                {
                    g.DrawString(num, new Font(clockFont.FontFamily, 12), brush,
                        x - size.Width / 2, y - size.Height / 2);
                }
            }
            
            // 绘制时针
            double hourAngle = (now.Hour % 12 + now.Minute / 60.0) * 30 * Math.PI / 180;
            int hourHandLength = (int)(radius * 0.5);
            int hourX = (int)(centerX + hourHandLength * Math.Sin(hourAngle));
            int hourY = (int)(centerY - hourHandLength * Math.Cos(hourAngle));
            
            using (Pen pen = new Pen(clockColor, 4))
            {
                g.DrawLine(pen, centerX, centerY, hourX, hourY);
            }
            
            // 绘制分针
            double minuteAngle = (now.Minute + now.Second / 60.0) * 6 * Math.PI / 180;
            int minuteHandLength = (int)(radius * 0.7);
            int minuteX = (int)(centerX + minuteHandLength * Math.Sin(minuteAngle));
            int minuteY = (int)(centerY - minuteHandLength * Math.Cos(minuteAngle));
            
            using (Pen pen = new Pen(clockColor, 3))
            {
                g.DrawLine(pen, centerX, centerY, minuteX, minuteY);
            }
            
            // 绘制秒针(如果显示)
            if (showSeconds)
            {
                double secondAngle = (now.Second + now.Millisecond / 1000.0) * 6 * Math.PI / 180;
                int secondHandLength = (int)(radius * 0.8);
                int secondX = (int)(centerX + secondHandLength * Math.Sin(secondAngle));
                int secondY = (int)(centerY - secondHandLength * Math.Cos(secondAngle));
                
                using (Pen pen = new Pen(Color.Red, 1))
                {
                    g.DrawLine(pen, centerX, centerY, secondX, secondY);
                }
                
                // 绘制秒针尖端
                using (Brush brush = new SolidBrush(Color.Red))
                {
                    g.FillEllipse(brush, secondX - 3, secondY - 3, 6, 6);
                }
            }
            
            // 绘制中心点
            using (Brush brush = new SolidBrush(clockColor))
            {
                g.FillEllipse(brush, centerX - 4, centerY - 4, 8, 8);
            }
            
            // 绘制日期(如果显示)
            if (showDate)
            {
                string dateText = now.ToString("MM/dd");
                SizeF size = g.MeasureString(dateText, new Font(clockFont.FontFamily, 10));
                
                using (Brush brush = new SolidBrush(clockColor))
                {
                    g.DrawString(dateText, new Font(clockFont.FontFamily, 10), brush,
                        centerX - size.Width / 2, centerY + radius / 2);
                }
            }
        }
        
        private void DrawMinimalClock(Graphics g)
        {
            DateTime now = DateTime.Now;
            
            // 只显示小时和分钟,使用大字体
            string timeText = now.ToString("HH:mm");
            using (Font largeFont = new Font(clockFont.FontFamily, 36, FontStyle.Bold))
            {
                SizeF timeSize = g.MeasureString(timeText, largeFont);
                
                if (showShadow)
                {
                    DrawTextWithShadow(g, timeText, largeFont,
                        new PointF((this.ClientSize.Width - timeSize.Width) / 2, 20),
                        clockColor, shadowColor, 3);
                }
                else
                {
                    using (Brush brush = new SolidBrush(clockColor))
                    {
                        g.DrawString(timeText, largeFont, brush,
                            (this.ClientSize.Width - timeSize.Width) / 2, 20);
                    }
                }
            }
        }
        
        private void DrawTextWithShadow(Graphics g, string text, Font font, 
            PointF location, Color textColor, Color shadowColor, int shadowOffset)
        {
            // 绘制阴影
            using (Brush shadowBrush = new SolidBrush(shadowColor))
            {
                g.DrawString(text, font, shadowBrush,
                    location.X + shadowOffset, location.Y + shadowOffset);
            }
            
            // 绘制文本
            using (Brush textBrush = new SolidBrush(textColor))
            {
                g.DrawString(text, font, textBrush, location);
            }
        }
        
        private string GetChineseWeekDay(DayOfWeek day)
        {
            switch (day)
            {
                case DayOfWeek.Sunday: return "星期日";
                case DayOfWeek.Monday: return "星期一";
                case DayOfWeek.Tuesday: return "星期二";
                case DayOfWeek.Wednesday: return "星期三";
                case DayOfWeek.Thursday: return "星期四";
                case DayOfWeek.Friday: return "星期五";
                case DayOfWeek.Saturday: return "星期六";
                default: return "";
            }
        }
        
        // 鼠标事件处理
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            
            if (e.Button == MouseButtons.Left)
            {
                isDragging = true;
                dragStartPoint = new Point(e.X, e.Y);
                this.Cursor = Cursors.SizeAll;
            }
            else if (e.Button == MouseButtons.Right)
            {
                // 显示上下文菜单
                trayMenu.Show(this, e.Location);
            }
        }
        
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            
            if (isDragging)
            {
                Point newLocation = this.Location;
                newLocation.Offset(e.X - dragStartPoint.X, e.Y - dragStartPoint.Y);
                this.Location = newLocation;
            }
        }
        
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            
            if (e.Button == MouseButtons.Left)
            {
                isDragging = false;
                this.Cursor = Cursors.Default;
                
                // 保存新位置
                SaveSettings();
            }
        }
        
        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            base.OnMouseDoubleClick(e);
            
            if (e.Button == MouseButtons.Left)
            {
                // 双击切换样式
                currentStyle = (ClockStyle)(((int)currentStyle + 1) % 3);
                this.Invalidate();
                SaveSettings();
            }
        }
        
        // 闹钟事件
        private void AlarmManager_AlarmTriggered(object sender, AlarmEventArgs e)
        {
            // 在主线程中显示提醒
            this.Invoke(new Action(() =>
            {
                ShowAlarmNotification(e.Alarm);
            }));
        }
        
        private void ShowAlarmNotification(Alarm alarm)
        {
            // 播放提示音
            SystemSounds.Exclamation.Play();
            
            // 显示通知
            if (trayIcon.Visible)
            {
                trayIcon.ShowBalloonTip(5000, "闹钟提醒", 
                    $"{alarm.Name}\n{alarm.Time:HH:mm}", ToolTipIcon.Info);
            }
            
            // 显示提醒窗口
            using (var alarmForm = new AlarmForm(alarm))
            {
                alarmForm.ShowDialog();
            }
        }
        
        // 菜单功能
        private void ChangeClockStyle(ClockStyle style)
        {
            currentStyle = style;
            this.Invalidate();
            SaveSettings();
        }
        
        private void ChangeOpacity()
        {
            currentOpacityIndex = (currentOpacityIndex + 1) % opacityLevels.Length;
            this.Opacity = opacityLevels[currentOpacityIndex];
            SaveSettings();
        }
        
        private void ChangeColor()
        {
            using (ColorDialog dialog = new ColorDialog())
            {
                dialog.Color = clockColor;
                dialog.FullOpen = true;
                
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    clockColor = dialog.Color;
                    this.Invalidate();
                    SaveSettings();
                }
            }
        }
        
        private void ToggleShowSeconds()
        {
            showSeconds = !showSeconds;
            SaveSettings();
            this.Invalidate();
        }
        
        private void ToggleShowDate()
        {
            showDate = !showDate;
            SaveSettings();
            this.Invalidate();
        }
        
        private void ToggleShowWeek()
        {
            showWeek = !showWeek;
            SaveSettings();
            this.Invalidate();
        }
        
        private void AddAlarm()
        {
            using (var alarmForm = new AlarmForm())
            {
                if (alarmForm.ShowDialog() == DialogResult.OK)
                {
                    alarmManager.AddAlarm(alarmForm.Alarm);
                    SaveAlarms();
                }
            }
        }
        
        private void ShowAlarms()
        {
            using (var alarmsForm = new AlarmsForm(alarmManager))
            {
                alarmsForm.ShowDialog();
                SaveAlarms();
            }
        }
        
        private void StartupMenuItem_Click(object sender, EventArgs e)
        {
            bool isStartup = RegistryHelper.IsAppSetToStartup("DesktopClock");
            
            if (isStartup)
            {
                RegistryHelper.RemoveFromStartup("DesktopClock");
            }
            else
            {
                RegistryHelper.SetAppToStartup("DesktopClock", Application.ExecutablePath);
            }
            
            UpdateStartupMenuItem();
        }
        
        private void SaveAlarms()
        {
            Settings.Default.Alarms = alarmManager.SerializeAlarms();
            Settings.Default.Save();
        }
        
        private void TrayIcon_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                this.Visible = !this.Visible;
            }
        }
        
        private void ExitApplication()
        {
            SaveSettings();
            SaveAlarms();
            
            updateTimer.Stop();
            secondTimer.Stop();
            
            trayIcon.Visible = false;
            Application.Exit();
        }
        
        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = true;
                this.Hide();
                trayIcon.ShowBalloonTip(1000, "桌面时钟", "时钟已隐藏到系统托盘", ToolTipIcon.Info);
            }
            base.OnFormClosing(e);
        }
        
        // 时钟样式枚举
        private enum ClockStyle
        {
            Digital = 0,
            Analog = 1,
            Minimal = 2
        }
    }
    
    // 窗体位置序列化类
    [Serializable]
    public class FormPosition
    {
        public Point Location { get; set; }
        public Size Size { get; set; }
        
        public FormPosition() { }
        
        public FormPosition(Point location, Size size)
        {
            Location = location;
            Size = size;
        }
        
        public bool IsValid()
        {
            return Location.X >= 0 && Location.Y >= 0 && 
                   Size.Width > 0 && Size.Height > 0;
        }
    }
}

3. 主窗体设计器(MainForm.Designer.cs)

namespace DesktopClock
{
    partial class MainForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(300, 150);
            this.Name = "MainForm";
            this.Text = "桌面时钟";
        }

        #endregion
    }
}

4. 闹钟管理器(AlarmManager.cs)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using System.IO;

namespace DesktopClock.Classes
{
    public class AlarmManager
    {
        private List<Alarm> alarms = new List<Alarm>();
        private System.Windows.Forms.Timer checkTimer;
        
        public event EventHandler<AlarmEventArgs> AlarmTriggered;
        
        public AlarmManager()
        {
            checkTimer = new System.Windows.Forms.Timer();
            checkTimer.Interval = 1000; // 每秒检查一次
            checkTimer.Tick += CheckTimer_Tick;
            checkTimer.Start();
        }
        
        public void AddAlarm(Alarm alarm)
        {
            alarms.Add(alarm);
        }
        
        public void RemoveAlarm(Alarm alarm)
        {
            alarms.Remove(alarm);
        }
        
        public List<Alarm> GetAlarms()
        {
            return new List<Alarm>(alarms);
        }
        
        public void CheckAlarms()
        {
            DateTime now = DateTime.Now;
            
            foreach (var alarm in alarms.Where(a => a.IsEnabled))
            {
                if (alarm.ShouldTrigger(now))
                {
                    OnAlarmTriggered(alarm);
                    
                    if (!alarm.Repeat)
                    {
                        alarm.IsEnabled = false;
                    }
                }
            }
        }
        
        private void CheckTimer_Tick(object sender, EventArgs e)
        {
            CheckAlarms();
        }
        
        protected virtual void OnAlarmTriggered(Alarm alarm)
        {
            AlarmTriggered?.Invoke(this, new AlarmEventArgs(alarm));
        }
        
        public string SerializeAlarms()
        {
            try
            {
                var serializer = new XmlSerializer(typeof(List<Alarm>));
                using (var writer = new StringWriter())
                {
                    serializer.Serialize(writer, alarms);
                    return writer.ToString();
                }
            }
            catch
            {
                return string.Empty;
            }
        }
        
        public void DeserializeAlarms(string xml)
        {
            try
            {
                if (!string.IsNullOrEmpty(xml))
                {
                    var serializer = new XmlSerializer(typeof(List<Alarm>));
                    using (var reader = new StringReader(xml))
                    {
                        var deserialized = (List<Alarm>)serializer.Deserialize(reader);
                        alarms = deserialized ?? new List<Alarm>();
                    }
                }
            }
            catch
            {
                alarms = new List<Alarm>();
            }
        }
    }
    
    [Serializable]
    public class Alarm
    {
        public string Name { get; set; }
        public DateTime Time { get; set; }
        public bool IsEnabled { get; set; }
        public bool Repeat { get; set; }
        public DayOfWeek[] RepeatDays { get; set; }
        public DateTime LastTriggered { get; set; }
        
        public Alarm()
        {
            Name = "新闹钟";
            Time = DateTime.Now;
            IsEnabled = true;
            Repeat = false;
            RepeatDays = new DayOfWeek[0];
        }
        
        public bool ShouldTrigger(DateTime currentTime)
        {
            if (!IsEnabled) return false;
            
            // 检查是否在触发时间范围内(允许±1分钟)
            if (Math.Abs((currentTime - Time).TotalMinutes) <= 1)
            {
                // 防止重复触发(同一分钟内只触发一次)
                if ((currentTime - LastTriggered).TotalMinutes < 1)
                    return false;
                
                if (Repeat)
                {
                    if (RepeatDays.Length == 0 || RepeatDays.Contains(currentTime.DayOfWeek))
                    {
                        LastTriggered = currentTime;
                        return true;
                    }
                }
                else
                {
                    LastTriggered = currentTime;
                    return true;
                }
            }
            
            return false;
        }
    }
    
    public class AlarmEventArgs : EventArgs
    {
        public Alarm Alarm { get; }
        
        public AlarmEventArgs(Alarm alarm)
        {
            Alarm = alarm;
        }
    }
}

5. 闹钟设置窗体(AlarmForm.cs)

using System;
using System.Windows.Forms;
using DesktopClock.Classes;

namespace DesktopClock
{
    public partial class AlarmForm : Form
    {
        public Alarm Alarm { get; private set; }
        
        private CheckBox[] dayCheckboxes = new CheckBox[7];
        private string[] dayNames = { "周一", "周二", "周三", "周四", "周五", "周六", "周日" };
        
        public AlarmForm() : this(null) { }
        
        public AlarmForm(Alarm existingAlarm)
        {
            InitializeComponent();
            InitializeDayCheckboxes();
            
            if (existingAlarm != null)
            {
                Alarm = existingAlarm;
                LoadAlarmData();
            }
            else
            {
                Alarm = new Alarm();
                timePicker.Value = DateTime.Now.AddMinutes(1);
            }
        }
        
        private void InitializeComponent()
        {
            this.Text = "设置闹钟";
            this.Size = new System.Drawing.Size(350, 300);
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.StartPosition = FormStartPosition.CenterScreen;
            
            // 名称标签
            var nameLabel = new Label
            {
                Text = "闹钟名称:",
                Location = new System.Drawing.Point(20, 20),
                Size = new System.Drawing.Size(80, 20)
            };
            
            // 名称文本框
            var nameTextBox = new TextBox
            {
                Location = new System.Drawing.Point(100, 20),
                Size = new System.Drawing.Size(200, 20)
            };
            nameTextBox.TextChanged += (s, e) => Alarm.Name = nameTextBox.Text;
            
            // 时间标签
            var timeLabel = new Label
            {
                Text = "提醒时间:",
                Location = new System.Drawing.Point(20, 50),
                Size = new System.Drawing.Size(80, 20)
            };
            
            // 时间选择器
            timePicker = new DateTimePicker
            {
                Location = new System.Drawing.Point(100, 50),
                Size = new System.Drawing.Size(100, 20),
                Format = DateTimePickerFormat.Time,
                ShowUpDown = true
            };
            timePicker.ValueChanged += (s, e) => Alarm.Time = timePicker.Value;
            
            // 重复复选框
            var repeatCheckBox = new CheckBox
            {
                Text = "重复",
                Location = new System.Drawing.Point(20, 80),
                Size = new System.Drawing.Size(60, 20)
            };
            repeatCheckBox.CheckedChanged += (s, e) =>
            {
                Alarm.Repeat = repeatCheckBox.Checked;
                panelDays.Enabled = repeatCheckBox.Checked;
            };
            
            // 重复日期面板
            panelDays = new Panel
            {
                Location = new System.Drawing.Point(20, 110),
                Size = new System.Drawing.Size(300, 60),
                Enabled = false
            };
            
            // 启用复选框
            var enabledCheckBox = new CheckBox
            {
                Text = "启用闹钟",
                Location = new System.Drawing.Point(20, 180),
                Size = new System.Drawing.Size(100, 20),
                Checked = true
            };
            enabledCheckBox.CheckedChanged += (s, e) => Alarm.IsEnabled = enabledCheckBox.Checked;
            
            // 按钮
            var okButton = new Button
            {
                Text = "确定",
                Location = new System.Drawing.Point(150, 220),
                Size = new System.Drawing.Size(80, 30),
                DialogResult = DialogResult.OK
            };
            
            var cancelButton = new Button
            {
                Text = "取消",
                Location = new System.Drawing.Point(240, 220),
                Size = new System.Drawing.Size(80, 30),
                DialogResult = DialogResult.Cancel
            };
            
            // 添加控件
            this.Controls.AddRange(new Control[]
            {
                nameLabel, nameTextBox, timeLabel, timePicker,
                repeatCheckBox, panelDays, enabledCheckBox,
                okButton, cancelButton
            });
            
            this.AcceptButton = okButton;
            this.CancelButton = cancelButton;
        }
        
        private void InitializeDayCheckboxes()
        {
            for (int i = 0; i < 7; i++)
            {
                dayCheckboxes[i] = new CheckBox
                {
                    Text = dayNames[i],
                    Location = new System.Drawing.Point(i * 40, 10),
                    Size = new System.Drawing.Size(40, 20),
                    Tag = (DayOfWeek)((i + 1) % 7) // 周日是0,调整为最后
                };
                
                int index = i; // 捕获变量
                dayCheckboxes[i].CheckedChanged += (s, e) =>
                {
                    UpdateRepeatDays();
                };
                
                panelDays.Controls.Add(dayCheckboxes[i]);
            }
        }
        
        private void LoadAlarmData()
        {
            // 查找并设置控件
            foreach (Control ctrl in this.Controls)
            {
                if (ctrl is TextBox && ctrl.Name.Contains("name"))
                {
                    ((TextBox)ctrl).Text = Alarm.Name;
                }
                else if (ctrl is DateTimePicker)
                {
                    ((DateTimePicker)ctrl).Value = Alarm.Time;
                }
                else if (ctrl is CheckBox checkBox)
                {
                    if (checkBox.Text == "重复")
                    {
                        checkBox.Checked = Alarm.Repeat;
                    }
                    else if (checkBox.Text == "启用闹钟")
                    {
                        checkBox.Checked = Alarm.IsEnabled;
                    }
                }
            }
            
            // 设置重复日期
            if (Alarm.RepeatDays != null)
            {
                foreach (var checkbox in dayCheckboxes)
                {
                    checkbox.Checked = Alarm.RepeatDays.Contains((DayOfWeek)checkbox.Tag);
                }
            }
        }
        
        private void UpdateRepeatDays()
        {
            var selectedDays = new List<DayOfWeek>();
            foreach (var checkbox in dayCheckboxes)
            {
                if (checkbox.Checked)
                {
                    selectedDays.Add((DayOfWeek)checkbox.Tag);
                }
            }
            Alarm.RepeatDays = selectedDays.ToArray();
        }
        
        private DateTimePicker timePicker;
        private Panel panelDays;
    }
}

参考代码 C# 桌面时钟(透明窗体,定时提醒,开机启动) www.youwenfan.com/contentcnt/49380.html

6. 闹钟列表窗体(AlarmsForm.cs)

using System;
using System.Windows.Forms;
using DesktopClock.Classes;
using System.Drawing;

namespace DesktopClock
{
    public partial class AlarmsForm : Form
    {
        private AlarmManager alarmManager;
        private ListView listView;
        
        public AlarmsForm(AlarmManager manager)
        {
            alarmManager = manager;
            InitializeComponent();
            LoadAlarms();
        }
        
        private void InitializeComponent()
        {
            this.Text = "闹钟列表";
            this.Size = new Size(500, 300);
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.StartPosition = FormStartPosition.CenterScreen;
            
            // 列表视图
            listView = new ListView
            {
                View = View.Details,
                FullRowSelect = true,
                GridLines = true,
                Location = new Point(10, 10),
                Size = new Size(460, 200)
            };
            
            // 添加列
            listView.Columns.Add("名称", 150);
            listView.Columns.Add("时间", 100);
            listView.Columns.Add("重复", 80);
            listView.Columns.Add("状态", 80);
            listView.Columns.Add("重复日期", 150);
            
            // 按钮
            var addButton = new Button
            {
                Text = "添加",
                Location = new Point(10, 220),
                Size = new Size(80, 30)
            };
            addButton.Click += AddButton_Click;
            
            var editButton = new Button
            {
                Text = "编辑",
                Location = new Point(100, 220),
                Size = new Size(80, 30)
            };
            editButton.Click += EditButton_Click;
            
            var deleteButton = new Button
            {
                Text = "删除",
                Location = new Point(190, 220),
                Size = new Size(80, 30)
            };
            deleteButton.Click += DeleteButton_Click;
            
            var toggleButton = new Button
            {
                Text = "启用/禁用",
                Location = new Point(280, 220),
                Size = new Size(80, 30)
            };
            toggleButton.Click += ToggleButton_Click;
            
            var closeButton = new Button
            {
                Text = "关闭",
                Location = new Point(370, 220),
                Size = new Size(80, 30),
                DialogResult = DialogResult.Cancel
            };
            
            this.Controls.AddRange(new Control[]
            {
                listView, addButton, editButton,
                deleteButton, toggleButton, closeButton
            });
            
            this.CancelButton = closeButton;
        }
        
        private void LoadAlarms()
        {
            listView.Items.Clear();
            
            foreach (var alarm in alarmManager.GetAlarms())
            {
                var item = new ListViewItem(alarm.Name);
                item.SubItems.Add(alarm.Time.ToString("HH:mm"));
                item.SubItems.Add(alarm.Repeat ? "是" : "否");
                item.SubItems.Add(alarm.IsEnabled ? "启用" : "禁用");
                
                string daysText = "";
                if (alarm.RepeatDays != null && alarm.RepeatDays.Length > 0)
                {
                    foreach (var day in alarm.RepeatDays)
                    {
                        daysText += GetDayAbbreviation(day) + " ";
                    }
                }
                item.SubItems.Add(daysText);
                item.Tag = alarm;
                
                listView.Items.Add(item);
            }
        }
        
        private string GetDayAbbreviation(DayOfWeek day)
        {
            switch (day)
            {
                case DayOfWeek.Sunday: return "日";
                case DayOfWeek.Monday: return "一";
                case DayOfWeek.Tuesday: return "二";
                case DayOfWeek.Wednesday: return "三";
                case DayOfWeek.Thursday: return "四";
                case DayOfWeek.Friday: return "五";
                case DayOfWeek.Saturday: return "六";
                default: return "";
            }
        }
        
        private void AddButton_Click(object sender, EventArgs e)
        {
            using (var alarmForm = new AlarmForm())
            {
                if (alarmForm.ShowDialog() == DialogResult.OK)
                {
                    alarmManager.AddAlarm(alarmForm.Alarm);
                    LoadAlarms();
                }
            }
        }
        
        private void EditButton_Click(object sender, EventArgs e)
        {
            if (listView.SelectedItems.Count > 0)
            {
                var alarm = (Alarm)listView.SelectedItems[0].Tag;
                using (var alarmForm = new AlarmForm(alarm))
                {
                    if (alarmForm.ShowDialog() == DialogResult.OK)
                    {
                        LoadAlarms();
                    }
                }
            }
        }
        
        private void DeleteButton_Click(object sender, EventArgs e)
        {
            if (listView.SelectedItems.Count > 0)
            {
                if (MessageBox.Show("确定要删除这个闹钟吗?", "确认删除", 
                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    var alarm = (Alarm)listView.SelectedItems[0].Tag;
                    alarmManager.RemoveAlarm(alarm);
                    LoadAlarms();
                }
            }
        }
        
        private void ToggleButton_Click(object sender, EventArgs e)
        {
            if (listView.SelectedItems.Count > 0)
            {
                var alarm = (Alarm)listView.SelectedItems[0].Tag;
                alarm.IsEnabled = !alarm.IsEnabled;
                LoadAlarms();
            }
        }
    }
}

7. 注册表助手(RegistryHelper.cs)

using System;
using Microsoft.Win32;
using System.Security;
using System.Windows.Forms;

namespace DesktopClock.Classes
{
    public static class RegistryHelper
    {
        private const string RUN_REGISTRY_KEY = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
        
        public static bool SetAppToStartup(string appName, string appPath)
        {
            try
            {
                using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RUN_REGISTRY_KEY, true))
                {
                    if (key != null)
                    {
                        key.SetValue(appName, $"\"{appPath}\"");
                        return true;
                    }
                }
            }
            catch (SecurityException ex)
            {
                MessageBox.Show($"权限不足: {ex.Message}", "错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (UnauthorizedAccessException ex)
            {
                MessageBox.Show($"访问被拒绝: {ex.Message}", "错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"设置失败: {ex.Message}", "错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            
            return false;
        }
        
        public static bool RemoveFromStartup(string appName)
        {
            try
            {
                using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RUN_REGISTRY_KEY, true))
                {
                    if (key != null)
                    {
                        key.DeleteValue(appName, false);
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"删除失败: {ex.Message}", "错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            
            return false;
        }
        
        public static bool IsAppSetToStartup(string appName)
        {
            try
            {
                using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RUN_REGISTRY_KEY, false))
                {
                    if (key != null)
                    {
                        return key.GetValue(appName) != null;
                    }
                }
            }
            catch
            {
                // 忽略错误
            }
            
            return false;
        }
        
        public static string GetStartupAppPath(string appName)
        {
            try
            {
                using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RUN_REGISTRY_KEY, false))
                {
                    if (key != null)
                    {
                        return key.GetValue(appName)?.ToString();
                    }
                }
            }
            catch
            {
                // 忽略错误
            }
            
            return null;
        }
    }
}

8. 设置类(Settings.cs)

using System;
using System.Drawing;
using System.Configuration;

namespace DesktopClock.Properties
{
    internal sealed partial class Settings : ApplicationSettingsBase
    {
        private static Settings defaultInstance = (Settings)Synchronized(new Settings());
        
        public static Settings Default
        {
            get { return defaultInstance; }
        }
        
        [UserScopedSetting]
        [DefaultSettingValue("true")]
        public bool UpgradeRequired
        {
            get { return (bool)this["UpgradeRequired"]; }
            set { this["UpgradeRequired"] = value; }
        }
        
        [UserScopedSetting]
        public FormPosition FormPosition
        {
            get 
            { 
                var value = this["FormPosition"];
                return value as FormPosition ?? new FormPosition();
            }
            set { this["FormPosition"] = value; }
        }
        
        [UserScopedSetting]
        [DefaultSettingValue("3")]
        public int OpacityLevel
        {
            get { return (int)this["OpacityLevel"]; }
            set { this["OpacityLevel"] = value; }
        }
        
        [UserScopedSetting]
        [DefaultSettingValue("0")]
        public int ClockStyle
        {
            get { return (int)this["ClockStyle"]; }
            set { this["ClockStyle"] = value; }
        }
        
        [UserScopedSetting]
        [DefaultSettingValue("true")]
        public bool ShowSeconds
        {
            get { return (bool)this["ShowSeconds"]; }
            set { this["ShowSeconds"] = value; }
        }
        
        [UserScopedSetting]
        [DefaultSettingValue("true")]
        public bool ShowDate
        {
            get { return (bool)this["ShowDate"]; }
            set { this["ShowDate"] = value; }
        }
        
        [UserScopedSetting]
        [DefaultSettingValue("true")]
        public bool ShowWeek
        {
            get { return (bool)this["ShowWeek"]; }
            set { this["ShowWeek"] = value; }
        }
        
        [UserScopedSetting]
        [DefaultSettingValue("Lime")]
        public Color ClockColor
        {
            get { return (Color)this["ClockColor"]; }
            set { this["ClockColor"] = value; }
        }
        
        [UserScopedSetting]
        [DefaultSettingValue("Arial")]
        public string FontName
        {
            get { return (string)this["FontName"]; }
            set { this["FontName"] = value; }
        }
        
        [UserScopedSetting]
        [DefaultSettingValue("24")]
        public float FontSize
        {
            get { return (float)this["FontSize"]; }
            set { this["FontSize"] = value; }
        }
        
        [UserScopedSetting]
        [DefaultSettingValue("")]
        public string Alarms
        {
            get { return (string)this["Alarms"]; }
            set { this["Alarms"] = value; }
        }
    }
}

9. 项目配置文件(App.config)

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="userSettings" 
            type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
            <section name="DesktopClock.Properties.Settings" 
                type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
                allowExeDefinition="MachineToLocalUser" requirePermission="false" />
        </sectionGroup>
    </configSections>
    
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
    </startup>
    
    <userSettings>
        <DesktopClock.Properties.Settings>
            <setting name="UpgradeRequired" serializeAs="String">
                <value>True</value>
            </setting>
            <setting name="FormPosition" serializeAs="String">
                <value />
            </setting>
            <setting name="OpacityLevel" serializeAs="String">
                <value>3</value>
            </setting>
            <setting name="ClockStyle" serializeAs="String">
                <value>0</value>
            </setting>
            <setting name="ShowSeconds" serializeAs="String">
                <value>True</value>
            </setting>
            <setting name="ShowDate" serializeAs="String">
                <value>True</value>
            </setting>
            <setting name="ShowWeek" serializeAs="String">
                <value>True</value>
            </setting>
            <setting name="ClockColor" serializeAs="String">
                <value>Lime</value>
            </setting>
            <setting name="FontName" serializeAs="String">
                <value>Arial</value>
            </setting>
            <setting name="FontSize" serializeAs="String">
                <value>24</value>
            </setting>
            <setting name="Alarms" serializeAs="String">
                <value />
            </setting>
        </DesktopClock.Properties.Settings>
    </userSettings>
</configuration>

使用说明

1. 编译和运行

# 使用Visual Studio
1. 打开DesktopClock.sln
2. 编译项目 (F6)
3. 运行 (F5)

# 使用命令行
msbuild DesktopClock.csproj
DesktopClock.exe

2. 功能操作

操作 功能
左键拖拽 移动时钟位置
右键单击 显示设置菜单
双击时钟 切换时钟样式
托盘图标右键 显示完整菜单
托盘图标左键 显示/隐藏时钟

3. 时钟样式

  1. 数字时钟:显示时间、日期、星期
  2. 模拟时钟:传统表盘样式
  3. 简约时钟:只显示小时和分钟

4. 闹钟功能

配置说明

1. 透明度级别

// 5个级别:30%, 50%, 70%, 90%, 100%
private float[] opacityLevels = { 0.3f, 0.5f, 0.7f, 0.9f, 1.0f };

2. 开机启动

3. 数据存储

扩展功能建议

  1. 天气显示:集成天气API显示实时天气
  2. 倒计时:添加倒计时功能
  3. 世界时钟:显示多个时区时间
  4. 屏幕边缘吸附:自动吸附到屏幕边缘
  5. 主题皮肤:支持多种主题颜色
  6. 语音报时:整点语音播报
  7. 快捷键:自定义快捷键操作

专注于matlab/simulink,电子电路,编程