前々回で日付入力、前回でバイオリズムグラフの描画をやりましたので、その機能をコントロールに実装してゆきます。
コントロールを作る場合、コードにして静的に実装する場合(例:BCCSkeltonのPICTUREBOX)と動的ライブラリ(DLL)にして実装する場合(例:Win32 SDKのDICE)がありますが、C#は簡単にDLLが作れ、また作ったDLLを簡単に読み込んで利用できるので、DLLによる実装をお勧めします。
次にコントロールを作る場合、「更地」のウィンドウから始める手もありますが、今回の場合、PictureBoxを表示に使っていたので、PictureBoxを承継した派生コントロール、"BrmBox"(クラス名)としてBiorythm(名前空間およびDLL名)に入れましょう。MSCompAssでDLLを作るには、"Option"の「出力ファイル」を"/target:library"するだけで、後はいつもと変わりありません。(参考までに私の環境でのoptファイルも載せます。)
なお、既に前回、前々回やった解説は省きます。(注)
注:ウィンドウベースではEaselクラスを使いましたが、文字列表示とLineしか使わないので、ここではC#のGraphicsクラスのメソッドだけを使って実装します。
【BrmBox in Biorythm】
//////////////////////////////
// C# Biorythm.cs
// Biorythm Control Component
//////////////////////////////
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Biorythm
{
public partial class BrmBox : PictureBox //PictureBoxを承継したBrmBoxというクラスを作る
{
//バイオリズムグラフ表示関係
private Bitmap Canvas = null; //仮想画面ビットマップ
private Graphics hGraph = null; //仮想画面のグラフィック
//バイオリズム計算関係
DateTime DOB; //誕生日(Date of Birth)
DateTime DOT; //指定日(Date of Traget)
//コンテキストメニュー関係-これは新しい内容です。右クリックでメニューを出します。
ContextMenu contextMenu;
MenuItem mi1, mi2, mi3;
//コンストラクター
public BrmBox()
{
this.ClientSize = new Size(320, 320);
this.BackColor = SystemColors.Control;
this.SizeChanged += Control_SizeChanged;
//同サイズのビットマップ仮想画面の作成-やり方はEaselと同じです。
Canvas = new Bitmap(this.Width, this.Height);
//Graphicsクラス(アンチエイリアス)-やり方はEaselと同じです。
hGraph = Graphics.FromImage(Canvas);
hGraph.SmoothingMode = SmoothingMode.AntiAlias;
hGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
//コンテキストメニュー関連-コントロール上で右クリックして出すポップアップメニューです。
mi1 = new MenuItem();
mi1.Index = 0;
mi1.Text = "生年月日入力";
mi2 = new MenuItem();
mi2.Index = 0;
mi2.Text = "指定日入力";
mi3 = new MenuItem();
mi3.Index = 0;
mi3.Text = "グラフ表示";
contextMenu = new ContextMenu();
contextMenu.MenuItems.Add(mi1);
contextMenu.MenuItems.Add(mi2);
contextMenu.MenuItems.Add(mi3);
this.ContextMenu = contextMenu;
mi1.Click += new EventHandler(SetDOB);
mi2.Click += new EventHandler(SetDOT);
mi3.Click += new EventHandler(Display);
}
//デストラクター
~BrmBox()
{
if(hGraph != null)
hGraph.Dispose(); //グラフィックリソースの開放
if(Canvas != null)
Canvas.Dispose(); //ビットマップリソースの開放
}
//コントロールがサイズ変更された場合
private void Control_SizeChanged(object sender, EventArgs e)
{
//幅または高さが0の場合、「使用されたパラメーターが有効ではありません」エラーとなる為
if(this.Width * this.Height == 0)
return;
Rectangle srcRect;
Rectangle desRect;
Image img = (Bitmap)Canvas.Clone(); //旧画像をBitmapで保存
Canvas.Dispose(); //Canvasを一旦開放
Canvas = new Bitmap(this.Width, this.Height); //新しいサイズで作成
if(this.Width > img.Width)
{
if(this.Height > img.Height)
{
srcRect = new Rectangle(0, 0, img.Width, img.Height);
desRect = new Rectangle(0, 0, img.Width, img.Height);
}
else
{
srcRect = new Rectangle(0, 0, img.Width, this.Height);
desRect = new Rectangle(0, 0, img.Width, this.Height);
}
}
else
{
if(this.Height > img.Height)
{
srcRect = new Rectangle(0, 0, this.Width, img.Height);
desRect = new Rectangle(0, 0, this.Width, img.Height);
}
else
{
srcRect = new Rectangle(0, 0, this.Width, this.Height);
desRect = new Rectangle(0, 0, this.Width, this.Height);
}
}
//CanvasのGraphicsクラスの再生成
hGraph.Dispose(); //旧いサイズのCanvasのものを廃棄
hGraph = Graphics.FromImage(Canvas); //新しいサイズのCanvasのものを生成
hGraph.SmoothingMode = SmoothingMode.AntiAlias; //アンチエイリアス
hGraph.PixelOffsetMode = PixelOffsetMode.HighQuality; //高品質画面
hGraph.DrawImage(img, desRect, srcRect, GraphicsUnit.Pixel); //旧いCanvasイメージ(img)のコピー
this.Image = Canvas; //Canvasに張り付け
img.Dispose(); //使い終わったimgを開放
}
public void SetDOB(object sender = null, EventArgs e = null)
{
DateDialog dd = new DateDialog("生年月日を入力してください。");
//OKボタンが押された場合
if(dd.ShowDialog() == DialogResult.OK)
DOB = dd.date;
dd.Dispose(); //2023年06月30日追加
}
public void SetDOT(object sender = null, EventArgs e = null)
{
DateDialog dd = new DateDialog("バイオリズムを見る年月日を指定してください。");
//OKボタンが押された場合
if(dd.ShowDialog() == DialogResult.OK)
DOT = dd.date;
dd.Dispose(); //2023年06月30日追加
}
public void Display(object sender = null, EventArgs e = null)
{
//初期設定
TimeSpan ts = DOT - DOB; //誕生から指定日までの経過日数
Color oldcol = this.ForeColor; //現在の前景色を退避
hGraph.Clear(this.BackColor); //画面消去
//使用するブラシの生成
Brush RBrush = new SolidBrush(Color.Red);
Brush GBrush = new SolidBrush(Color.Green);
Brush BBrush = new SolidBrush(Color.Blue);
Brush VBrush = new SolidBrush(Color.BlueViolet);
//身体、感情、知性の色定義を表示する
hGraph.DrawString("身体周期(Physical Cycle):", System.Drawing.SystemFonts.DefaultFont, RBrush, 10, 10, new StringFormat(StringFormatFlags.NoWrap));
hGraph.DrawString("感情周期(Emotional Cycle):", System.Drawing.SystemFonts.DefaultFont, GBrush, 10, 30, new StringFormat(StringFormatFlags.NoWrap));
hGraph.DrawString("知性周期(Intellectual Cycle):", System.Drawing.SystemFonts.DefaultFont, BBrush, 10, 50, new StringFormat(StringFormatFlags.NoWrap));
//バイオリズムグラフ表示領域の画面設定
//黒枠と基準線
hGraph.DrawRectangle(Pens.Black, 10, 80, this.Width - 20, this.Height - 90);
int VCenter = (this.Height - 70) / 2 + 70; //バイオリズムグラフ描画領域の水平中央線のy座標
hGraph.DrawLine(Pens.Black, 10, VCenter, this.Width - 10, VCenter);
//日を表す縦線 Color.Silver or Color.DarkGray
for(int i = 1; i < 15; i++)
hGraph.DrawLine(Pens.Silver, 10 + (int)(i * (double)(this.Width - 20) / 30.0), 80, 10 + (int)(i * (double)(this.Width - 20) / 30.0), this.Height - 10);
for(int i = 16; i < 30; i++)
hGraph.DrawLine(Pens.Silver, 10 + (int)(i * (double)(this.Width - 20) / 30.0), 80, 10 + (int)(i * (double)(this.Width - 20) / 30.0), this.Height - 10);
//指定日のみ青紫で表示
hGraph.DrawLine(Pens.BlueViolet, this.Width / 2, 80, this.Width / 2, this.Height - 10);
hGraph.DrawString(DOT.ToString("yyyy年MM月dd日"), System.Drawing.SystemFonts.DefaultFont, VBrush, this.Width / 2 - 40, 64, new StringFormat(StringFormatFlags.NoWrap));
//正弦波グラフを横(10~this.Width - 10)、縦(80~this.Height - 10)に表示する
int oldx = 0, oldPy = 0, oldEy = 0, oldIy = 0;
string Pstr = "", Estr = "", Istr = ""; //評価表示用文字列
for(double i = 0; i < 30; i += 0.1) //指定日を中央に30日のデータを表示
{ //グラフのx座標の範囲:10 ~ this.Width - 10
//バイオリズム計算(グラフy座標):sin(2πt/T): tは経過日数、Tは23(P), 28(S), 33(I)日
double t = (double)(ts.Days + i - 15);
int x = 10 + (int)(i * (double)(this.Width - 20) / 30.0);
int Py = (int)(-Math.Sin(Math.PI * 2 * t / 23.0) * (double)(this.Height - 100) / 2) + this.Height / 2 + 40;
int Ey = (int)(-Math.Sin(Math.PI * 2 * t / 28.0) * (double)(this.Height - 100) / 2) + this.Height / 2 + 40;
int Iy = (int)(-Math.Sin(Math.PI * 2 * t / 33.0) * (double)(this.Height - 100) / 2) + this.Height / 2 + 40;
if((int)i *10 == 150) //基準日処理-if(i == 15.0 または 15d)やif(i.Equal(15.0 または 15d))は失敗する。
{
if(Py < VCenter)
Pstr = "高調期";
else if(Py == VCenter)
Pstr = "不安定日";
else
Pstr = "低調期";
if(Ey < VCenter)
Estr = "高調期";
else if(Ey == VCenter)
Estr = "不安定日";
else
Estr = "低調期";
if(Iy < VCenter)
Istr = "高調期";
else if(Iy == VCenter)
Istr = "不安定日";
else
Istr = "低調期";
}
if(i > 0) //最初の始点は描画しない
{
hGraph.DrawLine(Pens.Red, oldx, oldPy, x, Py);
hGraph.DrawLine(Pens.Green, oldx, oldEy, x, Ey);
hGraph.DrawLine(Pens.Blue, oldx, oldIy, x, Iy);
}
oldx = x;
oldPy = Py;
oldEy = Ey;
oldIy = Iy;
}
//身体、感情、知性の評価を表示する
hGraph.DrawString(Pstr, System.Drawing.SystemFonts.DefaultFont, RBrush, 160, 10, new StringFormat(StringFormatFlags.NoWrap));
hGraph.DrawString(Estr, System.Drawing.SystemFonts.DefaultFont, GBrush, 160, 30, new StringFormat(StringFormatFlags.NoWrap));
hGraph.DrawString(Istr, System.Drawing.SystemFonts.DefaultFont, BBrush, 160, 50, new StringFormat(StringFormatFlags.NoWrap));
//バイオリズムグラフを表示する
this.Image = Canvas;
//ブラシの開放
RBrush.Dispose();
GBrush.Dispose();
BBrush.Dispose();
VBrush.Dispose();
this.ForeColor = oldcol; //前景色を元に戻す
}
}
/////////////////////
//日付入力ダイアログ
/////////////////////
class DateDialog : Form
{
//日付出力用DateTImeクラスオブジェクト
private DateTime _date;
public DateTime date
{
get
{
return _date;
}
}
string message; //ダイアログ表示メッセージ
ComboBox yyList, mmList, ddList; //年月日入力用コンボボックス
Button OkBtn, CancelBtn; //ボタンコントロール
public DateDialog(string str)
{
//メッセージを記録
message = str;
// ダイアログボックス用の設定
this.Text = "日付入力";
this.MaximizeBox = false; //最大化ボタン
this.MinimizeBox = false; //最小化ボタン
this.FormBorderStyle = FormBorderStyle.FixedDialog; //境界のスタイル
this.StartPosition = FormStartPosition.CenterParent; // 親フォームの中央に配置
this.Size = new Size(240, 200);
this.Load += Dlg_Load;
this.AcceptButton = OkBtn; // Enter キーで選択できるボタン
this.CancelButton = CancelBtn; // Esc キーで選択できるボタン
}
private void Dlg_Load(object sender, EventArgs e)
{
//メッセージラベル
Label label = new Label();
label.Location = new Point(10, 10);
label.AutoSize = true;
label.Text = message;
this.Controls.Add(label);
//コンボボックス(yyList)
Label yylabel = new Label();
yylabel.Location = new Point(10, label.Height + 20);
yylabel.AutoSize = true;
yylabel.Text = "年(西暦)";
this.Controls.Add(yylabel);
yyList = new ComboBox();
yyList.Location = new Point(yylabel.Width + 20, label.Height + 20);
for(int i = DateTime.Today.Year; i >= 1923; i--) //100年分リスト
{
yyList.Items.Add(i.ToString("D4"));
}
this.Controls.Add(yyList);
//コンボボックス(mmList)
Label mmlabel = new Label();
mmlabel.Location = new Point(10, label.Height + yylabel.Height + 30);
mmlabel.AutoSize = true;
mmlabel.Text = "月";
this.Controls.Add(mmlabel);
mmList = new ComboBox();
mmList.Location = new Point(yylabel.Width + 20, label.Height + yyList.Height + 30);
for(int i = 1; i <= 12; i++) //12月 分リスト
{
mmList.Items.Add(i.ToString("D2"));
}
this.Controls.Add(mmList);
//コンボボックス(ddList)
Label ddlabel = new Label();
ddlabel.Location = new Point(10, label.Height + yylabel.Height + mmlabel.Height + 40);
ddlabel.AutoSize = true;
ddlabel.Text = "日";
this.Controls.Add(ddlabel);
ddList = new ComboBox();
ddList.Location = new Point(yylabel.Width + 20, label.Height + yyList.Height + mmList.Height + 40);
for(int i = 1; i <= 31; i++) //31日分リスト
{
ddList.Items.Add(i.ToString("D2"));
}
this.Controls.Add(ddList);
//Cancelボタン
CancelBtn = new Button();
CancelBtn.Location = new Point(10, ClientSize.Height - CancelBtn.Height - 10);
CancelBtn.Text = "Cancel";
CancelBtn.AutoSize = true;
CancelBtn.Click += CancelButton_Click;
this.Controls.Add(CancelBtn);
//OKボタン
OkBtn = new Button();
OkBtn.Location = new Point(ClientSize.Width - OkBtn.Width - 10, ClientSize.Height - OkBtn.Height - 10);
OkBtn.Text = "OK";
OkBtn.AutoSize = true;
OkBtn.Click += OkButton_Click;
this.Controls.Add(OkBtn);
}
private void OkButton_Click(object sender, EventArgs e)
{
//OKボタン
try
{
_date = DateTime.Parse(yyList.Text + "/" + mmList.Text + "/" + ddList.Text);
//_date = DateTime.Parse(yyList.SelectedItem.ToString() + "/" + mmList.SelectedItem.ToString() + "/" + ddList.SelectedItem.ToString());
}
catch
{
MessageBox.Show("選択された日付が不正です", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
this.DialogResult = DialogResult.None; // Meaning false
this.Close();
return;
}
this.DialogResult = DialogResult.OK; // Meaning true
this.Close();
}
private void CancelButton_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel; // Meaning true
this.Close();
}
}
}
【Biorythm.opt】
[Compile Option]
Target=3
Resource=0
RscFile=
IconFile=
DbgOpt=0
WarnErr=5
Others=











