基本的な作り方は、参考書(1)に記載されていますので、そちらを参考にしてください。
ここでは、参考書(1)から、さらに簡単にした例です。
(1) Windows Forms で ScreenSaver1 というプロジェクトを作成します。
ここでは、Uchukamen.ScreenSaver 名前空間に、ScreenSaver1 というフォームを作成します。
(2) Form のプロパティを次のようにセットして、スクリーンセーバのトップ画面を作ります。
プロパティ | 値 | 説明 |
TopMost | True | 一番上の画面でスクリーンを覆う。 |
WindowState | Maximized | 画面を最大化 |
FormBoarderStyle | None | ウィンドウのまわりの枠は表示しない。 |
(3) キーを押したり、マウスを動かしたときに、スクリーンセーバを解除するイベントハンドラを追加します。
イベント | 動作 | 説明 |
MouseDown | ApplicationExit() | マウスボタンを押した。 |
MouseMove | ApplicationExit() | マウスを動かした。 |
KeyDown | ApplicationExit() | 何かキーが押された。 |
マウスが動いた場合のイベント処理 |
MSDNの例では、10ピクセル以上マウスが動いた場合、スクリーンセーバー解除するようにプログラムしています。
このために、MouseMoveイベントで、1回目のイベントで、そのときのマウスの位置を保存し、次のイベントで、移動量の絶対値が10以上であれば、スクリーンセーバを解除するようにしています。
private bool isActive = false;
private Point mouseLocation;
private void ScreenSaver1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
// If the MouseLocation still points to 0,0, move it to its actual location
// and save the location for later. Otherwise, check to see if the user
// has moved the mouse at least 10 pixels.
if(!isActive)
{
this.mouseLocation = new Point(e.X, e.Y);
isActive = true;
}
else
{
if(Math.Abs(e.X - this.mouseLocation.X) > 10 ||
Math.Abs(e.Y - this.mouseLocation.Y) > 10 )
Application.Exit();
}
}
|
(4) 描画処理を追加します。次のような、DrawShape() メソッドを追加してください。
ここでは、MSDN のサンプルコードのオプションを削除してさらに簡単にしています。
そして、この描画処理が、タイマーで一定期間ごとに呼び出されるようにします。
そのために、ツールバーより、タイマーをフォームへドラッグアンドドロップします。
次に、フォームのロードイベントで、タイマーをイネーブルされるようにします。
そして、タイマーのTickイベントでこのDrawShape() メソッドを呼び出すようにします。
スクリーンセーバーの描画処理 |
MSDNの例と同じように、描画処理を追加します。
このとき、Graphics オブジェクトが必要なので、フォームがロードされたときに、CreateGraphics()で作成しておきます。
private Graphics g = null;
private void ScreenSaver1_Load(object sender, System.EventArgs e)
{
this.timer1.Enabled = true;
g = this.CreateGraphics();
}
private Random random = new Random();
private void DrawShape()
{
Color myColor;
// ランダムな大きさで図形を描画するため、ウィンドウの大きさ内の(x1, y1), (x2, y2) を
// 乱数で発生させます。
int maxX = this.Width;
int maxY = this.Height;
int x1 = random.Next(0, maxX);
int x2 = random.Next(0, maxX);
int y1 = random.Next(0, maxY);
int y2 = random.Next(0, maxY);
// 上記座標より、描画する矩形を定義します。
Rectangle myRect = new Rectangle(Math.Min(x1, x2), Math.Min(y1, y2), Math.Abs(x1 - x2), Math.Abs(y1 - y2));
myColor = Color.FromArgb(random.Next(255), random.Next(255), random.Next(255), random.Next(255));
g.FillRectangle(new SolidBrush(myColor), myRect);
}
|
(6) これで実行してみましょう。
フルスクリーンで描画をはじめたと思います。
これで、基本的な描画は完成です。
(7) 次に、これをスクリーンセーバとして、Windows から起動してもらう必要があります。
そのためには、(6)で作ったファイルを .scr というファイル名にリネームし、%windir%\System32 にストアする必要があります。
しかし、それだけではだめで、スクリーンセーバとして起動される際に、パラメータとして渡されてきます。
そこで、各パラメータに従った動作をするように、起動時のパラメータの処理を追加します。
起動時パラメータ | 説明 |
/c | スクリーンセーバのオプション設定用のダイアログを表示する。 |
/s | スクリーンセーバとして動作 |
/p ウィンドウハンドル | プレビュー画面の表示。
しかし、ウィドウハンドルに直接描画するには、やっかいなプラットフォーム呼び出しが必要なので対応しない。 |
スクリーンセーバの起動時パラメータの処理 |
参考文献1のコードは、ちょっとトリッキーなコードですね。
自分のクラスのインスタンスを新たに生成し、そいつにダイアログを表示させると言う動作になります。
[STAThread]
static void Main(string[] args)
{
if(args.Length > 0)
{
// "/p" はプレビュー。ここではノンサポート。
if(args[0].ToLower() == "/p")
Application.Exit();
// "/c" はオプションダイアログ。ここではノンサポート。
if(args[0].ToLower().Trim().Substring(0, 2) == "/c")
{
OptionForm optionForm = new OptionForm();
optionForm.ShowDialog();
Application.Exit();
}
// "/s" スクリーンセーバの実行
if(args[0].ToLower() == "/s")
{
ScreenSaver1 form = new ScreenSaver1();
form.ShowDialog();
Application.Exit();
}
}
else
{
ScreenSaver1 form = new ScreenSaver1();
form.ShowDialog();
Application.Exit();
}
}
|
(8) オプションの設定
Windowsからは、設定ボタンを押した場合に、/c オプションでスクリーンセーバが起動されます。
この場合に、ダイアログを表示して、自分の好きな設定に変えることができます。
そこで、オプションを管理すための Option クラス、およびオプションの設定を行う OptionDialog クラスを追加します。
オプションは、タイマーのスピードを変えるだけの簡単なものにします。
この値は、実行ディレクトリの”MyScreenSaver.dat”と言うファイルに決めうちで、シリアライズ、デシリアライズします。
(9)*.scr ファイルを自動的にビルドするようにする。
ビルドができたらば、ScreenSaver1.exe をSceenSaver1.scr にコピーするようにビルドコマンドを追加します。
メニュー⇒プロジェクト⇒プロパティでプロジェクトのプロパティページを開き、共通プロパティのビルドイベントで、
ビルド後のイベントコマンドラインで、copy ScreenSaver1.exe ScreenSaver1.scr というようにコピーします。
また、テスト用にcopy ScreenSaver1.scr %windir%\system32 を追加しておくと、テストが楽です。
ただし、バグがあったりして動作不良の場合、デバッグもできなくなってしまうので、危険です。
WindowState を Normal で十分テストしてから、%windir%\system32 にコピーしましょう。
|
Form1.cs |
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace Uchukamen.ScreenSaver
{
/// <summary>
/// Form1 の概要の説明です。
/// </summary>
public class ScreenSaver1 : System.Windows.Forms.Form
{
private System.ComponentModel.IContainer components;
public ScreenSaver1()
{
//
// Windows フォーム デザイナ サポートに必要です。
//
InitializeComponent();
//
// TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
//
}
/// <summary>
/// 使用されているリソースに後処理を実行します。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows フォーム デザイナで生成されたコード
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.timer1 = new System.Windows.Forms.Timer(this.components);
//
// timer1
//
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// ScreenSaver1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
this.ClientSize = new System.Drawing.Size(292, 266);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "ScreenSaver1";
this.Text = "Form1";
this.TopMost = true;
this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ScreenSaver1_KeyDown);
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ScreenSaver1_MouseDown);
this.Load += new System.EventHandler(this.ScreenSaver1_Load);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ScreenSaver1_MouseMove);
}
#endregion
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main(string[] args)
{
if(args.Length > 0)
{
// "/p" はプレビュー。ここではノンサポート。
if(args[0].ToLower() == "/p")
Application.Exit();
// "/c" はオプションダイアログ。ここではノンサポート。
if(args[0].ToLower().Trim().Substring(0, 2) == "/c")
{
OptionForm optionForm = new OptionForm();
optionForm.ShowDialog();
Application.Exit();
}
// "/s" スクリーンセーバの実行
if(args[0].ToLower() == "/s")
{
ScreenSaver1 form = new ScreenSaver1();
form.ShowDialog();
Application.Exit();
}
}
else
{
ScreenSaver1 form = new ScreenSaver1();
form.ShowDialog();
Application.Exit();
}
}
private System.Windows.Forms.Timer timer1;
private Random random = new Random();
private void DrawShape()
{
Color myColor;
// ランダムな大きさで図形を描画するため、ウィンドウの大きさ内の(x1, y1), (x2, y2) を
// 乱数で発生させます。
int maxX = this.Width;
int maxY = this.Height;
int x1 = random.Next(0, maxX);
int x2 = random.Next(0, maxX);
int y1 = random.Next(0, maxY);
int y2 = random.Next(0, maxY);
// 上記座標より、描画する矩形を定義します。
Rectangle myRect = new Rectangle(Math.Min(x1, x2), Math.Min(y1, y2), Math.Abs(x1 - x2), Math.Abs(y1 - y2));
myColor = Color.FromArgb(random.Next(255), random.Next(255), random.Next(255), random.Next(255));
g.FillRectangle(new SolidBrush(myColor), myRect);
}
private Graphics g = null;
private Options options = new Options();
private void timer1_Tick(object sender, System.EventArgs e)
{
this.DrawShape();
}
private void ScreenSaver1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
Application.Exit();
}
private void ScreenSaver1_Load(object sender, System.EventArgs e)
{
this.timer1.Enabled = true;
g = this.CreateGraphics();
options.LoadOptions();
this.timer1.Interval = options.Speed;
}
private void ScreenSaver1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
Application.Exit();
}
private bool isActive = false;
private Point mouseLocation;
private void ScreenSaver1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
// MSDNの例では、10ピクセル以上マウスが動いた場合、
// スクリーンセーバー解除するようにプログラムしています。
// このために、MouseMoveイベントで、1回目のイベントで、
// そのときのマウスの位置を保存し、次のイベントで、
// 移動量の絶対値が10以上であれば、
// スクリーンセーバを解除するようにしています。
if(!isActive)
{
this.mouseLocation = new Point(e.X, e.Y);
isActive = true;
}
else
{
if(Math.Abs(e.X - this.mouseLocation.X) > 10 ||
Math.Abs(e.Y - this.mouseLocation.Y) > 10 )
Application.Exit();
}
}
}
}
|
Option.cs |
using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace Uchukamen.ScreenSaver
{
/// <summary>
/// Options の概要の説明です。
/// </summary>
[Serializable()]
public class Options
{
public Options()
{
//
// TODO: コンストラクタ ロジックをここに追加してください。
//
speed = 500;
}
private string optionsPath = Environment.CurrentDirectory + "\\ScreenSaver1.dat";
private int speed;
public int Speed
{
get
{
return speed;
}
set
{
speed = value;
}
}
public bool IsOptionFileExisting()
{
FileInfo finfo = new System.IO.FileInfo(optionsPath);
return finfo.Exists;
}
public void LoadOptions()
{
Options options = new Options();
if(options.IsOptionFileExisting())
{
XmlSerializer xs = new XmlSerializer(this.GetType());
StreamReader sr = new StreamReader(optionsPath);
System.Xml.XmlTextReader xtr = new System.Xml.XmlTextReader(sr);
if(xs.CanDeserialize(xtr))
options = (Options)(xs.Deserialize(xtr));
else
options.SaveOptions();
xtr.Close();
sr.Close();
}
this.Speed = options.Speed;
}
public void SaveOptions()
{
StreamWriter sw = new StreamWriter(optionsPath);
XmlSerializer xs = new XmlSerializer(this.GetType());
xs.Serialize(sw, this);
sw.Close();
}
}
}
|
OptionForm.cs |
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace Uchukamen.ScreenSaver
{
/// <summary>
/// OptionForm の概要の説明です。
/// </summary>
public class OptionForm : System.Windows.Forms.Form
{
private System.Windows.Forms.TrackBar trackBar1;
private System.Windows.Forms.Button buttonOk;
private System.Windows.Forms.Button buttonCancel;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
/// <summary>
/// 必要なデザイナ変数です。
/// </summary>
private System.ComponentModel.Container components = null;
public OptionForm()
{
//
// Windows フォーム デザイナ サポートに必要です。
//
InitializeComponent();
//
// TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
//
}
/// <summary>
/// 使用されているリソースに後処理を実行します。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows フォーム デザイナで生成されたコード
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
this.trackBar1 = new System.Windows.Forms.TrackBar();
this.buttonOk = new System.Windows.Forms.Button();
this.buttonCancel = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit();
this.SuspendLayout();
//
// trackBar1
//
this.trackBar1.LargeChange = 100;
this.trackBar1.Location = new System.Drawing.Point(8, 32);
this.trackBar1.Maximum = 1000;
this.trackBar1.Minimum = 100;
this.trackBar1.Name = "trackBar1";
this.trackBar1.Size = new System.Drawing.Size(256, 45);
this.trackBar1.TabIndex = 0;
this.trackBar1.TickFrequency = 100;
this.trackBar1.Value = 100;
//
// buttonOk
//
this.buttonOk.Location = new System.Drawing.Point(88, 96);
this.buttonOk.Name = "buttonOk";
this.buttonOk.TabIndex = 1;
this.buttonOk.Text = "Ok";
this.buttonOk.Click += new System.EventHandler(this.buttonOk_Click);
//
// buttonCancel
//
this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.buttonCancel.Location = new System.Drawing.Point(168, 96);
this.buttonCancel.Name = "buttonCancel";
this.buttonCancel.TabIndex = 2;
this.buttonCancel.Text = "Cancel";
//
// label1
//
this.label1.Location = new System.Drawing.Point(8, 8);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(32, 24);
this.label1.TabIndex = 3;
this.label1.Text = "速度";
//
// label2
//
this.label2.Location = new System.Drawing.Point(8, 72);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(32, 24);
this.label2.TabIndex = 4;
this.label2.Text = "早い";
//
// label3
//
this.label3.Location = new System.Drawing.Point(240, 72);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(32, 24);
this.label3.TabIndex = 5;
this.label3.Text = "遅い";
//
// OptionForm
//
this.AcceptButton = this.buttonOk;
this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
this.CancelButton = this.buttonCancel;
this.ClientSize = new System.Drawing.Size(280, 126);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.buttonCancel);
this.Controls.Add(this.buttonOk);
this.Controls.Add(this.trackBar1);
this.Name = "OptionForm";
this.Text = "ScreenSaver1 Option";
this.Load += new System.EventHandler(this.OptionForm_Load);
((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private void buttonOk_Click(object sender, System.EventArgs e)
{
options.Speed = this.trackBar1.Value;
options.SaveOptions();
this.Close();
}
private Options options;
private void OptionForm_Load(object sender, System.EventArgs e)
{
options = new Options();
options.LoadOptions();
this.trackBar1.Value = options.Speed;
}
}
}
|
|