C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[26]: パネルコントロールに配置したラベルのクリックイベントの取得


(過去ログ 60 を表示中)

[トピック内 34 記事 (1 - 20 表示)]  << 0 | 1 >>

■34467 / inTopicNo.1)  パネルコントロールに配置したラベルのクリックイベントの取得
  
□投稿者/ tamaboyo (74回)-(2009/03/30(Mon) 20:21:05)

分類:[C#] 

boyotamaです。

フォームにパネルコントロールを配置し、そのパネル上にラベルを配置しています。
ラベルは数が多いので、配列型で宣言し、ラベルの実体はnewで作成しています。

実体を作成後、Panel1.Controls.AddRange(this.Lb)で、パネルに追加したのですが、
パネルに追加するとラベルのクリックイベントが取れなくなりました。
for (i = 0; i < this.Lb.Length; i++)
{
//インスタンス作成
this.Lb[i] = new System.Windows.Forms.Label();
//イベントハンドラに関連付け
this.Lb[i].Click += new EventHandler(this.LB_Click);
}
今は上記のように実体の宣言、イベントの関連付けをしています。
Controls.AddRange(this.Lb)だとクリックイベントは取得できます。
パネルにコントロールを追加した場合、追加したコントロールのクリックイベントはとれないのでしょうか?

環境はVS2005です。
宜しくお願いします。
引用返信 編集キー/
■34470 / inTopicNo.2)  Re[1]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ .SHO (777回)-(2009/03/30(Mon) 20:39:49)
No34467 (tamaboyo さん) に返信

> パネルにコントロールを追加した場合、追加したコントロールのクリックイベントはとれないのでしょうか?

取れます。
問題は他にあると思います。
引用返信 編集キー/
■34472 / inTopicNo.3)  Re[2]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (75回)-(2009/03/30(Mon) 21:11:09)
.SHO さん、ありがとうございます。

>>パネルにコントロールを追加した場合、追加したコントロールのクリックイベントはとれないのでしょうか?
>
> 取れます。
> 問題は他にあると思います。

実体を宣言する前に追加を行うと、コンパイルは通るのですが、ラベルは表示されませんでした。
#パネルの下に入り込んだ様です。
実体の宣言時にラベルに付けていたthisを外してみましたが、状況は変わりませんでした。

また、イベントハンドラの関連付の宣言をし直す際に、自動でつくられる関数を利用してもイベント関数には飛んできませんでした。
パネルコントロールのクリックイベントから取得しないといけないのでしょうか?
引用返信 編集キー/
■34484 / inTopicNo.4)  Re[3]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ よねKEN (304回)-(2009/03/31(Tue) 09:43:51)
No34472 (tamaboyo さん) に返信
> 実体を宣言する前に追加を行うと、コンパイルは通るのですが、ラベルは表示されませんでした。

"実体を宣言する前に追加を行う"というのは、
"ラベルのインスタンス生成を行う前にパネルにそのラベル用の変数を追加する"、という意味でしょうか?
日本語ではわかりにくいので擬似コードで書くと以下のような感じでしょうか?

//以下はC#風の擬似コード。あくまで説明用です。
Label label1 = null;
Panel1.Controls.Add(label1); //← "実体を宣言する前に追加を行う"
label1 = new Label()

こういう意味であれば、表示されないのは当然の結果ですね。
元のコードで言うと、
Panel1.Controls.AddRange(this.Lb)
とする際に配列Lbの個々の要素がnullなので何も追加していないということになりますから。
(nullを追加したら例外が起きそうな気もしますが、私は未確認です。)

> #パネルの下に入り込んだ様です。

説明通りであれば、パネルの下に入り込んだわけではないはずです。

> 実体の宣言時にラベルに付けていたthisを外してみましたが、状況は変わりませんでした。

「ラベルに付けていたthis」を外すの意味がわかりません。

> また、イベントハンドラの関連付の宣言をし直す際に、自動でつくられる関数を利用してもイベント関数には飛んできませんでした。
> パネルコントロールのクリックイベントから取得しないといけないのでしょうか?

作成されたソースコードを見ていない状態でこの説明では理解できないので、
該当箇所の実際のソースコードを提示してください。
(■34467 で提示されているソースコードも実際のソースコードでは、重要な部分が端折られていてアドバイスが難しいです。)
引用返信 編集キー/
■34491 / inTopicNo.5)  Re[4]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (76回)-(2009/03/31(Tue) 10:39:02)
よねKEN さん、ありがとうございます。

