アナログクロック その2(自由な形のウィンドウを作る)
開発環境: Visual Studio 2003
次のような機能のForm アプリケーションを作る。
- 自由図形のアナログクロック
- マウスの左ボタンを押しながらドラッグすることにより、ウィンドウを移動する。
- マウスの右ボタンでコンテキストメニューを表示し、メニューから終了できる。
注意: 透明にならない場合の確認すべき点
透明なウィンドウおよび領域は、Windows 2000 のみでサポートされているというヘルプがありますが、XP
でもOKです。
透明にならない場合、Windows 2000 以降かどうか確認してください。
TransparencyKey は、コントロールパネル→画面→画面の色が32bit だと、透明にならない可能性があります。
透明にならない場合には、画面の色を 32bit 以外で試してみてください。
また、http://www.dotnet247.com/247reference/msgs/21/107515.aspx
では、フォントのスムージングをしている場合にもNGという説明があります。私の場合には、フォントを滑らかにするかどうかは影響ありませんでしたが、確認してみてください。
See
NASA Copyright Notification
作り方
| 手順 |
説明 |
1 | アナログクロックを作る。 | 基本的な枠組みを作るまではアナログクロックを作る(その1)と同じ。 |
2 | 自由図形のウィンドウにする。 | Form のTransparencyKey プロパティで透過色とする色を指定します。 今回の例では、次のようなスペースシャトルの背景を黒で塗りつぶします。 そして、TransparencyKey をBlack とします。 これにより、TransparencyKeyで指定された場所は透過となり、またそこで発生したイベントは、 すべて下のウィンドウへ送られます。
あとは、FormBorderStyle を None として、フレームを表示しないようにします。 |
3 | マウスの右ボタンでコンテキストメニューを表示し、終了できるようにする。 | ツールボックスより、ContextMenu を追加し、Exit メニューを作る。 |
4 | コンテキストメニューでExit する処理 | コンテキストメニューのExit が押された時のイベントを追加する。
private void OnExit(object sender, System.EventArgs e) { Application.Exit();
} |
5 | Form からContextMenuを呼び出せるようにする。。 | Form プロパティの動作から、ContextMenuプロパティに3で作ったコンテキストメニューをセットする。
|
6 | そのままでは、アナログクロックの移動ができないので、マウスでドラッグして移動できるようにします。 | そのために、つぎのようにマウスイベントを処理します。 マウスボタンが押されたときに、押されたことを示す mouseIsDown 変数を持ちます。 この変数は、マウスが放されたときに、クリアします。 また、マウスが移動したときに、そのときの移動量にしたがって、ウィンドウを移動します。 ウィンドウの移動には、Form.Left, Form.Top プロパティを変更するとウィンドウを移動できます。 |
7 | 起動時に引数で画像を読み込むようにします。 | main のargs の第1引数から、Image.FromFile( ) で、取得した Image
インスタンスをbackgroundImage に渡します。 ファイルが見つからないときのために、Exception をキャッチしておきます。 |
実行例
次のような画像ファイルを用意します。
10075946.gif
次に、コマンドラインから、
AnalogClock (引数がない場合は、デフォルトのシャトルが表示される)
AnalogClock 10075946.gif
と起動します。
実行結果
以下、ソースコード
日付 |
修正履歴 |
2003/12/7 | VS.2003, .NetFramework V1.1 対応 |
2002/4/28 | バックグラウンドイメージの大きさに合わせて、自動的にウィンドウをリサイズするように修正。 |
Timer コンポーネントではなく、Timer コントロールを使用するように修正。 |
ContextMenu を追加。 |
2002/3/3 | 初期バージョン作成 |
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Drawing.Drawing2D;
namespace TransparentAnalogClock
{
/// <summary>
/// Form1 の概要の説明です。
/// </summary>
public class TransparentAnalogClock : System.Windows.Forms.Form
{
private System.ComponentModel.IContainer components;
public TransparentAnalogClock( string[] args )
{
//
// Windows フォーム デザイナ サポートに必要です。
//
InitializeComponent();
//
// TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
//
if (args.Length == 1)
{
try
{
this.BackgroundImage = System.Drawing.Image.FromFile(args[0]);
}
catch ( Exception e )
{
DialogResult res = MessageBox.Show(e.Message, this.Text,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
/// <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(TransparentAnalogClock));
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.contextMenu1 = new System.Windows.Forms.ContextMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Interval = 1000;
this.timer1.Tick += new System.EventHandler(this.OnTick);
//
// contextMenu1
//
this.contextMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuItem1});
//
// menuItem1
//
this.menuItem1.Index = 0;
this.menuItem1.Text = "Exit";
this.menuItem1.Click += new System.EventHandler(this.OnExit);
//
// TransparentAnalogClock
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
this.ClientSize = new System.Drawing.Size(244, 422);
this.ContextMenu = this.contextMenu1;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "TransparentAnalogClock";
this.Text = "C# Analog Clock";
this.TransparencyKey = System.Drawing.Color.Black;
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.OnMouseDown);
this.Load += new System.EventHandler(this.TransparentAnalogClock_Load);
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.OnMouseUp);
this.Paint += new System.Windows.Forms.PaintEventHandler(this.OnFormPaint);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.OnMouseMove);
}
#endregion
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.Run(new TransparentAnalogClock( args ));
}
private System.Windows.Forms.Timer timer1;
private bool mouseIsDown = false;
private System.Windows.Forms.ContextMenu contextMenu1;
private System.Windows.Forms.MenuItem menuItem1;
private Point mouseDownPoint;
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/2, 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 YellowPen = new Pen(Color.Yellow, 3);
g.DrawLine(YellowPen, 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 OnMouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (mouseIsDown && e.Button == System.Windows.Forms.MouseButtons.Left)
{
this.Left += e.X - mouseDownPoint.X;
this.Top += e.Y - mouseDownPoint.Y;
}
}
private void OnMouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
mouseDownPoint = new Point(e.X, e.Y);
mouseIsDown = true;
}
}
private void OnMouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
mouseIsDown = false;
}
}
private void OnTick(object sender, System.EventArgs e)
{
Invalidate();
}
private void FitToBackgroundImage()
{
this.SetClientSizeCore(this.BackgroundImage.Width, this.BackgroundImage.Height);
}
private void OnExit(object sender, System.EventArgs e)
{
Application.Exit();
}
private void TransparentAnalogClock_Load(object sender, System.EventArgs e)
{
FitToBackgroundImage();
}
}
}