VB.NET RichTextBoxテキスト色付け高速化計画 | |
|
RichTextBox
今回はVB.NETを使用したRichTextBoxの色付けを考えて見ましょう。
考え方は、VB6と殆ど同じですが、今回はより実用に近い方法を紹介します。 最初はHTMLテキストのタグの色付けを行います。
スキーマ(設計図)を作成する
カラーテーブルの構造
カラーテーブルは通常下の様な形式になっている。
{\colortbl ;\red0\green0\blue255;\red255\green0\blue0;\red0\green128\blue0;} この中の、 "\red0\green0\blue255;" これはお分かりであろう色のRGBを表す、上の例は青である。 "\colortbl"は正式には"カラーテーブルのコントロールワード" と言う。 \red0、\green0、\blue255はそれぞれ、赤のインデックス、緑のインデックス、青のインデックスと呼ぶ。 頭に\が付く文字はコントロールワードを表しており、上場合は青、赤、緑の順番で並んでいる。 もちろん各インデックスはのRichTextBoxのテキストの色の設定で変わる。 このインデックスは";(セミコロン)"で区切られているが、この順番で1、2、3、.....と 番号が付けられる、たとえば文字の色だと\cf1、\cf2、\cf3...と、バックカラーは\cb1、\cb2、\cb3、... というコントロールワードになり、色付けが開始される文字の前に挿入される。 \cf0はでデフォルト値で黒ある、\cf0はカラーテーブルが無くても使用できるが、その他\cf1等は、 カラーテーブルとリンクしている。 たとえば"<div>"の中のdivを赤に設定したい場合、<\cf0 >となる、ただしこれは、 上のカラーテーブルを適用した場合である。 divの後に挿入される\cf0はこれ以降の文字が黒に設定されると言うことであり、 この結果は<div>となる。 つまりタグの中身を有る色\cfx(xはカラー番号)に設定したい場合は、"<"を 全て"<\cfx "に変換して、 ">"を"\cf0 >"に変換すればよいことになる。 (注意)\cfx、\cf0の後には半角の空白が必要です。
特定の文字を特定の色を設定する
では黒以外の色に設定された "Hello world;"の中のHelloの文字色を赤に
設定したい場合はどうなるのだろうか?
この場合は最初に"Hello world"が何色に設定されているかを調べる必要が有る。 なぜなら、Helloの文字に色を設定した後、world以降の色を元に戻さなければならないからだ。 それには、Rtfの中のHelloの文字の位置を取得して、それより前の"\cf"を探し、それに続く 番号を取得してそれをHelloの後ろに挿入すればよいことになる。 プログラム的には、最初に戻す方の色のコントロールワードを先に挿入してから、設定する色の コントロールワードを挿入する、これは一見逆の様に見えるが、先に設定のコントロールワードを 挿入してしまうと、HelloのRtfの先頭からの文字数が変化してしまい、戻す為のコントロール語の挿入が 多少面倒になるからだ、もちろん計算で出来ないことは無い。 戻す色を挿入した後は、設定したい色のコントロールワードをHelloの前に挿入すればよいことになる。 もしフォントテーブルに赤が(\red255\green0\blue0)が無い場合は、赤を追加する必要が有る。 更にフォントテーブルが無い場合は、フォントテーブルそのものを作成する必要が有る。 実際テキストの色が黒だけの場合フォントテーブルが無いのである。 その辺のところは実際のコードを参照していただきたい。 "\cfx Hello \cfy world" これがその設定である、\cfxは赤のカラー番号で、\cfyは赤を設定する前に既に設定されていた テキストの色の番号で有る。 通常\cfxの後に空白を設ける、\cfxの後に数字が来た場合、それが番号の続きなのか、 テキスト文なのか区別出来ないので、当然のことであろう。 ただし\cfxの後に\が来た場合は空白は必要ない、たとえ空白を入れても自動的に削除される。 最後にもう一つ重要なことが有る、フォントテーブルに赤が無くて追加した場合でも、 又既にフォントテーブルの中に赤がある場合でも、赤の番号を取得する必要が有る。 なぜなら挿入する"\cfx"の文字を作成する為に、"x"の値を知る必要があるからだ。 フォントテーブルが無くて自分で追加した場合は、設定したい文字は必ず\cf1となる、念のために。
具体的な構想
1、リッチテキストボックスのRtfからカラーテーブルを抜き出す。
Rtfの中からカラーテーブルを探すことは簡単である。
先ず「{\colortbl」を探し次に 来る「}」を探せばいいのである。 RichTextBox内にはカラーテーブルは一つ存在するか、全く存在しなかのどちらかである。 次の関数で引数にRtfを入れるとカラーテーブルが返ってくるものとしよう。
VB.NETのコード
Public Function GetColorTbl(ByRef strRtf As String) As String
この関数はカラーテーブルが無ければ、空白文字を返すものとする。
2、抜き出したカラーテーブルに設定したい色を追加する。
これはチョッと工夫が必要である、先ず関数の仕様を決めてしまう。
VB.NETのコード
Public Function AddColor(ByRef strRtf As String, _
この関数の第1引数にRtfを設定し第2引数にColorクラスの色を入れると、
カラーテーブルに色が追加されるものとする。
さて追加したい色を仮に赤とするなら「\red255\green0\blue0」を挿入することになる。 実際にプログラムで設定する場合は、Colorクラスを使用するから、Colorクラスから、 このRtfの色の形式に直す関数が必要となる。 VB.NETのコード
Public Function GetColorString(ByVal objColor As Object) As String
この関数の引数にColorクラスを入れると、Rtf形式の色要素が返ってくるものとする。
strRtfColor = GetColorString(Color.Red)
等として呼び出せば"\red255\green0\blue0"が返ってくるものとする。
引数の形式がObjectになっているのは、引数にColorクラスの色か、又はバイト配列で255,0,0等と 入れるとRtfのカラー文字列が返って来る仕様にした為である。 さてここで色を挿入すると書いたが、既にカラーテーブルにその色が存在する否か、 挿入する前に調べる必要が有る。 そのために、カラーテーブルから色コントロールワードを取得して、文字の配列に入れる関数を作ろう。 Private Function GetColorArray(ByVal strRtf As String) As String()
この関数で、既に設定されている色の文字列が、配列で返される、設定色が存在するか否かは、
この配列に色を調べれば良いことになり、もし存在していなかったら配列の上限を一つ増やして、
そこに新しい色を加え、その後で配列を元にカラーテーブルを作成する。
これで新しいカラーテーブルの完成である。
3、色を追加したカラーテーブルを元のRtfの中のカラーテーブルと入れ替える
テーブルの入れ替えは、次の関数で行う。
VB.NETのコード
Public Function ChangeCtbl(ByVal strRtf As String, _
見ての通り、第1引数にRtfを第2引数に、2で作成した新しいカラーテーブルを入れる。
これは簡単である。 4、設定したいカラーの色番号を、新しいカラーテーブルから取得する。
カラーテーブルに新しく色を追加した場合でも、既に色が存在する場合でも、テキストに設定
する色の番号を取得する必要が有る。
これは3で作成した、色を配列に入れる関数が使用出来る、配列の番号と色の番号が一致するからである。 5、Rtf上で現在設定してある色を待避する。
タグの色付けに関しては最初に説明した、先ず現在の色を待避させる。
これは"<"を"<\cfx"に置換した場合に既にタグに色が設定されていた場合の 二重設定を防ぐ為である。 この方法はチョッとトリッキーな方法を使おう。 strRtf = strRtf.Replace("<\cf", Chr(2))
Rtf内の"<\cf"をキャラクターコードの2に全て変換するコードである。
Chr(2)はRtf上では絶対使うことの無い文字であり、この文字に一時置き換える。 こうすると色が既に設定してあるタグは全てChr(2)に変換される為に、次のタグの変換が 行われないのである。 当然カラー番号が挿入された後元に戻しておく必要が有る。
6、タグ一斉変換「<」タグを「<\cfx 」に入れ替える。
xはその時で異なる番号である
タグの<を一斉に書き換えることは簡単である。 設定したカラーの番号がstrColorString(例:\cf2)であると仮定すると、
strRtf = strRtf.Replace("<", strColorNoString)
これだけである、更にタグの>を元に戻す色に置き換えなくてはならない、
strRtf = strRtf.Replace(">", "\cf0>")
となる、この場合タグの<>はデフォルトの色、つまり黒を想定している。
7、「>」タグを「\cf0 >」に入れ替える。
これはもうお分かりであろう。
8、待避した色を元に戻す。
最後は待避したタグの色を元に戻せばおしまいである。
strRtf = strRtf.Replace(Chr(2), "<\cf")
ユニコードとSift-Jisの2バイトコード
VB.NETでは文字は全てユニコードで取り扱う、ところがRtfでは日本語の文字は、
シフトJISコードをASCII形式で表した表記法が使われます。
しかもRtfの場合、"\'上位バイト\'下位バイト"と変換されます。 たとえば"あ"は\'82\'a0となります。 "abc"などの1バイト文字はそのままです。 したがってRtf内で有る2バイト文字を探す場合は、先ずユニコードからSift-Jisに変換して それが2バイト文字なら上下のバイトに"\'"を付加してRtfの文字形式に直す。 VB.NETのコード
Public Shared Function getEncodeString(ByVal strS As String) As String
この関数でユニコードの文字をRtf形式に直します。
この関数はタグの色付けには使用しませんが、Rtfの中から文字を検索して色付けを 行う場合に使用します。 ユニコードに関しては「 Unicode入門 」を御覧戴きたい。 さて次は関数の実装である。 |