>>実体を宣言する前に追加を行うと、コンパイルは通るのですが、ラベルは表示されませんでした。
>
> "ラベルのインスタンス生成を行う前にパネルにそのラベル用の変数を追加する"、という意味でしょうか?
> こういう意味であれば、表示されないのは当然の結果ですね。
> 元のコードで言うと、
> Panel1.Controls.AddRange(this.Lb)
> とする際に配列Lbの個々の要素がnullなので何も追加していないということになりますから。
> (nullを追加したら例外が起きそうな気もしますが、私は未確認です。)

はい、このような流れのコードを記載して試したところ、表示されませんでした。
コンパイルも通り、例外は発生していませんでした。


>>#パネルの下に入り込んだ様です。
>
> 説明通りであれば、パネルの下に入り込んだわけではないはずです。

見えていないので入り込んだと思っていましたが、違ったのですね。
納得です。


>>実体の宣言時にラベルに付けていたthisを外してみましたが、状況は変わりませんでした。
>
> 「ラベルに付けていたthis」を外すの意味がわかりません。

Lbの前にthisを付けて、this.Lbでコードを記載していました。
これだと、フォーム上のLbという意味になると思ったのではずしてみました。


> 作成されたソースコードを見ていない状態でこの説明では理解できないので、
> 該当箇所の実際のソースコードを提示してください。
> (■34467 で提示されているソースコードも実際のソースコードでは、重要な部分が端折られていてアドバイスが難しいです。)

配列の宣言は、関数の外で行っています。
protected System.Windows.Forms.Label[] Lb;
実体の作成は、作成用の関数を作成し、その中で行っています。
Lb = new System.Windows.Forms.Label[64];
for (i = 0; i < Lb.Length; i++)
{
//インスタンス作成
Lb[i] = new System.Windows.Forms.Label();
//プロパティ設定
Lb[i].Name = "Lb" + i.ToString();
Lb[i].Size = new Size(29, 36);
Lb[i].Location = new Point(i * 30, 10);
Lb[i].Visible = true;
//イベントハンドラに関連付け
Lb[i].Click += new EventHandler(this.LB_Click);
}
//フォームにコントロールを追加
Panel1.Controls.AddRange(Lb);
以上が、実際のソースです。
Panel1.Controls.AddRange(Lb);をControls.AddRange(Lb);に変更するとイベントは取得できます。
引用返信 編集キー/
■34495 / inTopicNo.6)  Re[5]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ よねKEN (305回)-(2009/03/31(Tue) 11:09:12)
2009/03/31(Tue) 11:14:31 編集(投稿者)

途中で誤って送信してしまったようなので、
こちらは削除して、次の投稿で書き直します。
引用返信 編集キー/
■34496 / inTopicNo.7)  Re[5]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ よねKEN (306回)-(2009/03/31(Tue) 11:13:24)
No34491 (tamaboyo さん) に返信
> >>実体の宣言時にラベルに付けていたthisを外してみましたが、状況は変わりませんでした。
>>
>>「ラベルに付けていたthis」を外すの意味がわかりません。
>
> Lbの前にthisを付けて、this.Lbでコードを記載していました。

そういうことであれば、Lbはラベルを参照するためのただの変数ですから、無関係ですね。

> これだと、フォーム上のLbという意味になると思ったのではずしてみました。

フォーム上か、パネル上かを決めるのは、あくまで、フォーム/パネルのControls.Addによる追加作業です。

> 配列の宣言は、関数の外で行っています。
> protected System.Windows.Forms.Label[] Lb;
> 実体の作成は、作成用の関数を作成し、その中で行っています。
> Lb = new System.Windows.Forms.Label[64];
> for (i = 0; i < Lb.Length; i++)
> {
> //インスタンス作成
> Lb[i] = new System.Windows.Forms.Label();
> //プロパティ設定
> Lb[i].Name = "Lb" + i.ToString();
> Lb[i].Size = new Size(29, 36);
> Lb[i].Location = new Point(i * 30, 10);
> Lb[i].Visible = true;
> //イベントハンドラに関連付け
> Lb[i].Click += new EventHandler(this.LB_Click);
> }
> //フォームにコントロールを追加
> Panel1.Controls.AddRange(Lb);
> 以上が、実際のソースです。

変数iが宣言されていませんので、関連するソースコードを正確には抜き出せていないようです。
それと、各ラベルにTextプロパティを設定している箇所もありません。
本当にこの通りのソースコードなんですか?
これだとラベルを視認できないので、Clickイベントが正しく動作するかどうかの確認自体ができないと思います。
(ちなみにAutoSizeプロパティをfalseに設定するコードもないようなので、
このままだとSizeプロパティの設定はあまり意味がありません。)

このコードをどこから呼び出しているのか?フォーム上に配置しているコントロールの構成などの
情報も合わせて、動作検証可能なソースコードを提示された方がよいと思います。

