Oka Laboratory

テキストボックス

テキストボックスコントロールに関する様々なテクニックを紹介しています。

Visual Basic 6(SP6) + Windows 2000/XP + Internet Explorer 6で動作確認をしています。

送信メッセージ

SendMessage APIのwMsgに以下の値を設定することで、テキストボックスへメッセージを送信できます。

メッセージ 意味
EM_CANUNDO &HC6 EM_UNDOメッセージを処理可能か判定
EM_EMPTYUNDOBUFFER &HCD EM_UNDOメッセージ処理用バッファをクリア
EM_FMTLINES &HC8 各行の終わりに CR-CR-LFを追加・削除(複数行テキストボックス)
EM_GETFIRSTVISIBLELINE &HCE 先頭に表示されている行の番号を取得
EM_GETHANDLE &HBD メモリバッファのハンドルを取得(複数行テキストボックス)
EM_GETLINE &HC4 バッファに指定の1行をコピー(複数行テキストボックス)
EM_GETLINECOUNT &HBA 行数の取得(複数行テキストボックス)
EM_GETMARGINS &HD4 左マージン、右マージンの取得
EM_GETMODIFY &HB8 テキストを変更したかどうかの判定
EM_GETPASSWORDCHAR &HD2 現在のパスワード文字を取得
EM_GETRECT &HB2 フォーマット領域の矩形の取得
EM_GETSEL &HB0 選択された最初と最後の文字位置の取得
EM_GETTHUMB &HBE スクロールバーの位置の取得
EM_GETWORDBREAKPROC &HD1 アプリケーション定義のワードラップ関数のアドレスを取得
EM_LIMITTEXT &HC5 入力可能な文字数の設定
EM_LINEFROMCHAR &HC9 指定の文字位置の行番号
EM_LINEINDEX &HBB 指定の行の先頭の文字位置の取得(複数行テキストボックス)
EM_LINELENGTH &HC1 指定の文字を含む行の文字数の取得(複数行テキストボックス)
EM_LINESCROLL &HB6 任意の方向にスクロール(複数行テキストボックス)
EM_REPLACESEL &HC2 現在選択されているテキストを指定の文字列で置換
EM_SCROLL &HB5 垂直方向のスクロール(複数行テキストボックス)
EM_SCROLLCARET &HB7 現在のカーソル位置を表示するようにスクロール
EM_SETHANDLE &HBC メモリバッファのハンドルを設定(複数行テキストボックス)
EM_SETMARGINS &HD3 左マージン、右マージンの設定
EM_SETMODIFY &HB9 更新状態の設定
EM_SETPASSWORDCHAR &HCC パスワード文字の設定
EM_SETREADONLY &HCF 編集不可に設定、解除
EM_SETRECT &HB3 フォーマット矩形の設定
EM_SETRECTNP &HB4 フォーマット矩形の設定
EM_SETSEL &HB1 指定した範囲を選択状態に設定
EM_SETTABSTOPS &HCB タブストップ位置の設定(複数行テキストボックス)
EM_SETWORDBREAKPROC &HD0 アプリケーション定義のワードラップ関数のアドレスを設定
EM_UNDO &HC7 テキストを元に戻す

タブストップの設定

MultiLineプロパティがTrueである複数行テキストボックスに、EM_SETTABSTOPSを送信することで設定できます。テキストが代入される前に設定しておく必要があります。タブストップ位置は、Pixel単位で表わしたフォントの平均文字幅の1/4を1とするダイアログ単位で設定します。

EM_SETTABSTOPS
意味 タブストップ位置の設定(複数行テキストボックス)
&HCB
wParam
0
デフォルト値に戻す
1
lParamの値の間隔に設定
2以上
タブストップの個数
lParam タブストップ位置の長整数型配列のアドレス。wParam=1のときはタブストップの間隔
戻り値
0以外
成功
0
失敗

Text1オブジェクトに任意の個数のタブストップ位置を設定する関数Tabsです。送信メッセージをLB_SETTABSTOPS(値:&H192)にするとリストボックスにタブストップを設定することができます。

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Const EM_SETTABSTOPS = &HCB

