ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Visual Basic User's Clubコミュのテキストボックスの行数制御について

  • mixiチェック
  • このエントリーをはてなブックマークに追加
VB2005環境です。

複数行入力可(MultiLine)のテキストボックスに、入力可能バイト数、
最大入力可能行数の制限を付けたいと思っています。
バイトの縛りはMaxByteLengthPropertyで良いのですが、行数の縛りが
うまくいきません。

例えば、入力可能な行数を7行までという前提で、以下のように作って
みました。

---------------
Private Const EM_GETLINECOUNT = &HBA
Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As Integer, ByVal MSG As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) As Integer

Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress

Dim line As Integer

'全行数を取得する
line = SendMessage(Me.TextBox1.Handle, EM_GETLINECOUNT, 0, 0)

If line > 7 Then
'7行を超えるのでキャンセル
e.Handled = True
End If

End Sub
---------------
動きの問題として、
・8行目にいくことが出来てしまう(ただし文字は入力できない)
・キーイベントで判定しているため、7行以上入力状態では一切の
 操作ができない(バックスペース、Delteなども)

単純に、7行目での改行だけ不可能にしたいのですが、良い方法はないでしょうか?
尚、テキストボックス端で折り返した場合、改行扱いとして行を増やしてカウント
しますが、後でデータとして表示する関係上、そこに改行コードを付与したりは
できません(なので改行コードを数えて…という判定は不可)。
また、7行目では文字が折り返すまでの入力は出来ないようにしたいと思っています。

リッチテキストボックスは使いたくないので、出来れば通常のテキストボックスで
うまいこと制御できる方法がありましたら、ご教授ください。

コメント(12)

試してはいないのですが

KeyPressでは無くて
KeyDownで
「↓」や「enter」など改行に関わるKEYを押された場合に
次の入力先にsetFocsする、
では
ダメなのでしょうか?
KeyPressイベント内でEnterキーを指定してキャンセルする方法を試してみました。

Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
   If e.KeyChar = Chr(Keys.Enter) And TextBox1.Lines.Length >= 7 Then    
    e.Handled = True
  End If
End Sub

でも、コピペで来た場合は対応できないということに気づきました。
この方法を使う場合はもうひとつ入力後などにチェックを設けないといけないかもですね。
もっと効率の良い案が出てくることを期待しつつ、私も調べてみようと思います。
りきゅあさんのおっしゃる方法がとても良さそうですね。
Lines.Lengthでは改行コードのない行数までカウントできないんですね。。(汗)
なので、EM_LINEINDEXを使って試してみました。
こんな感じではどうでしょうか?

Private Const EM_GETLINECOUNT = &HBA
Private Const EM_LINEINDEX = &HBB
Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As Integer, ByVal MSG As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) As Integer

Private Sub TextBox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged

Dim line As Integer
Dim intIndex As Integer

'全行数を取得する
line = SendMessage(Me.TextBox1.Handle, EM_GETLINECOUNT, 0, 0)
'現在行の先頭の文字インデックスを取得する
intIndex = SendMessage(Me.TextBox1.Handle, EM_LINEINDEX, -1, 0)

If line > 7 Then
  '7行を超えるのでキャンセル
  TextBox1.Text = TextBox1.Text.Remove(intIndex, TextBox1.Text.Length - intIndex)
  TextBox1.SelectionStart = TextBox1.Text.Length
End If
End Sub
すみません。。。
↑の方法では、7行目の後にEnterキーを押して何か入力しようとすると文字が消えてしまうようです。
確認不足でした。出直してきますたらーっ(汗)
レスありがとうございます。

>ドンナ・ガバチョさん
KeyDownのタイミングではキー入力を弾けないかなーと思いまして。
SetFocusを使うというのは、指定行数以上になりそうだったら、
フォーカスをキャンセルするような処理を入れて…って認識で良い
でしょうか。

>りきゅあさん
1行の文字数は、半角全角が混在する時があり、常に一定の文字数には
ならないと思うので、制御が難しくないでしょうか?
バイト数縛りだけで、文字数は特に縛らないので…。

>えりざさん
大変参考になります、ありがとうございます。
キャレットが立つ場所の判定とかも必要になっちゃいますかね…
うーん思ったより難しいです。
楽しそうですねわーい(嬉しい顔)

えりざさんのソースを動かしてみたくなったので、
ちょっと追加して、動作させてみました。

あまりスマートな方法ではないけど、希望どおりの動作はするかな?

----------
Private strTextBoxSave As String = "" ' Textboxの値保存
Private intPosSave As Integer = 0 ' キャレット位置保存
Private blnEvent As Boolean = True ' イベント制御

Private Const EM_GETLINECOUNT = &HBA
Private Const EM_LINEINDEX = &HBB
Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As Integer, ByVal MSG As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) As Integer

Private Sub TextBox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles TextBox1.TextChanged

If Not blnEvent Then Exit Sub

Dim line As Integer
Dim intIndex As Integer

'全行数を取得する
line = SendMessage(Me.TextBox1.Handle, EM_GETLINECOUNT, 0, 0)
'現在行の先頭の文字インデックスを取得する
intIndex = SendMessage(Me.TextBox1.Handle, EM_LINEINDEX, -1, 0)

If line > 7 Then
' イベントが発生しないように
blnEvent = False
' 入力前の状態に、戻す
TextBox1.Text = strTextBoxSave
TextBox1.SelectionStart = intPosSave
blnEvent = True
Else
' Textboxの値と、キャレット位置の保存
strTextBoxSave = TextBox1.Text
intPosSave = TextBox1.SelectionStart
End If

End Sub

インデントがどうやっても入らなくて、見づらくてすみませんあせあせ(飛び散る汗)
スイマセン、りきゅあさんの指摘で気づいたんですが、大事なことを
書き忘れていました。
以下、補足させてください。

テキストボックスに入力した値は、DB(SqlServer2005)のvarcharの
フィールドに登録します。
なので、以下のようにバイトチェックをかけています。
※上でプロパティと書いていましたが、継承したテキストボックスを
使用しており、そこに組み込まれていたようです。標準のプロパティ
ではありません、失礼しました。

----------
Dim sjisEncoding As System.Text.Encoding = System.Text.Encoding.GetEncoding("Shift_JIS")
Dim inputByteCount As Integer = sjisEncoding.GetByteCount(Me.Text)
----------

上記を用い、KeyPressの際に最大に指定したバイトを超えているようなら
入力をキャンセル(e.handle=True)しています。

りきゅあさんのご指摘通り、Shift_JISに変換かけていますので、文字数で
チェックをするのは難しそうです…。
>Miyaさん
流用させていただいたところ、目的の動作を満たしています。
ありがとうございます、大変助かりました。

>りきゅあさん
ご指摘ありがとうございました。
文字コードまで頭が回ってなかったです(汗)。
>Miyaさん
補足していただきありがとうございました。
この方法なら問題なくできますね。
大変参考になりました。

>りきゅあさん
キャレットを末尾に移動する方法を教えていただきありがとうございました。
とてもお勉強になりました。今後に活かしたいと思います。
>ジンフィズさん
バイト単位のチェック、面倒ですよね。
ご希望の動作になっていたようで、良かったです。

>えりざさん
えりざさんのソースがとても参考になりました。
今度使わせていただきます。

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

Visual Basic User's Club 更新情報

Visual Basic User's Clubのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング