大分昔に書いたFC2Blog記事の転載。自作の家計簿アプリに組み込んであるヤツ。
いい記事なんだけど検索にヒットしないんで、はは(;'∀')。
ひつじ!人間考案のシンプルな方法です。
このDateTimePicker、実は内部にコンボボックス・テキストボックス等は組み込まれていないらしいです。外部から判別してWindowメッセージ等を拾えるようには作ってないらしく。じゃあ、どうやって内部にカーソルを当ててるのかって根本的な疑問がありますが。
やっぱりListBoxが組み込まれてるって記述があったんで、ごにょごにょやれば行けるらしいです。
仕組みの把握が大変だな・・・
関連リンク
TextBoxってReadOnly = trueでもフォーカスあたる。空気読めなさすぎだよね。
C#のDateTimePickerのソースです。
https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/DateTimePicker.cs
Sender内部を調べたりしましたが、訳わかりませんね(笑) フォーカス時の違いが分からん。
とりあえずどうしようもないため、内部でクライアント領域の座標から矩形領域を描き、そこにマウスが入っているかどうかを調べます。
WindowsFormApplicationを使用しています。
Paint 3Dで作成しました。
大体、こんな感じです。
まずは以下のコードで、各フォーカス時のクライアント座標の値を割り出すことにしました。
public Form1()
{
InitializeComponent();
this.dateTimePicker1.MouseWheel
+= new MouseEventHandler(this.dateTimePicker1_MouseWheel);
}
private void dateTimePicker1_MouseWheel(object sender, MouseEventArgs e)
{
Point WheelPoint = new Point(e.X, e.Y);
// マウス座標をクライアント座標系へ変換
Point mouseClientPos = dateTimePicker1.PointToClient(WheelPoint);
Text = WheelPoint.ToString();
}
以下はおおまかな座標位置です。これを元にクライアント座標から指定の領域だけを区切れば、判定に成功する筈です。
Year
X=3-26 サイズは23
Y=3-15 高さはdatetimePickerの高さでOK
Month
X=38-60 ほぼ同じ
Y=3-15
Day
X= 62-83
Y= 3-15
注意:DateTimePickerのLocationプロパティを座標(0,0)にしないと動作しません。
任意の配置で動かすにはその都度調整が必要です。
例:Location が X=37,Y= 108 の場合、その分を差し引いてあげるといいみたいです。
Rectangle YearRect = new Rectangle(PickerRectLocation.X -37 ,PickerRectLocation.Y + 3 -108 ,23, DTHeight);
軽いので720P以上で見てくだせえ。
使わないともったいないのでSyntax ハイライターを入れた。死ぬ思いで入れた割にあまり使わなかったり・・・・。
<pre class="brush:csharp; height:400px"> コードすぐ忘れる・・・。
public Form1()
{
InitializeComponent();
this.dateTimePicker1.MouseWheel
+= new MouseEventHandler(this.dateTimePicker1_MouseWheel);
}
DateTime DT = new DateTime();
private void dateTimePicker1_MouseWheel(object sender, MouseEventArgs e)
{
//dateTimePicker1の高さ
int DTHeight = dateTimePicker1.Bounds.Height;
//dateTimePickerのウィンドウ座標をクライアント座標に変換
Point PickerRectLocation = dateTimePicker1.PointToClient(dateTimePicker1.Bounds.Location);
//マウスホイール時の座標
Point WheelPoint = new Point(e.X, e.Y);
// マウス座標をDateTimePicker上のクライアント座標系へ変換
Point mouseClientPos = dateTimePicker1.PointToClient(WheelPoint);
//dateTimePickerのLocationプロパティの値を引く
Rectangle YearRect = new Rectangle(PickerRectLocation.X -dateTimePicker1.Location.X ,PickerRectLocation.Y + 3 ,23, DTHeight);
Rectangle MonthRect = new Rectangle(PickerRectLocation.X -dateTimePicker1.Location.X + 38,PickerRectLocation.Y + 3,23,DTHeight);
//+38は前ボックスとの間隔
Rectangle DayRect = new Rectangle(PickerRectLocation.X -dateTimePicker1.Location.X+ 62, PickerRectLocation.Y + 3, 23, DTHeight);
//年ボックス判定
//年、月、日の数値をマウスホイールで1ずつ変える。
if (YearRect.Contains(mouseClientPos) == true)
{
// スクロール量(方向)の表示
DT = dateTimePicker1.Value.AddYears(e.Delta / 120);
dateTimePicker1.Text = DT.ToShortDateString();
}
//月ボックス判定
else if(MonthRect.Contains(mouseClientPos) == true)
{
DT = dateTimePicker1.Value.AddMonths(e.Delta / 120);
dateTimePicker1.Text = DT.ToShortDateString();
}
//日ボックス判定
else if (DayRect.Contains(mouseClientPos) == true)
{
DT = dateTimePicker1.Value.AddDays(e.Delta / 120);
dateTimePicker1.Text = DT.ToShortDateString();
}
}
自作の家計簿アプリに組み込んであります。
応用次第で色々出来る筈です。
カーソル位置を疑似的に判定して←キーを送信したり、クリックした年の数値をカーソル位置から判定して取り出すといった方法。Mousedownイベント等にも使えます。
参考にしたサイト
指定した座標がRectangle内か判定する - C#プログラミング
スクリーン座標←→クライアント座標の変換を行うには?
サンプルソースもある。