Public Sub Tabs(ParamArray TabPos())
'TextBoxに任意の個数のタブストップを設定する
	Dim n As Integer, i As Integer
	n = UBound(TabPos)				'パラメータの数 - 1
	ReDim TabStop(0 To n) As Long			'タブストップの配列

	For i = 0 To n
		TabStop(i) = CLng(TabPos(i) * 4)	'ダイアログ単位(平均文字幅の1/4)に変換
	Next i

	SendMessage Text1.hWnd, EM_SETTABSTOPS, n + 1, TabStop(0)
End Sub

Tabs関数の使用例です。ここでは6、30、35文字目にタブストップを設定しています。

Tabs 6, 30, 35	'6、30、35文字目にタブストップを設定
Text1.Text = "番号" & vbTab & "氏名" & vbTab & "得点" & vbTab & "備考" & vbCrLf

スクロールの方法

テキストボックスに、以下のメッセージを送信することで、テキストのスクロールを行なうことができます。このうち、EM_SCROLLEM_LINESCROLLは、MultiLineプロパティがTrueのテキストボックスで有効です。

EM_SCROLL
意味 垂直方向のスクロール(複数行テキストボックス)
&HB5
wParam 以下の値を設定します。
SB_LINEUP (0)
1行上にスクロール
SB_LINEDOWN (1)
1行下にスクロール
SB_PAGEUP (2)
1ページ上にスクロール
SB_PAGEDOWN (3)
1ページ下にスクロール
lParam 0
戻り値
MSW
1
LSW
実際にスクロールした行数
0
失敗
EM_LINESCROLL
意味 任意の方向にスクロール(複数行テキストボックス)
&HB6
wParam 水平方向のスクロールの文字数(右方向:正)
lParam 垂直方向のスクロールの行数(下方向:正)
戻り値
0以外
成功
0
失敗
EM_SCROLLCARET
意味 現在のカーソル位置を表示するようにスクロール
&HB7
wParam 0
lParam 0
戻り値
0以外
成功
0
失敗

EM_SCROLLメッセージを使って下に1行スクロールします。SendMessageの第4引数にByvalキーワードが必要です。

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Const EM_SCROLL = &HB5
Public Const SB_LINEUP = 0
Public Const SB_LINEDOWN = 1
Public Const SB_PAGEUP = 2
Public Const SB_PAGEDOWN = 3

Public Sub TextScroll()
	SendMessage Text1.hWnd, EM_SCROLL, SB_LINEDOWN, ByVal 0	'下に1行スクロール
End Sub

EM_LINESCROLLメッセージを使うと、水平、垂直両方向にスクロールが可能になります。ここでは右方向にx文字分、下方向にy行分のスクロールを行ないます。これもSendMessageの第4引数にByvalキーワードが必要です。

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Const EM_LINESCROLL = &HB6

Public Sub TextScroll(x As Long, y As Long)
	SendMessage Text1.hWnd, EM_LINESCROLL, x, ByVal y	'右方向にx文字、下方向にy行のスクロール
End Sub

EM_SCROLLCARETメッセージを送信すると、カーソルのある位置が表示されるようにスクロールします。これは1行テキストボックスでも有効です。

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Const EM_SCROLLCARET = &HB7

Public Sub TextScrollCaret()
	SendMessage Text1.hWnd, EM_SCROLLCARET, 0, ByVal 0
End Sub

[編集]メニュー機能の実装

[編集]メニューの[切り取り]、[コピー]、[貼り付け]、[クリア]、[元に戻す]を実装するには、以下のクリップボードメッセージをWindowsに送ります。これらのメッセージはCombo Boxコントロールでも使用できます。

WM_CUT
意味 選択範囲をクリップボードへコピーし消去
&H300
wParam 0
lParam 0
戻り値 なし
WM_COPY
意味 選択範囲をクリップボードへコピー
&H301
wParam 0
lParam 0
戻り値 なし
WM_PASTE
意味 クリップボードから現在位置へコピー
&H302
wParam 0
lParam 0
戻り値 なし
WM_CLEAR
意味 選択範囲を消去
&H303
wParam 0
lParam 0
戻り値 なし
WM_UNDO
意味 テキストを元に戻す
&H304
wParam 0
lParam 0
戻り値 なし

[元に戻す]関連のメッセージには以下のものがあります。このうちEM_UNDOは上記のWM_UNDOと同じ動作をします。

