2017年2月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28        

Amazonウィジェット

  • miniPC
  • 最近買った本
  • Raspberry Pi
  • クアッドコプター
  • 書籍ランキング

AdSense

  • 広告
無料ブログはココログ

C#

2016年12月 4日 (日)

C# イベントを発生させる続編 イベントを使って値を受け渡しする

C#のフォームアプリケーションを作っていると、描画の更新などイベントを使わなければ回りくどかったり、難しい場合がある。イベントを使いこなせても、今度は値を渡したいとか、どこで発生したイベントかを知らせたり、渡した値でハンドラの振る舞いを変えたいとかいろいろ出てくる。

イベントに値を追加して、イベントハンドラでその値を受け取らせたい場合は、クラスを作ってそれを入れ物として値を受け渡せばよい。じつはそういう例がMouseイベントでも見られる。マウスMoveはEventArgsではなく、マウスの座標をイベントオブジェクトの中に入れ込んだMouseEventArgsという型をやり取りしている。

MouseEventArgsをMSDNを調べてみると、EventArgsというクラスを継承して作られていることがわかる。

https://msdn.microsoft.com/ja-jp/library/system.windows.forms.mouseeventargs(v=vs.110).aspx

つまり、これと同様にしてEventArgsを継承したクラスを用意し、そのクラスに好きな値を持たせればよいことになる。

※マウスイベントの試し方:pictureBoxやパネルの中にあるマウス系イベントのMouseMoveイベントを、フォームデザイナのプロパティで設定してみると、MouseEventHandlerというハンドラが追加されることがわかる。

※手順:pictureBoxをフォームに追加して、プロパティ画面の雷マークを押すと、イベントのプロパティが現れる。この中に、マウスという項目がある。このなかのMouseDownという項目の右をダブルクリックすると、pictureBox1_MouseDownという関数がフォームデザイナでForm内に自動的に追加される。

//色が変化したときにイベントで飛ばすプロパティを入れたクラス
    class ColorEventArgs : EventArgs
    {
        Color c;
        public ColorEventArgs(Color c)
        {
            this.c = c;
        }
        public Color color
        {
            get { return c; }
        }
    }

上記入れ物をイベントに載せて飛ばすためには、
・その型を持ったイベントの宣言
・その型を持ったオブジェクトを受けられるデリゲートの宣言
の2つが必要。

        //イベント
        public event ColorEventHandler CurrentColorChange;

        //ColorEventArgs型のオブジェクトを返すようにする
        public delegate void ColorEventHandler(object sender, ColorEventArgs e);

デリゲートに、イベントが発生したときにやってほしい関数を渡すのを忘れずに。

//イベントで処理する関数を登録
          ceditor.CurrentColorChange += new ColorEditor.ColorEventHandler(this.currentColorChanged);

イベントを発生させるには

        public void setCurrentColor(Color c)
        {
            currentColor = c;
            if (CurrentColorChange != null)
            {
                CurrentColorChange(this, new ColorEventArgs(currentColor));
            }
        }

という風にして、先ほどのイベントを関数のようにして呼ぶ。 そのときに引数として先ほど作ったデータの入れ物型のオブジェクトを作って渡す。

すると、イベントハンドラ先で入れ物を受け取り、そのなかのメンバにアクセスして データを取り出すことができる。この中には、イベントの送り先とかデータを何でも入れられる。 これによりどこが発生させたイベントかを判別することで振る舞いを変えたりできる。

イベントハンドラはこんな風にかける。

        private void currentColorChanged(object sender, ColorEventArgs e)
        {
            colorNum_t num = e.color;
        }

ちなみに、他のイベントハンドラと共用で使いたい場合は、一旦基底クラスのEventArgsで受けておいて、 ほしいクラスのキャストをしてやってもよい。

        private void currentColorChanged(object sender, EventArgs e)
        {
            colorNum_t num = ((ColorEventArgs)e).getColorNum();
        }

イベントを使うとかなり色々なことが出来るようになった気になるが、あまり使いすぎたりあちこちからイベントを発生させたりすると、プログラムの流れが全く読めなくなって困る。

2016年11月13日 (日)

C# イベントを発生させる方法

イベントを発生させる方法。
別スレッドに処理をさせている間に、なにか問題があったときに報告させたり、グラフィックの再描画が必要なタイミングをイベントから知るようにするときに使う。
コンソールアプリで実行できる簡単な例を記載。

