65.9K
CodeProject 正在变化。 阅读更多。
Home

简单的模拟时钟小部件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.48/5 (18投票s)

2007 年 10 月 23 日

CPOL

2分钟阅读

viewsIcon

73674

downloadIcon

4644

创建一个简单的 C# 模拟时钟小部件,你也能做到!

Simple C# widget and windows gadget side-by-side.

引言

在长时间体验 Mac OS 的“仪表盘”和雅虎的 Konfabulator 之后,微软终于在其最新的操作系统 Windows Vista 中推出了自己的小工具版本。然而,它们都是用 HTML 和 JavaScript 编写的。为了测试我迄今为止所学的 C# 编程知识,我也开发了一个 C# 版本的 Windows 小工具。我认为这对于初学者来说是一个挑战,因为它需要一些简单的数学、图像处理和 3D 图形编程基础。

Using the Code

首先,我们需要为小部件提供一个背景图像,使其看起来更专业。可以在窗体加载时设置它。为了防止图像丢失,我将图像嵌入到应用程序中。这段代码的作用是获取左上角的像素,并在同一位图的其他部分遇到相同颜色时将剩余的像素设置为不可见。然后将其设置为背景,并将窗体设置为适应图像大小。

private void SetFormBackgroundImage(Bitmap bmpImage)
{
    Color clrPixel = bmpImage.GetPixel(0, 0);
    bmpImage.MakeTransparent(clrPixel);
    this.BackgroundImage = bmpImage;
    // Set the form size from image size

    this.Size = bmpImage.Size;
}

为了创建无闪烁的动画,您需要 双缓冲。为了实现这一点

public void EnableDoubleBuffering()
{
    // Set the value of the double-buffering style bits to true.

    this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint |
        ControlStyles.AllPaintingInWmPaint, true);
    this.UpdateStyles();
}

要捕获鼠标按下事件,您需要在鼠标按下时存储鼠标的位置,并在鼠标移动时进行偏移。

private void frmIrregular_MouseDown(object sender, MouseEventArgs e)
{
    ptMouseOffset = new Point(-e.X, -e.Y);
}

private void frmIrregular_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        Point ptCurrMousePos = Control.MousePosition;
        ptCurrMousePos.Offset(ptMouseOffset.X, ptMouseOffset.Y);
        this.Location = ptCurrMousePos;
    }
}

现在是这个小部件的重要部分:绘制时针、分针和秒针。基本原理是...

  1. 将窗体的原点设置为从左上角开始的中心(以便进行后续的旋转)
  2. 保存当前状态
  3. 旋转新的图形对象
  4. 在新原点和新方向上绘制秒针(或任何指针)
  5. 恢复保存的状态
  6. 旋转新的图形对象
  7. 在新原点和新方向上绘制分针(或剩余的任何指针)
  8. 重新加载标识
  9. 重置原点和方向(如果似乎失败,则恢复保存的状态)
  10. 旋转新的图形对象
  11. 在新原点和新方向上绘制时针(或剩余的任何指针)

将这些步骤转化为代码

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
    // Set the origin to center of the form

    e.Graphics.TranslateTransform(80.0F, 80.0F);

    // Save translated graphics state; So origin 

    // will remain at center of form when restore

    GraphicsState transState = e.Graphics.Save();

    // Capture a copy of current time for consistent

    DateTime dtNow = DateTime.Now;

    // rotation starts from new center of the form

    e.Graphics.RotateTransform(dtNow.Second * 6.0F - 90.0F);
    // Anti-alias only affect the next shape

    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    // draw the second hand at new center of the form

    e.Graphics.FillRectangle(new SolidBrush(Color.Silver), -1, -1, 55, 2);

    //// Restore graphics state to translated state and fill second hand

    e.Graphics.Restore(transState);

    // minus 90 degree because start at x-axis

    e.Graphics.RotateTransform(dtNow.Minute * 6.0F - 90.0F);
    // Anti-alias only affect the next shape

    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    e.Graphics.FillRectangle(new SolidBrush(Color.Silver), -1, -1, 45, 3);

    //// Restore graphics state to translated state and fill minute hand

    //gHands.Restore(transState);

    // Reset transformation matrix to identity and fill rectangle.

    e.Graphics.ResetTransform();
    // Set the origin to center of the form

    e.Graphics.TranslateTransform(80.0F, 80.0F);

    // minus 90 degree because start at x-axis; Minute affects hour hand too

    e.Graphics.RotateTransform(
        dtNow.Hour * 30.0F - 90.0F + dtNow.Minute * 0.5F);
    // Anti-alias only affect the next shape

    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    e.Graphics.FillRectangle(new SolidBrush(Color.Silver), -1, -1, 35, 4);
}

通过定时器每秒强制窗体重新绘制:瞧!我认为我已经展示了 90% 的代码了;很简单,对吧?你也可以从我的 博客 上获取它。

版本

  • 2007-09-26:首次发布
© . All rights reserved.