EM_CANUNDO
意味 EM_UNDOメッセージを処理可能か判定
&HC6
wParam 0
lParam 0
戻り値
0以外
処理可能
0
処理不可能
EM_UNDO
意味 テキストを元に戻す
&HC7
wParam 0
lParam 0
戻り値 複数行テキストボックスでは成功したときは1、失敗したときは0。1行入力テキストボックスでは常に1
EM_EMPTYUNDOBUFFER
意味 EM_UNDOメッセージ処理用バッファをクリア
&HCD
wParam 0
lParam 0
戻り値 なし

メニューエディタで、以下のメニューを作成します。

キャプション ショートカット 名前
編集(&E)   mnuEdit
....元に戻す(&U) Ctrl+Z mnuEditUndo
....-   mnuEditSeparate1
....切り取り(&T) Ctrl+X mnuEditCut
....コピー(&C) Ctrl+C mnuEditCopy
....貼り付け(&P) Ctrl+V mnuEditPaste
....クリア(&L) Del mnuEditClear

各メニューのClickイベントに以下のコードを記述します。mnuEditのClickイベントは、サブメニューが開かれるときに実行されます。

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Const EM_CANUNDO = &HC6
Public Const EM_EMPTYUNDOBUFFER = &HCD
Public Const EM_UNDO = &HC7
Public Const WM_CLEAR = &H303
Public Const WM_COPY = &H301
Public Const WM_CUT = &H300
Public Const WM_PASTE = &H302
Public Const WM_UNDO = &H304

Private Sub mnuEdit_Click()
'クリップボードにテキストデータが存在するとき、[貼り付け]を有効にする。
	mnuEditPaste.Enabled = Clipboard.GetFormat(VbCFText)

'[元に戻す]の設定
	With mnuEditUndo
		If SendMessage(Text1.hWnd, EM_CANUNDO, 0, Byval 0) Then
			.Enabled = True
			.Caption = "元に戻す(&Z)"
		Else
			.Enabled = False
			.Caption = "元に戻せません"
		End If
	End With
End Sub

Private Sub mnuEditClear_Click()
'クリア
	SendMessage Text1.hWnd, WM_CLEAR, 0, Byval 0
End Sub

Private Sub mnuEditCopy_Click()
'コピー
	SendMessage Text1.hWnd, WM_COPY, 0, Byval 0
End Sub

Private Sub mnuEditCut_Click()
'切り取り
	SendMessage Text1.hWnd, WM_CUT, 0, Byval 0
End Sub

Private Sub mnuEditPaste_Click()
'貼り付け
	SendMessage Text1.hWnd, WM_PASTE, 0, Byval 0
End Sub

Private Sub mnuEditUndo_Click()
'元に戻す
	SendMessage Text1.hWnd, WM_UNDO, 0, Byval 0		'WM_UNDOをEM_UNDOに換えても可
	SendMessage Text1.hWnd, EM_EMPTYUNDOBUFFER, 0, Byval 0	'Undoバッファを消去するときは必要
End Sub

バイト単位で入力文字数を制限

テキストボックスのMaxLengthプロパティは、全角、半角関係なく文字数で設定しますが、EM_LIMITTEXTを送信することで入力可能な最大バイト数を設定することができます。入力可能なバイト数の既定値は30000バイトです。既に文字列があるとき、EM_LIMITTEXTを送信しても無視されます。

EM_LIMITTEXT
意味 入力可能な文字数の設定
&HC5
wParam 文字数(バイト単位)
lParam 0
戻り値 なし

次のMaxByte関数は、引数Lengで与えられた入力可能な最大バイト数をText1オブジェクトに設定します。

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Const EM_LIMITTEXT = &HC5

Public Sub MaxByte(Leng As Long)
	SendMesaage Text1.hWnd, EM_LIMITTEXT, Leng, Byval 0
End Sub

マージンの設定と取得

テキストボックスにEM_SETMARGINSを送信することでマージンを設定できます。マージンはpixel単位で与えます。またEM_GETMARGINSを送信すると現在のマージンを取得できます。