引用返信 編集キー/
■34500 / inTopicNo.8)  Re[6]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (77回)-(2009/03/31(Tue) 13:04:53)
よねKEN さん、ありがとうございます。

> 変数iが宣言されていませんので、関連するソースコードを正確には抜き出せていないようです。
> それと、各ラベルにTextプロパティを設定している箇所もありません。
> 本当にこの通りのソースコードなんですか?
> これだとラベルを視認できないので、Clickイベントが正しく動作するかどうかの確認自体ができないと思います。

すみません。iの宣言が抜けていました。
iは、
関数の頭で
int i = 0;
で宣言しています。
また、このラベルには文字列は表記しません。
コピーの際に抜けてしまっているのですが、
forの中で
Lb[i].BackColor = Color.Gray;
を記載しており、色つきのラベルを複数表示させるのが目的です。


> (ちなみにAutoSizeプロパティをfalseに設定するコードもないようなので、
> このままだとSizeプロパティの設定はあまり意味がありません。)

このあと、SetBoundsを使用して、ラベル位置の補正を行っています。
Textを表示しないのと、SetBoundsで指定し直しているので、AutoSizeの設定は必要ないかと思っていました。


> このコードをどこから呼び出しているのか?フォーム上に配置しているコントロールの構成などの
> 情報も合わせて、動作検証可能なソースコードを提示された方がよいと思います。

フォームには、はじめパネルとボタンコントロールを配置しています。
フォームを表示する際に、関数Contorol_Loadでラベルを作成し、パネルの上に表示しようとしています。
パネルを載せているフォームは、他のフォーム(親)から呼び出しを行うため、関数Contorol_Loadは、
親フォームでフォームの宣言をした後に呼ぶようにしています。
Contorol_Loadを抜けた後、フォームはShowDialogで親フォームから表示しています。
Contorol_Loadへはラベルの作成個数等の情報を引数で渡していますが、今はデバッグのため、引数は無視して、配列数は64で固定で動かしています。
public void Contorol_Load(int nMax)
{
int i = 0;

this.SuspendLayout();

Lb = new System.Windows.Forms.Label[64];
for (i = 0; i < Bit.Length; i++)
{
//インスタンス作成
Lb[i] = new System.Windows.Forms.Label();
//プロパティ設定
Lb[i].Name = "Bit" + i.ToString();
Lb[i].Size = new Size(29, 36);
Lb[i].Location = new Point(i * 30, 10);
Lb[i].Visible = true;
Lb[i].BackColor = Color.Gray;
//イベントハンドラに関連付け
Lb[i].Click += new EventHandler(this.LB_Click);
}

//フォームにコントロールを追加
Panel1.Controls.AddRange(Lb);
}
引用返信 編集キー/
■34508 / inTopicNo.9)  Re[7]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ 魔界の仮面弁士 (1023回)-(2009/03/31(Tue) 14:41:24)
No34500 (tamaboyo さん) に返信
>>(ちなみにAutoSizeプロパティをfalseに設定するコードもないようなので、
>>このままだとSizeプロパティの設定はあまり意味がありません。)

AutoSize プロパティの規定値は false のようなので、設定せずとも大丈夫かも。
(デザイナから貼りつけた場合は、最初に true に編集されるというだけで)


> public void Contorol_Load(int nMax) 
基本的には、それで問題ないと思います。下記に示すような問題はありましたが、
当方環境でパネルに登録され、Click イベントにも反応することを確認できましたし。

------------

>     int i = 0;
ループカウンタ変数のスコープを出来る限り短くするためにも、
 int i;
 for (i = 0; i < length; i++) { ・・・ }
の構文では無く、
 for (int i = 0; i < length; i++) { ・・・ }
の構文を利用されることをお奨めします。


>     this.SuspendLayout();
対応する ResumeLayout が書かれていないようです。


>     Lb = new System.Windows.Forms.Label[64];
>     for (i = 0; i < Bit.Length; i++)
>     {
>         //インスタンス作成
>         Lb[i] = new System.Windows.Forms.Label();

デバッグのため、配列変数 Lb の要素数を 64固定にしているのは分かりますが、
その後のループ条件が、「i < 64」や「i < Lb.Length」ではなく、
「i < Bit.Length」にしているのは何故でしょうか?
最初のコードでは、Lb.Length を使っていましたよね。

もし、Bit.Length が 0 だとしたら、Lb[] の各要素はすべて null であるため、
ラベルが追加される事は無いかと思います。


>         //フォームにコントロールを追加
>         Panel1.Controls.AddRange(Lb);
C# の開発環境では、パネル名の規定値は「Panel1」ではなく「panel1」かと。

引用返信 編集キー/
■34509 / inTopicNo.10)  Re[7]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ よねKEN (307回)-(2009/03/31(Tue) 14:52:43)
提示のコードをもとに私の方で試してみましたが、ラベルのクリックイベントは普通に起きました。

