DOBON.NET DOBON.NETプログラミング掲示板過去ログ

RichTextBoxで行単位編集

環境/言語:[Windows2000 VB.NET NET Framework1.1]
分類:[.NET]

こんにちは、はじめまして。.NETを初めて以来こちらにお世話になっています。
早速質問させてください。
リッチテキストボックスにて指定行の更新・削除にて行き詰まってしまい困り果てています。
御教示いただけますよう宜しくお願いします。

リッチテキストボックスに書式付(色、太文字)で1000行くらい書いた(ApendText等)ものにたいして
例えば300行目を消すとか、500行目の文字列を書き換えるなどの処理です。

計算結果などのログ出力に用いていまして、ユーザーの編集はありません。
更新及び削除は行単位をコーディングで行います。

For文で指定行の先頭までのTextLengthを調べ、指定行を選択して、更新・削除・・・
などとやっていますと、ものすごく時間がかかってしまって使い物になりません。
最終行の更新や削除などは数秒かかってしまいます。

RichTextBox.Linesを別Arrayにコピーしてみたり、Redimしてみましたが、それでは書式が失われてしまいます。

#RichTextBoxを使用したい目的は、行内に存在する規定の文字列に色を使いたいだけなのです。


どうか宜しくお願いします。
> RichTextBox.Linesを別Arrayにコピーしてみたり、Redimしてみましたが、それでは書式が失われてしまいます。
>
> #RichTextBoxを使用したい目的は、行内に存在する規定の文字列に色を使いたいだけなのです。

ListViewを使用してみるとラクかもしれませんね。
>
> ListViewを使用してみるとラクかもしれませんね。

お答えのとおり始めはListViewを使用しておりました。
しかし、一行のなかの指定文字だけ色をつけるっというのができなくて
断念しました。。。

なんとかよろしくお願いします。
API関数を使って置き換えればかなり高速に処理できます。
現在のファイルサイズや行数及び具体的な処理時間を教えて頂ければ
比較する事も可能ですが。
一応私がやっているコードを載せます。

    '--------------------------------------------------------------------------
    '  Function : リッチテキストボックスを更新
    '  Parameter: <Message> 説明文
    '           : <Save>省略可、ログファイルに追記保存。Default=False
    '           : <Color>省略可、文字の色。Default=Black
    '           : <Lines>省略可、更新する行を指定。Default=0(追記モード)
    '           : <FontSize>省略可、更新する行のフォントサイズを指定。Default=10
    '           : <BoldStyle>省略可、更新する行の太文字を指定。Default=False
    '  ReturnVal:
    '--------------------------------------------------------------------------
    Private Sub TestMessage(ByVal Message As String)
        Dim CurLen As Integer = RichTextBoxTestMessage.Text.Length      '更新前のテキスト長
        Dim CurLines As Integer = RichTextBoxTestMessage.Lines.Length   '更新前の行数

        If Lines = 0 Then
            '更新行=0の場合は追記
            RichTextBoxTestMessage.AppendText(Message & vbCrLf)
            RichTextBoxTestMessage.Select(CurLen, Message.Length)
        ElseIf Lines > CurLines Then
            '更新行が現在より大きい場合
            '0行の場合はループしない
            If CurLines = 0 Then Lines -= 1
            '不足分を改行で埋める
            Dim cr, p As Integer
            For cr = 0 To Lines - CurLines - 1
                RichTextBoxTestMessage.AppendText(vbCrLf)
            Next
            RichTextBoxTestMessage.AppendText(Message & vbCrLf)
            p = RichTextBoxTestMessage.Find(Message, RichTextBoxFinds.Reverse)
            RichTextBoxTestMessage.Select(p, Message.Length)
        ElseIf CurLines >= Lines Then
            '更新行が現在より小さいか同じ場合
            '更新行の先頭をさがす
            Dim i, Sea As Integer
            For i = 1 To Lines - 1
                Sea += RichTextBoxTestMessage.Lines(i - 1).Length + 1
            Next
            RichTextBoxTestMessage.Select(Sea, RichTextBoxTestMessage.Lines(Lines - 1).Length)
            RichTextBoxTestMessage.SelectedText = Message
            RichTextBoxTestMessage.Select(Sea, Message.Length)
        End If
        'スタイル、サイズを更新
        If BoldStyle = False Then
            RichTextBoxTestMessage.SelectionFont = New Font(RichTextBoxTestMessage.Font.FontFamily, FontSize, FontStyle.Regular)
        Else
            RichTextBoxTestMessage.SelectionFont = New Font(RichTextBoxTestMessage.Font.FontFamily, FontSize, FontStyle.Bold)
        End If

        '文字色を決定
        Dim col As System.Drawing.Color
        Select Case LineColors
            Case Colors.Black : col = Color.Black
            Case Colors.Blue : col = Color.Blue
            Case Colors.Green : col = Color.Green
            Case Colors.Red : col = Color.Red
        End Select
        '色変更
        RichTextBoxTestMessage.SelectionColor = col

        '非選択状態へ
        'HideSelection=Falseが条件でオートスクロール
        RichTextBoxTestMessage.SelectionStart = RichTextBoxTestMessage.TextLength
        RichTextBoxTestMessage.SelectionLength = 0
        Application.DoEvents()

        'ログファイルに追記する
        If Save = True Then
            Try
                TestLogSave(Message)
            Catch ex As Exception
                Throw ex
            End Try
        End If
    End Sub

    '--------------------------------------------------------------------------
    '  Function : リッチテキストボックスをクリア
    '  Parameter: <Lines>省略可、最終行から削除する行数を指定。Default=0(全削除モード)
    '           :        ex. 1 = 最終行から1行削除、5 = 最終行から5行削除
    '  ReturnVal:
    '--------------------------------------------------------------------------
    Private Sub TestMessageErase(Optional ByVal Lines As Integer = 0)
        If Lines >= RichTextBoxTestMessage.Lines.Length - 1 OrElse Lines = 0 Then
            RichTextBoxTestMessage.Clear() '全削除
            Return
        End If

        '更新行の先頭をさがす
        Dim i, Sea, loc As Integer
        Dim strBuffer As String

        loc = RichTextBoxTestMessage.Lines.Length - Lines
        For i = 1 To loc - 1
            Sea += RichTextBoxTestMessage.Lines(i - 1).Length + 1
        Next
        RichTextBoxTestMessage.Select(Sea - 1, RichTextBoxTestMessage.Text.Length)
        RichTextBoxTestMessage.SelectedText = Environment.NewLine
        Application.DoEvents()
 
    End Sub
