C# Programming

Image

アナログクロックを作る

開発環境: Visual Studio 2003 

1.目次

2.目的

次のような機能のWindows.Forms アプリケーションを作る。
  • アナログクロック
  • 透明なアナログクロック
  • Web からインストールせずに直接アナログクロックを起動する(ノータッチデプロイメント)
Image

See NASA Copyright Notification


このような透明ウィンドウを作ることができます。

Image

See NASA Copyright Notification


さらに、次にリンクをクリックすると、ノータッチデプロイメントが可能です。
アナログクロックのノータッチデプロイメント
AnalogClock.exe
Image

3.参考書

(1) デジタルクロックを作る(その2)
(2) MSDN: Opacityプロパティ
(3) MSDN: .NET Framework のノータッチ デプロイメント

4.アナログクロックの作り方

1. 基本的な枠組みを作るまではデジタルクロックを作る(その2)と同じ。
2. タイマーで、System.Windows.Forms.Invalidate()を呼び出す。
これにより、
OnFormPaintが呼ばれるようになる。
3. OnFormPaint で、時計の針を描画すればOK。
   OnFormPaint では、Graphicsの原点を中心に移動(Translate) し、DrawClock している。
4. DrawClock の説明は、特に必要ないでしょう。
System.Drawing.Drawing2D.Matrix という設計は、気がふれているとしか思えん!
それから、Help を読んでいて目が点になったのだけど、currentpoint をなくしている!
だけど、currentpoint のせいで、可読性が下がるので、currentpointをなくしたことはいい思い切りかもしれない。

5.アナログクロックのソースコード


日付修正履歴
2002/4/28バックグラウンドイメージの大きさに合わせて、自動的にウィンドウをリサイズするように修正。
Timer コンポーネントではなく、Timer コントロールを使用するように修正。
2003/12/7.Net Framework V1.1、VS.2003 対応
AnalogClock.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Drawing.Drawing2D;

namespace AnalogClock
{
    /// <summary>
    /// Form1 の概要の説明です。
    /// </summary>
    public class AnalogClock : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Timer timer1;
        private System.ComponentModel.IContainer components;

        public AnalogClock()
        {
            //
            // Windows フォーム デザイナ サポートに必要です。
            //
            InitializeComponent();

            //
            // TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
            //
        }

        /// <summary>
        /// 使用されているリソースに後処理を実行します。
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// デザイナ サポートに必要です。このメソッドの内容を
        /// コード エディタで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(AnalogClock));
            this.timer1 = new System.Windows.Forms.Timer(this.components);
            // 
            // timer1
            // 
            this.timer1.Enabled = true;
            this.timer1.Interval = 1000;
            this.timer1.Tick += new System.EventHandler(this.OnTick);
            // 
            // AnalogClock
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
            this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
            this.ClientSize = new System.Drawing.Size(394, 304);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.Name = "AnalogClock";
            this.Text = "C# Analog Clock";
            this.Load += new System.EventHandler(this.AnalogClock_Load);
            this.Paint += new System.Windows.Forms.PaintEventHandler(this.OnFormPaint);

        }
        #endregion

        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new AnalogClock());
        }

        private void OnFormPaint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            // Translate to the center of the client window.
            g.TranslateTransform(ClientSize.Width/2, ClientSize.Height/2, MatrixOrder.Append);
            // Now Draw it!
            DrawClock( e.Graphics );
        }

        private void DrawClock(Graphics g)
        {
            const double pai = Math.PI;
            Point center = new Point (0, 0);

            DateTime time = DateTime.Now;
            double secAng = 2.0*pai*time.Second/60.0;
            double minAng = 2.0*pai*(time.Minute + time.Second/60.0)/60.0;
            double hourAng = 2.0*pai*(time.Hour + time.Minute/60.0)/12.0;
            int r = Math.Min( ClientSize.Width, ClientSize.Height ) / 2;
            int secHandLength = (int)(0.7*r);
            int minHandLength = (int)(0.9*r);
            int hourHandLength = (int)(0.5*r);

            Point secHand  = new Point((int)(secHandLength*Math.Sin(secAng)),
                (int)(-secHandLength*Math.Cos(secAng)));
            Point minHand  = new Point((int)(minHandLength*Math.Sin(minAng)),
                (int)(-minHandLength*Math.Cos(minAng)));
            Point hourHand = new Point((int)(hourHandLength*Math.Sin(hourAng)),
                (int)(-hourHandLength*Math.Cos(hourAng)));

            Pen BluePen = new Pen(Color.Blue, 3);
            g.DrawLine(BluePen, center, secHand);

            Pen GreenPen = new Pen(Color.Green, 5);
            g.DrawLine(GreenPen, center, minHand);

            Pen RedPen = new Pen(Color.Red, 7);
            g.DrawLine(RedPen, center, hourHand);
        }

        private void FitToBackgroundImage()
        {               
            this.SetClientSizeCore(this.BackgroundImage.Width, this.BackgroundImage.Height);
        }

        private void OnTick(object sender, System.EventArgs e)
        {
            this.Invalidate();
        }

        private void AnalogClock_Load(object sender, System.EventArgs e)
        {
            this.FitToBackgroundImage();            
        }
    }
}

6.透明なアナログクロックの作り方


Form Windowのプロパティで、Opacity を変更するだけ。
Image

7.ノータッチデプロイメント。

アナログクロックでは、ファイルアクセスとか、レジストリ操作とか、セキュリティ上危ないコードは使用していません。
このような安全なコードは、ノータッチデプロイメントするのに適しています。
ノータッチデプロイメントの説明は MSDN: .NET Framework のノータッチ デプロイメントに詳しいのでそちらを読んでください。
やりかたは、単にコンパイルした AnalogClock.exe を Web 上にアップロードすればOKです。

クライアント側(IEから起動する側)は、.NET Framework SP1 以上があればOKです。