私の方で手を加えたのは以下のあたりだけです。
○Form1の作成
・新規にWindows Formsのプロジェクトを作成した。
・Form1にはパネルを追加した。(デフォルト名はpanel1なのでPanel1に修正した)
・Lbの定義が提示のコードにはないので、適当に追加した。
・Bit.Lengthは定義が存在しないため、とりあえず64固定にした。
○呼び出し側
 Form1 f = new Form1();
 f.Contorol_Load(1);  // 引数の1は適当
 f.Show();

-- 以下はその実験コードのうち、Form1の部分のみ--

public partial class Form1 : Form
{
    private Label[] Lb;
    public Form1()
    {
        InitializeComponent();
    }

    public void Contorol_Load(int nMax)
    {
        int i = 0;

        this.SuspendLayout();

        Lb = new System.Windows.Forms.Label[64];
        for (i = 0; i < 64; i++)
        {
            //インスタンス作成
            Lb[i] = new System.Windows.Forms.Label();
            //プロパティ設定
            Lb[i].Name = "Bit" + i.ToString();
            Lb[i].Size = new Size(29, 36);
            Lb[i].Location = new Point(i * 30, 10);
            Lb[i].Visible = true;
            Lb[i].BackColor = Color.Gray;
            //イベントハンドラに関連付け
            Lb[i].Click += new EventHandler(this.LB_Click);
        }

        //フォームにコントロールを追加
        Panel1.Controls.AddRange(Lb);
    }

    private void LB_Click(object sender, EventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("LB_Click");
    }
}


引用返信 編集キー/
■34510 / inTopicNo.11)  Re[8]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ よねKEN (308回)-(2009/03/31(Tue) 15:03:02)
No34508 (魔界の仮面弁士 さん) に返信
> ■No34500 (tamaboyo さん) に返信
> >>(ちなみにAutoSizeプロパティをfalseに設定するコードもないようなので、
> >>このままだとSizeプロパティの設定はあまり意味がありません。)
> 
> AutoSize プロパティの規定値は false のようなので、設定せずとも大丈夫かも。
> (デザイナから貼りつけた場合は、最初に true に編集されるというだけで)

あれ?そうでしたっけ?

Label.AutoSizeプロパティ
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.label.autosize.aspx

には既定値 trueと書かれているので、trueだとばかり信じてました。
以下で試したら確かにfalseが返ってきましたorz

class Test
{
	static void Main()
	{
		System.Console.WriteLine(new System.Windows.Forms.Label().AutoSize);
	}
}

引用返信 編集キー/
■34513 / inTopicNo.12)  Re[6]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (78回)-(2009/03/31(Tue) 15:46:44)
魔界の仮面弁士さん、よねKEN さん、ありがとうございます。

投稿してから、いらない部分を消し、コードを整理したところ、イベントが取れるようになりました。
特に追加したり、削除したコードはないのですが、引数を統一&まとめたたことで上手くまくいくようになりました。
いろいろ試してる途中で、値が混在してしまっていたようです。
また、ソースの貼り付けもあちこち異なっていたようで申し訳ありません。
お手数をおかけしましたが、解決できたようです。
ありがとうございました。


ただ、次の問題が発生しました。
重ねての質問になりますが、よろしくお願いします。
パネルコントロールにラベルを配置した場合、このフォームを元にして作成した新しいフォームでのラベルのクリックイベントは取れなくなりました。
元になるクリックイベントは
protected virtual void LB_Click(object sender, EventArgs e)
新しいフォームのラベルのクリックイベントは
protected override void LB_Click(object sender, EventArgs e)
としています。
ラベルをパネルに追加しない場合は、ラベルをクリックすると、新しいフォームのLB_Clickイベントに飛んできていました。
この場合、新しいフォーム側で、ラベルのクリックイベントについて、改めて設定してあげないといけないのかと思い、新しいフォームのContorol_Load関数で追加してみたのですが、イベントは飛んできませんでした。
また、Designer.cs上でpanelの宣言がinternalだから?と思いprotectedに変更してみたのですが、変わりませんでした。
#Designer.csって、簡単に触って良いものなのか不安ですが・・・

基本フォームと新しいフォームの違いは、関数の中身が異なるものがいくつかありますが、
使用コントロールは全く同じものです。
中身が異なる関数は、virtual、override宣言しています。

宜しくお願いします。
引用返信 編集キー/
■34516 / inTopicNo.13)  Re[9]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ 魔界の仮面弁士 (1025回)-(2009/03/31(Tue) 16:09:01)
No34510 (よねKEN さん) に返信
> には既定値 trueと書かれているので、trueだとばかり信じてました。
> 以下で試したら確かにfalseが返ってきましたorz