EM_SETMARGINS
意味 左マージン、右マージンの設定
&HD3
wParam 以下の値を設定します。
EC_LEFTMARGIN (1)
左マージンの設定
EC_RIGHTMARGIN (2)
右マージンの設定
lParam
MSW
右マージン
LSW
左マージン
戻り値 なし
EM_GETMARGINS
意味 左マージン、右マージンの取得
&HD4
wParam 0
lParam 0
戻り値
MSW
右マージン
LSW
左マージン

次のSetMargin関数はTwips単位で引数LeftMargin、RightMarginに与えた左右マージンをText1オブジェクトに設定します。このように左右両方を設定するときはEC_LEFTMARGINEC_RIGHTMARGINをOr演算子で結合します。

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Const EM_SETMARGINS = &HD3
Public Const EC_LEFTMARGIN = &H1
Public Const EC_RIGHTMARGIN = &H2

Public Sub SetMargin(LeftMargin As Long, RightMargin As Long) 
	Dim n As Long
	n = (RightMargin / Screen.TwipsPerPixelX * &H10000) Or (LeftMargin / Screen.TwipsPerPixelX)
	SendMesaage Text1.hWnd, EM_SETMARGINS, EC_LEFTMARGIN Or EC_RIGHTMARGIN, Byval n
End Sub

次のGetMargin関数は引数flagにEC_LEFTMARGINを与えると左マージン、EC_RIGHTMARGINを与えると右マージンをTwips単位で返します。

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Const EM_GETMARGINS = &HD4
Public Const EC_LEFTMARGIN = &H1
Public Const EC_RIGHTMARGIN = &H2

Public Function GetMargin(flag As Long) As Long
	Dim n As Long
	n = SendMesaage(Text1.hWnd, EM_GETMARGINS, 0, Byval 0)
	If flag = EC_LEFTMARGIN Then
		n = n And &HFFFF&
	Else
		n = n \ &H10000
	End If
	GetMargin = n * Screen.TwipsPerPixelX
End Sub

スタイルの変更

GetWindowLong APIとSetWindowLong APIを使うことで、テキストボックスのスタイルを変更することができます。

GetWindowLong
機能 指定されたウィンドウに関する情報を取得します。
宣言
Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
引数 hWnd ウィンドウハンドル
nIndex 取得するデータの種類を以下の定数で指定
GWL_EXSTYLE (-20)
拡張ウィンドウスタイル
GWL_HINSTANCE (-6)
アプリケーションのインスタンスハンドル
GWL_HWNDPARENT (-8)
親ウィンドウのハンドル
GWL_ID (-12)
ウィンドウID
GWL_STYLE (-16)
ウィンドウスタイル
GWL_USERDATA (-21)
ウィンドウに関連付けられたアプリケーション定義の32ビット値
GWL_WNDPROC (-4)
ウィンドウプロシージャのアドレス、またはそれを示すハンドル
戻り値
0以外
取得した32ビットデータ
0
失敗
SetWindowLong
機能 指定されたウィンドウの属性を変更します。
宣言
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
引数 hWnd ウィンドウハンドル
nIndex 変更するデータの種類を以下の定数で指定
GWL_EXSTYLE (-20)
拡張ウィンドウスタイル
GWL_HINSTANCE (-6)
アプリケーションのインスタンスハンドル
GWL_ID (-12)
ウィンドウID
GWL_STYLE (-16)
ウィンドウスタイル
GWL_USERDATA (-21)
ウィンドウに関連付けられたアプリケーション定義の32ビット値
GWL_WNDPROC (-4)
ウィンドウプロシージャのアドレス、またはそれを示すハンドル
dwNewLong 新しく設定するデータ
戻り値
0以外
変更前のデータ
0
失敗

テキストボックスに関するウィンドウ属性(GetWindowLongの戻り値、SetWindowLongの引数dwNewLong)は次の通りです。

