コントロールでスクロールされたことを検出する
コントロールでスクロールされたことを検出するコードを紹介します。
概要
フォームなどのScrollイベントのあるコントロールでは、Scrollイベントハンドラを実装することでスクロールを検出できますが、Scrollイベントのないコントロールではこの方法は使えません。Scrollイベントのないコントロールの場合はコントロールを派生してウィンドウメッセージを受信することでスクロールの検出ができます。
実装例
プロジェクトの作成
新規のWindowsフォームアプリケーションを作成します。プロジェクト作成後[新しい項目の追加]で[コンポーネント クラス]を選択します。[名前]の欄に名称を設定します。今回は"ScrollDetectTextBox.cs"としました。
ソリューションエクスプローラにコンポーネントクラスが追加されます。
コード(コンポーネント)
作成した"ScrollDetectTextBox.cs"に以下のコードを実装します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ScrollDetectControl
{
public partial class ScrollDetectTextBox : TextBox
{
public ScrollDetectTextBox()
{
InitializeComponent();
}
public ScrollDetectTextBox(IContainer container)
{
container.Add(this);
InitializeComponent();
}
public delegate void ScrollDelegate(object sender, ScrollEventArgs e);
private ScrollDelegate onScroll;
public event ScrollDelegate Scroll
{
add
{
onScroll += value;
}
remove
{
onScroll -= value;
}
}
protected override void WndProc(ref Message message)
{
base.WndProc(ref message);
switch (message.Msg) {
case WindowsConst.WM_HSCROLL:
WM_HSCROLL_Proc(message);
break;
case WindowsConst.WM_VSCROLL:
WM_VSCROLL_Proc(message);
break;
}
}
private void WM_HSCROLL_Proc(Message message)
{
short hi = HiWord((long)message.WParam);
short lo = LoWord((long)message.WParam);
ScrollEventType set;
switch (lo) {
case WindowsConst.SB_ENDSCROLL:
set = ScrollEventType.EndScroll;
break;
case WindowsConst.SB_LEFT:
set = ScrollEventType.First;
break;
case WindowsConst.SB_RIGHT:
set = ScrollEventType.Last;
break;
case WindowsConst.SB_LINELEFT:
set = ScrollEventType.SmallDecrement;
break;
case WindowsConst.SB_LINERIGHT:
set = ScrollEventType.SmallIncrement;
break;
case WindowsConst.SB_PAGELEFT:
set = ScrollEventType.LargeDecrement;
break;
case WindowsConst.SB_PAGERIGHT:
set = ScrollEventType.LargeIncrement;
break;
case WindowsConst.SB_THUMBPOSITION:
set = ScrollEventType.ThumbPosition;
break;
case WindowsConst.SB_THUMBTRACK:
set = ScrollEventType.ThumbTrack;
break;
default:
set = ScrollEventType.EndScroll;
break;
}
if (onScroll != null) {
ScrollEventArgs e = new ScrollEventArgs(set, hi, ScrollOrientation.VerticalScroll);
onScroll(this, e);
}
}
private void WM_VSCROLL_Proc(Message message)
{
short hi = HiWord((long)message.WParam);
short lo = LoWord((long)message.WParam);
ScrollEventType set;
switch (lo) {
case WindowsConst.SB_BOTTOM:
set = ScrollEventType.Last;
break;
case WindowsConst.SB_ENDSCROLL:
set = ScrollEventType.EndScroll;
break;
case WindowsConst.SB_LINEDOWN:
set = ScrollEventType.SmallIncrement;
break;
case WindowsConst.SB_LINEUP:
set = ScrollEventType.SmallDecrement;
break;
case WindowsConst.SB_PAGEDOWN:
set = ScrollEventType.LargeIncrement;
break;
case WindowsConst.SB_PAGEUP:
set = ScrollEventType.LargeDecrement;
break;
case WindowsConst.SB_THUMBPOSITION:
set = ScrollEventType.ThumbPosition;
break;
case WindowsConst.SB_THUMBTRACK:
set = ScrollEventType.ThumbTrack;
break;
case WindowsConst.SB_TOP:
set = ScrollEventType.First;
break;
default:
set = ScrollEventType.EndScroll;
break;
}
if (onScroll != null) {
ScrollEventArgs e = new ScrollEventArgs(set, hi, ScrollOrientation.VerticalScroll);
onScroll(this, e);
}
}
protected short LoWord(long input)
{
return (short)((int)input & 0xFFFF);
}
protected short HiWord(long input)
{
return (short)((int)input >> 16);
}
}
}
解説
コンポーネントクラス作成時のコードは"Component"クラスを派生していますが、今回はTextBoxの派生クラスに変更し、スクロールを検出できるTextBoxを作成します。
public partial class ScrollDetectTextBox : Component
の部分を
public partial class ScrollDetectTextBox : TextBox
に変更します。
コントロールに送られたWM_SCROLLウィンドウメッセージを取得してスクロールを検出します。動作の詳細については
こちらの記事を参照してください。
また、コントロールにScrollイベントを追加します。コンポーネントクラスへのイベント追加は
こちらと
こちらの記事を参照してください。
アプリケーションUI
プロジェクトをビルドすると[ツールボックス]に作成した"ScrollDetectTextBox”コントロールが追加されます。
フォームデザイナに"ScrollDetectTextBox"コントロールを配置します。
"ScrollDetectTextBox"コントロールの[Multiline]プロパティを"true"にします。
"ScrollDetectTextBox"コントロールの[WordWrap]プロパティを"false"にします。また情報表示用のTextBoxを配置します。
コード(アプリケーション)
アプリケーションに以下のコードを記述します。
実際は"ScrollDetectTextBox"コントロールの"Scroll"イベントを実装します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ScrollDetectControl
{
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
}
private void scrollDetectTextBox1_Scroll(object sender, ScrollEventArgs e)
{
if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll) {
textBox1.Text += "横方向スクロール:";
}
else if (e.ScrollOrientation == ScrollOrientation.VerticalScroll) {
textBox1.Text += "縦方向スクロール:";
}
switch (e.Type) {
case ScrollEventType.EndScroll:
textBox1.Text += "EndScroll \r\n";
break;
case ScrollEventType.First:
textBox1.Text += "First \r\n";
break;
case ScrollEventType.LargeDecrement:
textBox1.Text += "LargeDecrement \r\n";
break;
case ScrollEventType.LargeIncrement:
textBox1.Text += "LargeIncrement \r\n";
break;
case ScrollEventType.Last:
textBox1.Text += "Last \r\n";
break;
case ScrollEventType.SmallDecrement:
textBox1.Text += "SmallDecrement \r\n";
break;
case ScrollEventType.SmallIncrement:
textBox1.Text += "SmallIncrement \r\n";
break;
case ScrollEventType.ThumbPosition:
textBox1.Text += "ThumbPosition \r\n";
break;
case ScrollEventType.ThumbTrack:
textBox1.Text += "ThumbTrack \r\n";
break;
}
}
}
}
解説
"ScrollDetectTextBox"コントロールでスクロールされるとScrollイベントが呼び出されます。ScrollEventArgsのTypeです黒るの種類を、ScrollOrientationでスクロールの方向を検出します。
実行結果
アプリケーションを実行します。下図のウィンドウが表示されます。
"ScrollDetectTextBox"コントロールに文字列を入力しスクロールバーを有効にします。スクロールバーをクリックし"ScrollDetectTextBox"コントロールをスクロールすると下のTextBoxにスクロールされた旨のメッセージが表示されます。
スクロールバーのつまみ部分以外の背景をクリックしページスクロールすると"LargeDecrement"が表示されページスクロールも検出できます。
横方向のスクロールも検出できます。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用