AutoSize の DefaultValue 属性は false に設定されています。

デザイナに貼り付けると true が初期値として設定されるのですが、規定値は false であるため、
プロパティ グリッド上では、AutoSize の値が「太字」で書かれている事がわかるかと思います。
引用返信 編集キー/
■34518 / inTopicNo.14)  Re[7]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ 魔界の仮面弁士 (1026回)-(2009/03/31(Tue) 16:18:17)
2009/03/31(Tue) 16:20:36 編集(投稿者)

No34513 (tamaboyo さん) に返信
> 投稿してから、いらない部分を消し、コードを整理したところ、イベントが取れるようになりました。
うまくいかなかった理由は、その「いらない部分」にあったという事でしょうかね。
(できれば、何故うまくいかなかったのか、その理由を知りたいところですが…)

> このフォームを元にして作成した新しいフォームでの
継承フォームという事ですね。

> ラベルのクリックイベント
イベントを受け取る LB_Click メソッドは、継承元と継承先、どちらに用意してありますか?
また、それを Label の Click イベントへと割り当てる作業は、継承元と継承先の
どちらから行っていますか?

> ラベルのクリックイベントについて、改めて設定してあげないといけないのかと
デザイナで設定できるようにするなら、その継承フォームに「ラベルをクリックしたときのイベント」として、
例えば「public event EventHandler LabelClick;」および、それに対応する
プロテクトメソッド(例: OnLabelClick) は用意しておくと良いかも知れません。

> #Designer.csって、簡単に触って良いものなのか不安ですが・・・
開発環境が、.designer.cs を修正する事があるため、一部の設定は失われる事があります。
そうした点を理解した上で触る分には問題無いかと思います。(私は触りませんが)
引用返信 編集キー/
■34520 / inTopicNo.15)  Re[8]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (79回)-(2009/03/31(Tue) 16:52:06)
魔界の仮面弁士 さん、ありがとうございます

>>投稿してから、いらない部分を消し、コードを整理したところ、イベントが取れるようになりました。
> うまくいかなかった理由は、その「いらない部分」にあったという事でしょうかね。
> (できれば、何故うまくいかなかったのか、その理由を知りたいところですが…)

どうも、デバッグ用に固定値を入れていたタイミングが悪かったのが事の始まりだったようです。
また、デバッグ用に固定値を使うために元々使っていた変数を一時的にコメントにしたため、
その変更を行った時に余計なことをしていたようです。
一度コメントを元に戻し、値を引数から渡すようにしたところ、うまくいきました。


>>ラベルのクリックイベント
> イベントを受け取る LB_Click メソッドは、継承元と継承先、どちらに用意してありますか?

LB_Click関数は、継承元、継承先、どちらにもあります。
継承元はprotected virtual、継承先はprotected overrideで宣言を付加しています。


> また、それを Label の Click イベントへと割り当てる作業は、継承元と継承先の
> どちらから行っていますか?

これは、継承元で行っています。
上記でLbの宣言を行っていた部分は、1つの関数Arrangeとして継承元でまとめ、それを継承元のControl_Loadから呼び出す形に変更しました。
#この変更は、動くことを確認済です。
Arrange関数は継承先では必要ないので、継承先には作成していません。
継承先のContorol_LoadからArrangeを呼び出し、ラベルが表示されるところまでは確認しています。
ただ、イベントは・・・取れません。


>>ラベルのクリックイベントについて、改めて設定してあげないといけないのかと
> デザイナで設定できるようにするなら、その継承フォームに「ラベルをクリックしたときのイベント」として、
> 例えば「public event EventHandler LabelClick;」および、それに対応する
> プロテクトメソッド(例: OnLabelClick) は用意しておくと良いかも知れません。

継承元では、
public event EventHandler LbClicked;
protected virtual void OnLbClicked(object sender, EventArgs e)
{
if (LbClicked != null)
{
LbClicked(this, e);
}
}
継承先では、
public new event EventHandler LbClicked;
protected override void OnLbClicked(object sender, EventArgs e)
{
if (LbClicked != null)
{
LbClicked(this, e);
}
}
の宣言はしています。
試しに、両方をコメントにしてみたりしたのですが、イベントは飛んできませんんでした。

>>#Designer.csって、簡単に触って良いものなのか不安ですが・・・
> 開発環境が、.designer.cs を修正する事があるため、一部の設定は失われる事があります。
> そうした点を理解した上で触る分には問題無いかと思います。(私は触りませんが)

