- PR -

C# ボタンClick処理中に次のClickを受け付けなくする方法

1
投稿者投稿内容
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-12-19 17:10
よろしくお願いします。

課題
ボタンを早押ししても1回しか処理が実行されないようにしたい。


・新しいボタン(NewButton)を作成し、Clickイベントを定義しています。
・Exec処理にはSleepやJoin等のロジックが含まれていることもあり、結果として10秒程度の時間がかかります。
・現状ではExec処理中でも次のClickイベントが受け付けられてしまい、結果として、ボタンを早押しした回数だけExecが実行されます。
・早押ししてもExec処理が1回しか実行されないようにしたい。つまり、Exec処理中は次のClickを受け付けないようにする。もしくは、Exec処理中に受け付けたClick処理をキャンセルできれば良い。


public class NewButton : System.Windows.Forms.Button
{

this.Click += new System.EventHandler(Exec);

private void Exec(object sender, System.EventArgs e)
{
// JoinやSleep等が必要で処理が長くなる
}

mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2004-12-19 17:28
こんにちは、meiです。

引用:

ひろしさんの書き込み (2004-12-19 17:10) より:

課題
ボタンを早押ししても1回しか処理が実行されないようにしたい。



単純な方法ですがボタンがクリックされたタイミングで
button1.Enabled = false;
と、ボタンを無効にして処理が終わったら有効にするというのは、いかがでしょうか?
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-12-19 18:23
ご回答ありがとうございます。
試みてみましたが、今回の場合うまくいきませんでした。
Exec処理の先頭にthis.Enabled = false;最後にthis.Enabled = true;を挿入しました。けれども、Exec処理の途中でスレッドのSleepを含むdelegateを実行している最中にClickされたClickイベントは受け付けてしまいます。累積されたClickイベントはExec処理が終わった後に逐次実行されてしまうので、結果的にExec処理に挿入したthis.Enabled = falseをすり抜けてしまいます。


長くなって恐縮ですが、以下に完全なソースコードを掲載します。
ソースコード中の表記は下記のように読み替える必要があります。
クリックするたびにON/OFFをくりかえすボタンです。表示を変更するだけでなくが外部で定義されたStartToStopおよびStopToStart処理を組み込むことができます。
StartToStopおよびStopToStartメソッド中にスレッドのSleepロジックが含まれているとthis.Enabled = false;が無効にされてしまします。

NewButton → SwitchButton
Exec → Switch

ソースコード(参考のため)

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;


namespace Lib
{
namespace UserControl
{
public class SwitchButton : System.Windows.Forms.Button
{
/// <summary>
/// 必要なデザイナ変数です。
/// </summary>
private System.ComponentModel.Container components = null;

public SwitchButton()
{
// この呼び出しは、Windows.Forms フォーム デザイナで必要です。
InitializeComponent();

// TODO: InitializeComponent 呼び出しの後に初期化処理を追加します。
}

/// <summary>
/// 使用されているリソースに後処理を実行します。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region コンポーネント デザイナで生成されたコード
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
//
// SwitchButton
//
this.Click += new System.EventHandler(this.Switch);

}
#endregion
public enum ModeType
{
Start,
StartToStop,
Stop,
StopToStart
}
private ModeType mode = ModeType.Stop;
private string startText = "OFF";
private string startToStopText = "Wait";
private string stopText = "ON";
private string stopToStartText = "Wait";
private System.Drawing.Color startBackColor = System.Drawing.Color.LightPink;
private System.Drawing.Color startToStopBackColor = System.Drawing.Color.LightYellow;
private System.Drawing.Color stopBackColor = System.Drawing.Color.LightBlue;
private System.Drawing.Color stopToStartBackColor = System.Drawing.Color.LightYellow;

[DefaultValue(false)]
/// <summary>
/// Start状態 = true Stop状態 = false
/// </summary>
public ModeType Mode
{
get
{
return mode;
}
set
{
mode = value;
}

}

[DefaultValue(false)]
/// <summary>
/// Start状態に表示する背景色
/// </summary>
public System.Drawing.Color StartBackColor
{
get
{
return startBackColor;
}
set
{
startBackColor = value;
}
}

[DefaultValue(false)]
/// <summary>
/// StartToStop状態に表示する背景色
/// </summary>
public System.Drawing.Color StartToStopBackColor
{
get
{
return startToStopBackColor;
}
set
{
startToStopBackColor = value;
}
}

[DefaultValue(false)]
/// <summary>
/// Stop状態に表示する背景色
/// </summary>
public System.Drawing.Color StopBackColor
{
get
{
return stopBackColor;
}
set
{
stopBackColor = value;
}
}

[DefaultValue(false)]
/// <summary>
/// StopToStart状態に表示する背景色
/// </summary>
public System.Drawing.Color StopToStartBackColor
{
get
{
return stopToStartBackColor;
}
set
{
stopToStartBackColor = value;
}
}

[DefaultValue(false)]
/// <summary>
/// Start状態に表示するText
/// </summary>
public string StartText
{
get
{
return startText;
}
set
{
startText = value;
}
}
[DefaultValue(false)]
/// <summary>
/// StartToStop状態に表示するText
/// </summary>
public string StartToStopText
{
get
{
return startToStopText;
}
set
{
startToStopText = value;
}
}

[DefaultValue(false)]
/// <summary>
/// Stop状態に表示するText
/// </summary>
public string StopText
{
get
{
return stopText;
}
set
{
stopText = value;
}
}
[DefaultValue(false)]
/// <summary>
/// StopToStart状態に表示するText
/// </summary>
public string StopToStartText
{
get
{
return stopToStartText;
}
set
{
stopToStartText = value;
}
}

public override string Text
{
get
{
string temp;
switch(mode)
{
case ModeType.Start:
temp = startText;
break;
case ModeType.StartToStop:
temp = startToStopText;
break;
case ModeType.Stop:
temp = stopText;
break;
case ModeType.StopToStart:
temp = stopToStartText;
break;
default:
temp = "";
break;
}
return temp;
}
}

public override Color BackColor
{
get
{
Color temp;
switch(mode)
{
case ModeType.Start:
temp = startBackColor;
break;
case ModeType.StartToStop:
temp = startToStopBackColor;
break;
case ModeType.Stop:
temp = stopBackColor;
break;
case ModeType.StopToStart:
temp = stopToStartBackColor;
break;
default:
temp = Color.Empty;
break;
}
return temp;
}
}

/// <summary>
/// ボタンを切り替える
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Switch(object sender, System.EventArgs e)
{
this.Enabled = false;
switch(mode)
{
case ModeType.Start:
mode = ModeType.StartToStop;
this.Refresh();
StartToStop.Callback();
mode = ModeType.Stop;
break;
case ModeType.StartToStop:
break;
case ModeType.Stop:
mode = ModeType.StopToStart;
this.Refresh();
StopToStart.Callback();
mode = ModeType.Start;
break;
case ModeType.StopToStart:
break;
default:
break;
}
this.Refresh();
this.Enabled = true;
}


public FuncSet StartToStop = new FuncSet();
public FuncSet StopToStart = new FuncSet();
public class FuncSet
{
public FuncSet()
{
func = null;
isEnabled = false;
}
public FuncSet(Func pFunc)
{
func = pFunc;
isEnabled = true;
}
public void Callback()
{
if(isEnabled)
{
answer = func(param);
}

}
public object Param
{
get
{
return param;
}
set
{
param = value;
}
}
public object Answer
{
get
{
return answer;
}
}
public bool IsEnabled
{
get
{
return isEnabled;
}
set
{
isEnabled = value;
}
}
public delegate object Func(object dummy);
private Func func;
private object param;
private object answer;
private bool isEnabled;
}

}
}
}

