[VB.NET]TextBoxで無限アンドゥを実現 | 独り言はもうやめませんか

[VB.NET]TextBoxで無限アンドゥを実現

VisualBasicでメモ帳のようなものを作ったとき、「元に戻す」や「やり直す」を実装する必要があるかと思います。


フォームに「TextBox1」を貼りつけた場合、「Textbox1.Undo()」とすることで「元に戻す」を実現できますが、元に戻せるのは1回のみで、Wordのようにいくつも前の操作を取り消すことができません。


ということで、無限アンドゥ、リドゥを自作してみました。


'-----ここから-----

    Private Structure UnDn        'アンドゥ、リドゥに必要な情報を保存する
        Dim uSellength As Long    '選択された文字の長さ
        Dim uSelstart As Long     'カーソルの位置
        Dim uText As String       'テキストの中身
    End Structure

    Dim UndoTable() As UnDn
    Dim UndoPossition As Long
    Dim TextPossition As Long           '現在アンドゥ、リドゥしている位置
    Public TextchangeFlag As Boolean    'テキストを編集されたときはFalse、アンドゥ、リドゥ中はTrue

    Private Sub Undo()
        If TextPossition <> 0 Then  'アンドゥできるかどうか

            TextchangeFlag = True   'アンドゥによるテキストの変化を記録させない
            TextPossition = TextPossition - 1   '一つ前の情報へ戻る
            TextBox1.Text = UndoTable(TextPossition).uText   'Text1にひとつ前に編集したテキストの内容を入れる
            TextBox1.SelectionStart = UndoTable(TextPossition).uSelstart  'Text1にひとつ前に編集したテキストのカーソルの位置を入れる
            TextBox1.SelectionLength = UndoTable(TextPossition).uSellength  'Text1にひとつ前に編集したテキストの選択範囲の長さを入れる

            TextBox1.ScrollToCaret()       'カーソル位置に合わせてスクロール

        End If
    End Sub

    Private Sub Redo()
        If TextPossition < UndoPossition Then 'リドゥできるかどうか

            TextchangeFlag = True   'リドゥによるテキストの変化を記録させない
            TextPossition = TextPossition + 1   '一つ先の情報へ進む
            TextBox1.Text = UndoTable(TextPossition).uText  'Text1にひとつ先に編集したテキストの内容を入れる
            TextBox1.SelectionStart = UndoTable(TextPossition).uSelstart  'Textbox1にひとつ先に編集したテキストのカーソルの位置を入れる
            TextBox1.SelectionLength = UndoTable(TextPossition).uSellength  'Textbox1にひとつ先に編集したテキストの選択範囲の長さを入れる

            TextBox1.ScrollToCaret()  'カーソル位置に合わせてスクロール
        End If
    End Sub

    Private Sub TextBox1_TextChanged(ByVal sender As ObjectByVal e As System.EventArgs) Handles TextBox1.TextChanged
        If TextchangeFlag = False Then 'アンドゥ、リドゥによる変化ではないかをチェック

            '配列を再定義
            TextPossition = TextPossition + 1
            ReDim Preserve UndoTable(TextPossition) '配列をひとつ増やす

            UndoPossition = TextPossition 'アンドゥしたときに、最後までアンドゥしきったかをチェックするために使用

            '配列にそれぞれの値を格納
            UndoTable(TextPossition).uSellength = TextBox1.SelectionLength
            UndoTable(TextPossition).uSelstart = TextBox1.SelectionStart
            UndoTable(TextPossition).uText = TextBox1.Text

        Else 'アンドゥ、リドゥの場合はこちらへ

            TextchangeFlag = False 'ここでフラグを戻しておく

        End If
    End Sub

'-----ここまで-----


右端が切れて見えないでいますが、すべてコピーペーストしてください。テキストボックスの名前は「TextBox1」としています。ボタンのクリックイベントなどに「Undo()」「Redo()」と書けばそのまま使えます。


個人利用であればご自由に。このサイトへリンクを張ってくださるとうれしいです。