メインループでは最初にYobidashiというクラスのインスタンスを作ってstartメソッドを呼び出す。あとはreadlineで入力待ちのため何もしない。

Yobidashiのstartでは、SleepClassが作られて、SleepClassの持つイベントにイベントハンドラが登録される。SleepClassのオブジェクトがStartを呼んだあとは、Startメソッドのなかで3秒間待つ。3秒たったらTime(this,EventArgs.Empty)が実行されて、ここでイベントが発行される。

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace CS_eventTameshi
{
    class Program
    {
        static void Main(string[] args)
        {
            Yobidashi y = new Yobidashi();
            y.start();

            Console.ReadLine();
        }
    }

    class Yobidashi
    {
        public void start()
        {
            SleepClass clsSleep = new SleepClass();

            //イベントハンドラの追加
            clsSleep.Time += new EventHandler(this.SleepClass_Time);
            clsSleep.Start();
        }

        private void SleepClass_Time(object sender, System.EventArgs e)
        {
            //起動してから3秒後におkが表示される。エンター押すと終了
            Console.WriteLine("ok!");
        }
    }
    

    class SleepClass
    {
        public event EventHandler Time;

        public void Start()
        {
            System.Threading.Thread.Sleep(3000);
            if (Time != null)
            {
                Time(this, EventArgs.Empty);
            }
        }

        
    }
}

<自分の勝手な理解>
イベントにイベントハンドラをセットするのは、 C言語で言うところの、関数ポインタをセットしておくのに似ている。

+=という操作をすると、そこで指定した関数へのポインタがセットされる。 イベントを発生させる側で、イベントの関数を実行すると、 その中にセットされていたイベントハンドラへのポインタがロードされて、 今度はそれが実行されるようになる。

そのために、例示したソースの中で
if (Time != null)

というのがあるが、これはeventに何も入っていなければそこへ飛びようがないので、 中身がなければ処理しないということ。

2016年11月 6日 (日)

C# 図形の塗りつぶし色の変え方

C# Csharp グラフィック 塗りつぶし四角形の色の変え方。システム色以外のRGBによる設定

MSDNのドキュメントはどれもすさまじい日本語で、英語の原文を読んだほうがよほどましな気がした。キーワード検索すると必ず日本語のページが出てくるので、最後にenglishを入れて検索する。

Rectangle構造体 これはあくまでも構造体のようで、描画をするためのものではない。
サイズを指定するようなもの
https://msdn.microsoft.com/ja-jp/library/system.drawing.rectangle(v=vs.110).aspx

上のページから、備考の欄にFillRectangleメソッドへのリンクが貼ってある。
https://msdn.microsoft.com/ja-jp/library/yysstebh(v=vs.110).aspx

このページの構文のところで
BrushとRectangleを引数として受け取るということがわかる。

Brushのリンクを辿ると、
https://msdn.microsoft.com/ja-jp/library/system.drawing.brush(v=vs.110).aspx
四角形、楕円、扇形、多角形、およびパスなどのグラフィカル形状の内部を塗りつぶすに使用されるオブジェクトを定義します。
とあるが、abstractがついているのでこのままではオブジェクトを作れない。
このクラスを継承しているクラスが他にあるということ。

解説のところに、
これは抽象基本クラスであり、インスタンス化することはできません。 Brush オブジェクトを作成するから派生したクラスを使用して Brush, など SolidBrush, 、TextureBrush, 、および LinearGradientBrushです。
ということが書かれているので、SolidBrushのリンクを辿ってみた。

すると、ようやくやりたいことが見えてきた。
https://msdn.microsoft.com/ja-jp/library/system.drawing.solidbrush(v=vs.110).aspx

この中の例をみると、
Color customColor = Color.FromArgb(50, Color.Gray);
SolidBrush shadowBrush = new SolidBrush(customColor);

となっていたので、
Color.FromArgb
とVisualStudio内で打ち込んでみて、Intelisenseで表示される、
RGBをint値でそれぞれ指定するメソッドを選べばいいことがわかった。

最終的にコードはこんな風になった。

SolidBrush brush = new SolidBrush(Color.FromArgb(150,0,30));
g.FillRectangle(brush, 0,0,100,100);

SolidBrushにColorを渡してまずはブラシをつくり、
それを図形を描画するメソッドに渡せば、その色で塗りつぶしが実行できるということ。