TextBoxで行数を表示してみる(サブクラス) VB2005

VB Tips And Sample(HOME)(VB.NET Sample インデックス)

TextBoxで行数を表示してみる(サブクラス) VB2005


テキストボックスの行番号
 

前回はRichTextBoxで行ってみた、行番号を表示するプログラムを
今回はTextBoxで行ってみる。

ポイントは、テキストボックスにはスクロールイベントが無いので
ウィンドウズのメッセージを取得する必要がある事。
そのために、テキストボックスを継承したクラスを作り(昔はサブクラスと言った。今でも言うのかな?)
そのクラスをフォームに配置する必要がある。(本当は配置ではなく置き換えるだけ)
以下に紹介した他にも方法があり、MSのサイトに掲載されていました。
Visual Basic .NET または Visual Basic 2005 を使用して Windows フォームでウィンドウをサブクラス化する方法

※この方法で実装した行番号の表示ですが、マウスでドラッグしてスクロールしている最中は1・2行ズレてしまう欠点がある。
離せば大丈夫なのですが・・・・・

 
テキストボックスを継承したクラスを作成

Public Class SCTextBox
    'テキストボックスを継承する
    Inherits TextBox

    'メッセージの定数
    Private Const WM_VSCROLL As Integer = &H115

    'イベントを作成
    Public Event TextBoxScroll(ByVal sender As Object, ByVal e As EventArgs)

    'ウィンドウズメッセージをキャッチするためにWndProcオーバーライドする
    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

        Select Case m.Msg

            Case WM_VSCROLL
'イベントを起こす
                RaiseEvent TextBoxScroll(Me, New EventArgs)
        End Select

        MyBase.WndProc(m)

    End Sub
End Class


フォームに作ったSCTextBoxクラスを配置する

フォームにテキストボックスを継承したクラスを配置する手順ですが、
まず、通常のテキストボックスをフォームに貼り付けて、
そのあと、「ソリューションエクスプローラ(ファイルが並んで表示されている窓)」でファイルを全て表示するモードに切り替えて、
Form.Designer.vb
を表示させ、開きます。
で、下の赤字で書いている二箇所を、作成した「SCTextBox」に書き換えます。
やっていることは、通常のテキストボックスを自作のテキストボックスに置き換えているという作業。


<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form2
    Inherits System.Windows.Forms.Form

    'フォームがコンポーネントの一覧をクリーンアップするために dispose をオーバーライドします。
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Windows フォーム デザイナで必要です。
    Private components As System.ComponentModel.IContainer

    'メモ: 以下のプロシージャは Windows フォーム デザイナで必要です。
    'Windows フォーム デザイナを使用して変更できます。  
    'コード エディタを使って変更しないでください。
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
        Me.TextBox1 = New MyEdit2.SCTextBox のように書き換える
        Me.ScTextBox1 = New MyEdit2.SCTextBox
        Me.SuspendLayout()
        '
        'TextBox1
        '
        Me.TextBox1.Anchor = System.Windows.Forms.AnchorStyles.None
        Me.TextBox1.Location = New System.Drawing.Point(68, 3)
        Me.TextBox1.Multiline = True
        Me.TextBox1.Name = "TextBox1"
        Me.TextBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both
        Me.TextBox1.Size = New System.Drawing.Size(441, 248)
        Me.TextBox1.TabIndex = 0
        '
        'ScTextBox1
        '
        Me.ScTextBox1.Anchor = System.Windows.Forms.AnchorStyles.None
        Me.ScTextBox1.Location = New System.Drawing.Point(3, 3)
        Me.ScTextBox1.Multiline = True
        Me.ScTextBox1.Name = "ScTextBox1"
        Me.ScTextBox1.Size = New System.Drawing.Size(59, 248)
        Me.ScTextBox1.TabIndex = 1
        '
        'Form2
        '
        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 12.0!)
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        Me.ClientSize = New System.Drawing.Size(521, 263)
        Me.Controls.Add(Me.ScTextBox1)
        Me.Controls.Add(Me.TextBox1)
        Me.Name = "Form2"
        Me.Text = "Form2"
        Me.ResumeLayout(False)
        Me.PerformLayout()

    End Sub
    'Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
    Friend WithEvents TextBox1 As SCTextBox 'のように書き換える
    Friend WithEvents ScTextBox1 As MyEdit2.SCTextBox
End Class


残るはフォームにプログラムを書く

Public Class Form2

    Private 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 Const EM_GETFIRSTVISIBLELINE As Short = &HCES

    Private Sub TextBox1_TextBoxScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.TextBoxScroll
        'クラスで作成したイベント
        ' Debug.Print("sssss")
        SetLineNo()
    End Sub

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

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        SetLineNo()
    End Sub

    Private Sub SetLineNo()
        '行番号をふる
        Dim row As Integer
        '先頭の行数を取得する
        row = SendMessage(TextBox1.Handle, EM_GETFIRSTVISIBLELINE, 0, 0) + 1

        Me.ScTextBox1.Text = row.ToString

        Dim i As Integer
        Dim lines As String = ""
        Do Until i = 60 '一度に表示できる行数が60ぐらいとして設定 モニタによるので 120でも可

            If lines = "" Then
                lines = GetFormat(i + row)
            Else
                lines = lines & vbCrLf & GetFormat(i + row)
            End If

            i = i + 1
        Loop
        Me.ScTextBox1.Text = lines
    End Sub

    Private Function GetFormat(ByVal row As Integer) As String
        '文字を5桁右寄せにする
        Dim i As Integer
        i = Len(row.ToString)
        Select Case i
            Case 1
                Return "    " & row.ToString
            Case 2
                Return "   " & row.ToString
            Case 3
                Return "  " & row.ToString
            Case Else
                Return " " & row.ToString
        End Select
    End Function
End Class




VB Tips And Sample(HOME)(VB.NET Sample インデックス)