_________________
mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2004-12-19 19:54
こんばんは、meiです。

引用:

ひろしさんの書き込み (2004-12-19 18:23) より:
ご回答ありがとうございます。
試みてみましたが、今回の場合うまくいきませんでした。



問題は、メッセージキューに溜まったイベントを無効にしたいということなんですね。
あまりスマートな方法ではありませんが、こうするとどうでしょうか?

コード:
private void Switch(object sender, System.EventArgs e) { 
	if (this.Enabled) {
		this.Enabled = false;
		// わざとSleepを入れる
		System.Threading.Thread.Sleep(1000);
		switch(mode) { 
			case ModeType.Start: 
				mode = ModeType.StartToStop; 
				this.Refresh(); 
				StartToStop.Callback(); 
				mode = ModeType.Stop; 
				break; 
			case ModeType.StartToStop: 
				break; 
			case ModeType.Stop: 
				mode = ModeType.StopToStart; 
				this.Refresh(); 
				StopToStart.Callback(); 
				mode = ModeType.Start; 
				break; 
			case ModeType.StopToStart: 
				break; 
			default: 
				break; 
		}
		// メッセージキューをすべて処理してしまう
		// this.Enabled == falseなのでSwitchは何もしない
		Application.DoEvents();
		this.Refresh(); 
		this.Enabled = true;
	}
} 


1

スキルアップ/キャリアアップ(JOB@IT)