とりあえず、動作に変わりがないので、元に戻しました。
パネルコントロールの宣言はinternalです。
引用返信 編集キー/
■34530 / inTopicNo.16)  Re[9]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ 魔界の仮面弁士 (1027回)-(2009/03/31(Tue) 21:27:17)
No34520 (tamaboyo さん) に返信
>>> ラベルのクリックイベント
>> イベントを受け取る LB_Click メソッドは、継承元と継承先、どちらに用意してありますか?
> LB_Click関数は、継承元、継承先、どちらにもあります。
> 継承元はprotected virtual、継承先はprotected overrideで宣言を付加しています。
>
>>また、それを Label の Click イベントへと割り当てる作業は、継承元と継承先の
>>どちらから行っていますか?
> これは、継承元で行っています。

と言う事は、継承元が割り当てているのは、「継承元の proteced virtual の方」ですね。


> 上記でLbの宣言を行っていた部分は、1つの関数Arrangeとして継承元でまとめ、それを継承元のControl_Loadから呼び出す形に変更しました。
継承元の Arrange メソッドを、継承元自身の Control_Load から呼び出すという点は分かりましたが、
その前の、Lb(配列型のフィールド変数)を、Arrange 関数にまとめる…という部分が良く分かりません。
どのようなコードに変更されたのでしょうか?


> 継承元では、
> public event EventHandler LbClicked;
> protected virtual void OnLbClicked(object sender, EventArgs e)
イベントを実装する場合、対応する OnEventName メソッドには sender を渡しません。
sender はフォーム自身なので、あえて引数に渡す必要が無いためです。

すなわち、EventArgsまたはその継承クラスだけを受け取るように実装します。
フォームの OnLoad や OnFormClosing メソッドも、そうなっていますよね。

なお、イベントの利用側に、どのラベルをクリックしたかと言う情報を伝える必要が
ある場合には、それを EventArgs を継承させたクラスを使って渡すようにします。
(TreeView の AfterSelect イベントなどがそうであるように)


> 継承先では、
> public new event EventHandler LbClicked;
継承先で、イベントをシャドウイングしているようですが、それは何故ですか?

普段、Form を継承して Form1 クラスを作る際に、継承元の Load イベントを処理するためには
『public new event EventHandler Load;』と書いたりはしないかと思います。通常は、
「Load += 〜 でイベントを割り当てる」か、「OnLoad をオーバーライドする」ぐらいでしょう。

今回も同様で、特に理由が無ければ、同名イベントを再実装する必要は無いと思いますよ。


> protected override void OnLbClicked(object sender, EventArgs e)
必ずしもオーバーライドさせる必要は無いかと思いますが、オーバーライドさせるならば、
継承元のベースメソッドを呼びだすコードも含めておくべきかと。


> イベントは飛んできませんんでした。
そもそも、継承元フォームで LbClicked イベントを発生させていますか?

今回の実装だと、継承元側は Label の Click イベントを受け取ったときに、
OnLbClicked メソッドを呼び出す必要がありますよね。
引用返信 編集キー/
■34548 / inTopicNo.17)  Re[10]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ tamaboyo (80回)-(2009/04/01(Wed) 10:13:14)
魔界の仮面弁士 さん、ありがとうございます。

> 継承元の Arrange メソッドを、継承元自身の Control_Load から呼び出すという点は分かりましたが、
> その前の、Lb(配列型のフィールド変数)を、Arrange 関数にまとめる…という部分が良く分かりません。
> どのようなコードに変更されたのでしょうか?

以下のように、Lbの実体を宣言し、配置をし直すところをまとめて1つの関数にしました。
これを、Control_Loadから呼び出しています。
#継承元のControl_Loadからも継承先のControl_Loadからもこれを呼び出してLbの実態を作成しています。
protected void Arrange()
{
int nMidLb = 0;
int nWidth = 0;
//隣の間の隙間を含むサイズ
int nMid = 0;
int nLeft = 0;

this.SuspendLayout();

//コントロール配列の作成
Lb = new System.Windows.Forms.Label[m_Max];

//コントロールのインスタンス作成し、プロパティを設定する
for (int i = 0; i < Lb.Length; i++)
{
//インスタンス作成
Lb[i] = new System.Windows.Forms.Label();
//プロパティ設定
Lb[i].Name = "Lb" + i.ToString();
Lb[i].Size = new Size(29, 36);
Lb[i].Location = new Point(i * 30, 10);
Lb[i].Visible = true;
Lb[i].BackColor = Color.Gray;
//イベントハンドラに関連付け
Lb[i].Click += new EventHandler(this.LB_Click);
}
//フォームにコントロールを追加
Picture1.Controls.AddRange(this.Lb);

nMid = this.Width / 2 + 25;
//真中のINDEX取得
if (m_Max % 4 != 0)
{
nMidLb = (m_Max + 4 - (m_Max % 4)) / 2;
}
else
{
nMidLb = m_Max / 2;
}

nLeft = nMid;
//画面左部のイメージ整列
for (int i = nMidLb; i <= m_Max - 1; i++)
{
if (i % 4 == 0)
{
nLeft = (int)(nLeft - nWidth * 1.5);
}
else
{
nLeft = nLeft - nWidth;
}
Lb[i].SetBounds(nLeft, Lb[i].Top, nWidth - 3, Lb[i].Height);
}

if ((nMidLb % 4) == 0)
{
nLeft = (int)(nMid - nWidth * 1.5);
}
else
{
nLeft = nMid - nWidth;
}

//画面右部のイメージ整列
for (int i = nMidLb - 1; i >= 0; i += -1)
{
if ((i + 1) % 4 == 0)
{
nLeft = (int)(nLeft + nWidth * 1.5);
}
else
{
nLeft = nLeft + nWidth;
}
Lb[i].SetBounds(nLeft, Lb[i].Top, nWidth - 3, Lb[i].Height);
}

this.ResumeLayout(true);
}