■No10029に返信(うなさんの記事)

お早うございます。平ちゃんです。

> こんにちは、はじめまして。.NETを初めて以来こちらにお世話になっています。
> 早速質問させてください。
> リッチテキストボックスにて指定行の更新・削除にて行き詰まってしまい困り果てています。

> #RichTextBoxを使用したい目的は、行内に存在する規定の文字列に色を使いたいだけなのです。

> RichTextBox.Linesを別Arrayにコピーしてみたり、Redimしてみましたが、それでは書式が失われてしまいます。
>

ArrayList に 全行のテキスト、書式等の構造体またはクラスを記憶させ検索や編集した結果を表示する為にRichTextBoxにArrayListからコピーするとスピードアップする気がしますがどうでしょうか?
書式などもコピーすると逆に遅くなるのかな?

またArrayList をDataGrid に連結できれば速いと思いますが書式は反映できるのかな?

行き詰っていれば試してみて下さい。
■No10053に返信(平ちゃんさんの記事)
> 書式などもコピーすると逆に遅くなるのかな?

RichText.RTFを文字列で取得、SplitでArrayにいれてから
削除をおこないRTFを書き戻すと劇的に早くできました。
単純に削除の場合はRTFのヘッダ文やフッタ文を考慮すれば簡単に割り出せるの
で簡単でした。

しかし編集だとどうしても消すのと違い、文字を選択しなくちゃならないのは
変わらず、情報量の多いRTFでは余計に遅くなります。

SendMessageとかで選択しても2バイト文字が混在したりしていると
うまく選択できません・・・

引き続きここのあたりの処理についてもアドバイスお願いします。
■No10079に返信(うなさんの記事)

お早うございます。
興味がありますので、実験してみようと思います。
具体的な削除、編集の方法ですが行番号が与えられていてその行に対して削除、編集を行うのでしょうか。
(この場合の行番号とは先頭からの改行文字の数ー1です。)
それとも特定の文字を先頭から順次検索してヒットしたところで編集するのでしょうか。
この場合は同じ文字列がある場合の処理はどのようにするのでしょうか?
■No10083に返信(平ちゃんさんの記事)
> ■No10079に返信(うなさんの記事)

自己レスです。

リッチテキストは行単位での管理ではないのですね。
すみません。 無知でした。

>削除をおこないRTFを書き戻すと劇的に早くできました。

ひょっとしてこれは削除場所により、書式が失われるかもしれませんね。

も少し、調べてみますがお役に立てない気がします。 ・・・
(期待しないで下さい 。。。)
> SendMessageとかで選択しても2バイト文字が混在したりしていると
> うまく選択できません・・・