定数名 説明
ES_AUTOHSCROLL &H80 行末に文字を入力したとき、10文字分右にスクロール
ES_AUTOVSCROLL &H40 最終行でEnterキーを押したとき、1ページ分上にスクロール
ES_CENTER &H1 中央揃え
ES_LEFT &H0 左揃え
ES_LOWERCASE &H10 入力された文字をすべて小文字に変換
ES_MULTILINE &H4 複数行のテキストボックス
ES_NOHIDESEL &H100 フォーカスを受け取ったときに強調表示にしない。
ES_NUMBER &H2000 数字のみ入力可
ES_OEMCONVERT &H400 入力されたテキストをANSI文字セットからOEM文字セットに変換し、その後ANSI文字セットに戻します。
ES_PASSWORD &H20 入力されたすべての文字をアスタリスク(*)で表示
ES_READONLY &H800 入力・編集不可
ES_RIGHT &H2 右揃え
ES_UPPERCASE &H8 入力された文字をすべて大文字に変換
ES_WANTRETURN &H1000 複数行のテキストボックスに入力しているとき、Enterキーによりキャリッジリターンを挿入(1行入力では無効)

小文字変換、大文字変換、数字のみ入力を設定、解除する関数を示します。設定するときは引数flagにTrue、解除するときはFalseを指定します。単に設定のみの場合は、If...Then...Elseブロック中のThen以下の1行のAnd演算子より前の括弧内だけでも構いません。

Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Const GWL_STYLE = (-16)
Public Const ES_LOWERCASE = &H10&
Public Const ES_NUMBER = &H2000&
Public Const ES_UPPERCASE = &H8&

Public Sub TextLower(flag As Boolean)
'小文字変換の設定、解除
	Dim Style As Long

	Style = GetWindowLong(Text1.hWnd, GWL_STYLE)
	If flag Then
		Style = (Style Or ES_LOWERCASE) And (Not (ES_UPPERCASE Or ES_NUMBER))
	Else
		Style = Style And (Not ES_LOWERCASE)
	End If
	SetWindowLong Text1.hWnd, GWL_STYLE, Style
End Sub

Public Sub TextUpper(flag As Boolean)
'大文字変換の設定、解除
	Dim Style As Long

	Style = GetWindowLong(Text1.hWnd, GWL_STYLE)
	If flag Then
		Style = (Style Or ES_UPPERCASE) And (Not (ES_LOWERCASE Or ES_NUMBER))
	Else
		Style = Style And (Not ES_UPPERCASE)
	End If
	SetWindowLong Text1.hWnd, GWL_STYLE, Style
End Sub

Public Sub TextNumberOnly(flag As Boolean)
'数字のみ入力の設定、解除
	Dim Style As Long

	Style = GetWindowLong(Text1.hWnd, GWL_STYLE)
	If flag Then
		Style = (Style Or ES_NUMBER) And (Not (ES_LOWERCASE Or ES_UPPERCASE))
	Else
		Style = Style And (Not ES_NUMBER)
	End If
	SetWindowLong Text1.hWnd, GWL_STYLE, Style
End Sub

文字列の追加

MultiLineプロパティがTrueである複数行テキストボックスに、文字列を1行追加する方法です。この方法は余分なメモリを消費せず高速です。

Public Sub TextAdd(St As String)
'テキストを1行追加
	With Text1
		.SelStart = Len(.Text) .SelText = St & vbCrLf
	End With
End Sub

[Enter]キー押下時のBeep音抑制

MultiLineプロパティがFalseである1行入力テキストボックスで、[Enter]キーを押下したときに発生するBeep音を抑制します。 KeyPressイベントの引数KeyAsciiにはANSI文字コードを表す整数値が設定されています。このイベント内でKeyAsciiを0に設定することで、キー操作を取り消すことができます。ここでは[Enter]キーが押下されたときKeyAsciiを0に設定しています。

Private Sub Text1_KeyPress(KeyAscii As Integer)
'[Enter]キーのとき、入力をCancel
	If KeyAscii = 13 Then
		KeyAscii = 0
	End If
End Sub

フォーカスを得たときテキストを選択する

Windows上のプログラムでは、テキストボックスがフォーカスを得たとき、テキスト全体が選択状態になるのが標準的です。これを実現するには標準モジュールに以下のSelectAllText関数を作成します。

Public Sub SelectAllText(Txt As TextBox)
'TextBoxのテキスト全体を選択
	With Txt
		.SelStart = 0
		.SelLength = Len(.Text)
	End With
End Sub

SelectAllText関数は、各テキストボックスのGotFocusイベントで呼び出します。

Private Sub Text1_GotFocus()
	SelectAllText Text1
End Sub

正当なCSSです!