>>継承元では、
>> public event EventHandler LbClicked;
>> protected virtual void OnLbClicked(object sender, EventArgs e)
> イベントを実装する場合、対応する OnEventName メソッドには sender を渡しません。
> sender はフォーム自身なので、あえて引数に渡す必要が無いためです。
>
> すなわち、EventArgsまたはその継承クラスだけを受け取るように実装します。
> フォームの OnLoad や OnFormClosing メソッドも、そうなっていますよね。
>
> なお、イベントの利用側に、どのラベルをクリックしたかと言う情報を伝える必要が
> ある場合には、それを EventArgs を継承させたクラスを使って渡すようにします。
> (TreeView の AfterSelect イベントなどがそうであるように)
>
>
>>継承先では、
>> public new event EventHandler LbClicked;
> 継承先で、イベントをシャドウイングしているようですが、それは何故ですか?
>
> 普段、Form を継承して Form1 クラスを作る際に、継承元の Load イベントを処理するためには
> 『public new event EventHandler Load;』と書いたりはしないかと思います。通常は、
> 「Load += 〜 でイベントを割り当てる」か、「OnLoad をオーバーライドする」ぐらいでしょう。
>
> 今回も同様で、特に理由が無ければ、同名イベントを再実装する必要は無いと思いますよ。

継承先にもLB_Clickがあるため、継承先は継承先で宣言が必要かと思っていました。
また、継承元、継承先にのLB_Clickの中で関数の最後に
if (LbClicked != null)
{
OnLbClicked(this, e);
}
の記述を入れているため、継承先にも宣言してないとエラーになってしまうこともあり、記述していました。


>> protected override void OnLbClicked(object sender, EventArgs e)
> 必ずしもオーバーライドさせる必要は無いかと思いますが、オーバーライドさせるならば、
> 継承元のベースメソッドを呼びだすコードも含めておくべきかと。

申し訳ないのですが、ここの意味が理解できませんでした。
継承先の宣言でnew eventで新しく割り付け直したつもりだったのですが、違うのでしょうか?


>>イベントは飛んできませんんでした。
> そもそも、継承元フォームで LbClicked イベントを発生させていますか?
>
> 今回の実装だと、継承元側は Label の Click イベントを受け取ったときに、
> OnLbClicked メソッドを呼び出す必要がありますよね。

Lbの実体を宣言する時に、イベントハンドラをLB_Clickにくくりつけているのですが、
LB_Click関数の最後に
if (LbClicked != null)
{
OnLbClicked(this, e);
}
を入れています。
引用返信 編集キー/
■34549 / inTopicNo.18)  Re[11]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ επιστημη (1862回)-(2009/04/01(Wed) 10:41:53)
επιστημη さんの Web サイト
> >>        protected override void OnLbClicked(object sender, EventArgs e)
>>必ずしもオーバーライドさせる必要は無いかと思いますが、オーバーライドさせるならば、
>>継承元のベースメソッドを呼びだすコードも含めておくべきかと。
> 
> 申し訳ないのですが、ここの意味が理解できませんでした。
> 継承先の宣言でnew eventで新しく割り付け直したつもりだったのですが、違うのでしょうか?

protected override void OnLbClicked(object sender, EventArgs e) {
    base.OnLbClicked(sender,e); // ←これ入れとけ、ってこっちゃないすか。
    // なんかする。 場合によっては base.... の前に。
}

引用返信 編集キー/
■34556 / inTopicNo.19)  Re[11]: パネルコントロールに配置したラベルのクリックイベントの取得
□投稿者/ 魔界の仮面弁士 (1030回)-(2009/04/01(Wed) 12:47:15)
2009/04/01(Wed) 12:58:15 編集(投稿者)