先にも書きましたが、API で置き換え処理をすれば、半角・全角が混在していても
問題ありません。
又、””(空文字)と置き換えれば削除する事ができます。
処理時間は、計測できない位の速度で処理できます。
(0〜0.001秒位でした。)

 VB6.0 ですが、下記サイトで...........
http://www.bcap.co.jp/hanafusa/vbbbs/wforum.cgi?no=2611&reno=2589&oya=2589&mode=msgview&page=0
>平ちゃんさん
>リッチテキストは行単位での管理ではないのですね。
>すみません。 無知でした。
>>削除をおこないRTFを書き戻すと劇的に早くできました。
>ひょっとしてこれは削除場所により、書式が失われるかもしれませんね。
>も少し、調べてみますがお役に立てない気がします。 ・・・
>(期待しないで下さい 。。。)
ちゃんと回答ができないのならば、答えるのをやめていただきませんか?
かなり迷惑です。少し前のトピックでも同じようなことをして、質問者と他の回答者を混乱させましたよね?
答えることはよいことですが、こんなに間違いばかり続くのは問題ありだと思っています。

(予想ではなくしっかりと調べた上での答えを書きましょう)
  • 題名: Re[6]: おせっかいな忠告
  • 著者: 平ちゃん
  • 日時: 2005/03/25 19:24:54
  • ID: 10105
  • この記事の返信元:
  • この記事への返信:
    • (なし)
  • ツリーを表示
2005/03/25(Fri) 19:25:54 編集(投稿者)

■No10101に返信(忠告さんの記事)

皆さん 今日は いつもお世話になります。
平ちゃんです。

> ちゃんと回答ができないのならば、答えるのをやめていただきませんか?
> かなり迷惑です。少し前のトピックでも同じようなことをして、質問者と他の回答

>者を混乱させましたよね?
> 答えることはよいことですが、こんなに間違いばかり続くのは問題ありだと思って

>います。
>
> (予想ではなくしっかりと調べた上での答えを書きましょう)

仰るとおりです。
私としては質問者が手詰まり状態でなにも出来ない状態でスレッドから消えていくな

ら答えでなく、案を出したつもりで、それに対して質問者がどうするかは、自由です


私が質問者なら例え間違いの考え方でも沢山スレッドを頂ければそこから解決の手口

が発見できる場合がありそのほうが幸せです。
考え方の相違ですが、大体において仰るように迷惑かもしれません。
ただ何も発言しないで文句だけいうのもどうでしょうか?


うなさんへ
花ちゃんさんからスレッドがでてますので当然そちらも考慮してください。


さて今回の私の考え方ですが実験の結果次のようにすればいけました。

最初に元になるデータがリッチテキストボックスにあるとします。
次の手順でArrayList に全行 保存します。

@ データは rtf形式 で1行ずつ個別に作成する
  SelectedRtf プロパティで各行の関連をなくし個別行管理する。

A @で作った各行を全てArrayList に保存する
  (Text部 と Rtf部 の両方)

元になるデータを表示しているリッチテキストボックスを全てArrayListのデータに置

き換えます。これは各行の関連性をなくするためです。
(ここまでは準備段階で 結構時間が掛かります。といっても1000行、各行20

文字で5秒ていど)

これ以降はArrayList の内容で操作していきます。
例えば135行編集ならArrayList(134)にありますので
ArrayList(0)〜ArrayList(133)のText部文字数にEnvironment.NewLineの文字

数を考慮した文字数+1がデータ表示しているリッチテキストボックスの該当位置の先

頭になります。

このようになりますのでデータ表示しているリッチテキストボックスの特定の書式付

文字の選択がすばやく出来ます。

これを踏まえて
削除ならArrayList(134)を削除すると共に選択した部分のSelectedRtf="" でい

いです。

編集の場合はArrayList(134)を別の編集用のリッチテキストボックス

(Visible=False)に1行書き出しコードで任意に編集し再びArrayList(134)にも

どします。
あとは前と同様に選択した部分のSelectedRtfをArrayList(134)のRtf部で置き換

えます。

実験の結果ですが1100、1行当たり20文字で 色付けの編集は瞬時(数十mS)で

できました。

この編集方法はリッチテキストボックスによるコード編集ですからうなさんの内容に

あってると思います。


問題点として
各行が独立しているのでrtf形式が冗長となりメモリ消費量が大きくなる。
最初ArrayListに読み込むときと
最初の1回だけArrayListから再書き込みする時に多少時間が掛かる。(これは次回起

動時には既にこのようになっているので不要)


なるべく解りやすく書いたつもりです。宜しく

DOBON.NET | プログラミング道 | プログラミング掲示板