No34548 (tamaboyo さん) に返信
> for (int i = 0; i < Lb.Length; i++)
この時点では、『i < 最大値』という記述をしていて、
> for (int i = nMidLb; i <= m_Max - 1; i++)
ここでは『i <= 最大値 - 1』の記述法なのは何故でしょうか?

結果的には同じ事ですが、表記を統一した方がよろしいかと。


> 継承先にもLB_Clickがあるため、継承先は継承先で宣言が必要かと思っていました。
そもそも、継承元の LB_Click は継承先に見せる必要はないのですから、
private にしておけば十分だと思いますよ。
protected にするのは、OnLbClicked メソッドの方です。

また、継承先に用意するのは、Label.Click イベントを受け取るための LB_Click ではなく、
継承元フォーム.LbClicked イベントを受け取るための Form1_LbClicked になります。
(もっとも、イベントを受け取るメソッドの名前は、どんな名前でも構わないのですが)


すなわち、先の私の修正案とは:

継承先の LB_Click を、それぞれの Label.Click に直接割り当てるとなると、
継承元で動的生成された個々のラベルそれぞれに対して、継承先が、
 this.Controls[indexLabel].Click += LB_Click;
を行わねばならなくなってしまい、使い勝手が悪くなります。

そこで、個々のラベルに対してイベントを割り当てていくのでは無く、
複数のラベルからのイベントを一つに集約した独自イベントを作成し、継承先が
 this.LbClicked += Form1_LbClicked;
とするだけで、たとえば
 private void Form1_LbClicked(object sender, LbClickedEventArgs e)
 {
  Label label = e.Label;
 }
のようにして利用できるように設計した方が使い勝手がよいであろう……という話です。



No34549 (επιστημη さん) に返信
> base.OnLbClicked(sender,e); // ←これ入れとけ、ってこっちゃないすか。

ですます。フォローありがとうございます。
まぁ、今回はそもそも OnLbClicked を継承先で再実装すること自体が不要になりそうですけれども。
引用返信 編集キー/
■34563 / inTopicNo.20)  Re[12]: パネルコントロールに配置したラベルのクリックイベントの取得
 
□投稿者/ tamaboyo (81回)-(2009/04/01(Wed) 14:45:01)
魔界の仮面弁士 さん、επιστημη さん、ありがとうございます。

> 結果的には同じ事ですが、表記を統一した方がよろしいかと。

そうですね。
もう一度見直して、整理します。
ご指摘、ありがとうございます。


>>継承先にもLB_Clickがあるため、継承先は継承先で宣言が必要かと思っていました。
> そもそも、継承元の LB_Click は継承先に見せる必要はないのですから、
> private にしておけば十分だと思いますよ。
> protected にするのは、OnLbClicked メソッドの方です。

継承元と継承先に同じ名前の関数があり、どちらもラベルのクリックイベントで発生する場合で
virtualとoverrideを利用する場合は、protectedではないのでしょうか?
#説明を理解しきれてないのでしょうか?


> また、継承先に用意するのは、Label.Click イベントを受け取るための LB_Click ではなく、
> 継承元フォーム.LbClicked イベントを受け取るための Form1_LbClicked になります。
> (もっとも、イベントを受け取るメソッドの名前は、どんな名前でも構わないのですが)

この場合、継承元のLB_Clickのイベントはどうなるのでしょうか?


> すなわち、先の私の修正案とは:
>
> 継承先の LB_Click を、それぞれの Label.Click に直接割り当てるとなると、
> 継承元で動的生成された個々のラベルそれぞれに対して、継承先が、
>  this.Controls[indexLabel].Click += LB_Click;
> を行わねばならなくなってしまい、使い勝手が悪くなります。
>
> そこで、個々のラベルに対してイベントを割り当てていくのでは無く、
> 複数のラベルからのイベントを一つに集約した独自イベントを作成し、継承先が
>  this.LbClicked += Form1_LbClicked;
> とするだけで、たとえば
>  private void Form1_LbClicked(object sender, LbClickedEventArgs e)
>  {
>   Label label = e.Label;
>  }
> のようにして利用できるように設計した方が使い勝手がよいであろう……という話です。

説明頂いた内容の概略は理解できたのですが、
それぞれのラベルがクリックされた判別はできるのでしょうか?
#どういうコードを書けば良いかがまだわからないので、想像がついていません。すみません。


> ■No34549 (επιστημη さん) に返信
>> base.OnLbClicked(sender,e); // ←これ入れとけ、ってこっちゃないすか。
>
> ですます。フォローありがとうございます。
> まぁ、今回はそもそも OnLbClicked を継承先で再実装すること自体が不要になりそうですけれども。

なるほど、そういう意味だったのですね。
ありがとうございます。
引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -