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

テキストボックス内の改行位置について

環境/言語:[WindowsXP、VB.NET]
分類:[.NET]

テキストボックスでマルチライン入力を行う際、
改行の位置、スペースの位置を目視できるようにしたいのですが
(よくあるテキストエディタのような表示をしたいのです)
よい方法をご存知の方、いないでしょうか?

Replace関数などで該当の文字を置き換えてやればよいと思うのですが、
入力の制御が非常に複雑になりそうで、できれば避けたいです。

市販のOCX等も検討しているのですが、よいものが見つかりません。
よろしくお願い致します。
■No6224に返信(ゆうこりんさんの記事)

 ゆうこりんさん、こんにちは。深山です。

> テキストボックスでマルチライン入力を行う際、
> 改行の位置、スペースの位置を目視できるようにしたいのですが
> (よくあるテキストエディタのような表示をしたいのです)
> よい方法をご存知の方、いないでしょうか?

 過去ログに以下のようなやり取りがありました。全て自前で描画してやるのが王道のようです。

テキストエディタの特殊文字
http://dobon.net/vb/bbs/log3-7/4062.html


 でも、それだと大変ですよね。ちょーっとチラツキが気になるかも知れませんけど、
次のように WndProc メソッドで WM_PAINT メッセージをキャッチして、必要な記号を
描画するという方法なら簡単にできるかと思います。
# もちろん、それなりですが(^_^;) もう少し工夫すれば多少は改善されるかも?

 以下は RichTextBox クラスを継承した例です。改行位置に『↓』を描画してみました。
(正規表現を利用する為に System.Text.RegularExpressions 名前空間を使用しています。)


    private const Int32 WM_PAINT = 0x000F;

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        base.WndProc(ref m);
        switch (m.Msg)
        {
            case WM_PAINT:
                Marking();
                break;
        }
    }

    private void Marking()
    {
        using (Graphics g = this.CreateGraphics())
        using (Brush brush = new SolidBrush(Color.DarkGreen))
        {
            // 改行検索
            Regex regex = new Regex("\n");
            foreach (Match match in regex.Matches(this.Text))
            {
                // 改行位置取得
                Point point = this.GetPositionFromCharIndex(match.Index);
                point.Offset(-2, 2);    // 出力位置微調整(お好みに応じて)

                // 改行記号(ここでは"↓")描画
                g.DrawString("↓", this.Font, brush, point);
            }
        }
    }

# TextBox で行う場合は EM_POSFROMCHAR メッセージで GetPositionFromCharIndex メソッドの
# 代用ができる‥‥かなぁ?(未確認)
>  でも、それだと大変ですよね。ちょーっとチラツキが気になるかも知れませんけど、
> 次のように WndProc メソッドで WM_PAINT メッセージをキャッチして、必要な記号を
> 描画するという方法なら簡単にできるかと思います。

確かWM_PAINTは”ポスト”されると思うので、このままだと日本語変換などができない
おそれがあります。あまりいい方法ではありませんが、WM_IME_COMPOSITION
などを取得して変換の有無をフラグに立て、delegateで非同期にに描画
したほうがいいと思います。

#しかしながら、テキスト量が多くなるとつらくなるとおもうので、
#やはり一から作ったほうが…(^^;
2004/09/25(Sat) 03:40:52 編集(投稿者)

■No6315に返信(antさんの記事)

 antさん、こんばんは。深山と申します。

> 確かWM_PAINTは”ポスト”されると思うので、このままだと日本語変換などができない
> おそれがあります。あまりいい方法ではありませんが、WM_IME_COMPOSITION
> などを取得して変換の有無をフラグに立て、delegateで非同期にに描画
> したほうがいいと思います。

 はい。この方法では日本語変換できません(爽)
 簡単に実装してる分、機能もそれなりということで‥‥って先の投稿にその旨一言
添えておくべきでしたね。申し訳ありませんm(__)m

 そして毎度のフォローありがとうございます!
# No6099 や No6149 のスレッドでは色々勉強させて頂きました(^^)/


> #しかしながら、テキスト量が多くなるとつらくなるとおもうので、
> #やはり一から作ったほうが…(^^;

# やっぱりそうですよね(^_^;)
# でも折角(?)なので、この方向のままもう少し遊んでみようと思います〜。



■追記

 その後改良を加えて(と言っても知れてますが(^_^;))、次のようにしてみました。

 ・プライベート メンバに再描画用フラグA、日本語入力中フラグBを追加
 ・OnTextChanged 、 OnHScroll 、 OnVScroll 、 OnResize メソッドをオーバーライドし、
  フラグAを true にする処理を追加
 ・WM_IME_STARTCOMPOSITION メッセージ受信時にフラグBを true にする処理を追加
 ・WM_IME_ENDCOMPOSITION メッセージ受信時にフラグBを false にする処理を追加
 ・WM_PAINT メッセージ受信時、フラグAが true 且つ フラグBが false であれば
  フラグAを false にして描画処理を行うよう修正

 まだ数点問題は残っているものの、日本語入力もできるようになりましたし、前よりは
随分マシになったかと思います。とは言え‥‥やっぱり重いですね(ーー;)
 クライアント領域内以外は処理しないようにする等、検索&描画処理にも幾ばくか手を
入れてみたのですけど、焼け石に水でしたorz

# テキストエディタを造るのは大変だなぁと改めて感じた秋の夜更け‥‥<挫折経験のある人(汗)
■No6316に返信(深山さんの記事)

深山さん今日は
以前にもお世話になりました。有難うございます。
私はVB.netの初心者ですので今回に件に関して深山様が言っている事が理解できません。
1.深山様のコードでどのような動作をするのか?
2.当初の(ゆうこりんさん)質問は単に改行、スペースを別の文字に置き換える方法を考えているだけではないのか?
3.私はVB.Netの限界がどれだけなのか良く解らないのですがVB.Netで出来る事はVB.Netでしたい。

それで次のようなサンプルプログラムを作ってみました。
このプログラムの欠点は多々あるとは思いますが出来ればVB.Netでの欠点でAPIを使用すればここが良くなる等を指摘して頂きければ非常に嬉しいのですが。
コピペで動作すると思います。

***サンプルプログラム****


Public Class Form1
Inherits System.Windows.Forms.Form

#Region " Windows フォーム デザイナで生成されたコード "

Public Sub New()
MyBase.New()

' この呼び出しは Windows フォーム デザイナで必要です。
InitializeComponent()

' InitializeComponent() 呼び出しの後に初期化を追加します。

End Sub

' Form は dispose をオーバーライドしてコンポーネント一覧を消去します。
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

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

' メモ : 以下のプロシージャは、Windows フォーム デザイナで必要です。
' Windows フォーム デザイナを使って変更してください。
' コード エディタは使用しないでください。
Friend WithEvents Rtedit As EXRichTextBox
Friend WithEvents RTNo As System.Windows.Forms.RichTextBox
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.Rtedit = New Ritctext.EXRichTextBox()
Me.RTNo = New System.Windows.Forms.RichTextBox()
Me.SuspendLayout()
'
'Rtedit
'
Me.Rtedit.Location = New System.Drawing.Point(102, 40)
Me.Rtedit.Name = "Rtedit"
Me.Rtedit.Size = New System.Drawing.Size(376, 104)
Me.Rtedit.TabIndex = 0
Me.Rtedit.Text = "RichTextBox1" & Microsoft.VisualBasic.ChrW(10) & "abcdefgh" & Microsoft.VisualBasic.ChrW(10) & "123456" & Microsoft.VisualBasic.ChrW(10) & "ijklmn" & Microsoft.VisualBasic.ChrW(10) & "78opqrstuvw" & Microsoft.VisualBasic.ChrW(10) & "xyz" & Microsoft.VisualBasic.ChrW(10) & "abcde" & Microsoft.VisualBasic.ChrW(10) & "あいうえお" & Microsoft.VisualBasic.ChrW(10) & "かきくけこ" & Microsoft.VisualBasic.ChrW(10) & "さしすせそ" & Microsoft.VisualBasic.ChrW(10) & "たち伝と" & Microsoft.VisualBasic.ChrW(10) & _
"なににねの" & Microsoft.VisualBasic.ChrW(10) & "はひふへほ" & Microsoft.VisualBasic.ChrW(10) & "まみむめも" & Microsoft.VisualBasic.ChrW(10) & "やゆよ" & Microsoft.VisualBasic.ChrW(10) & "らりるれろ"
'
'RTNo
'
Me.RTNo.BackColor = System.Drawing.SystemColors.InactiveCaptionText
Me.RTNo.Location = New System.Drawing.Point(48, 40)
Me.RTNo.Name = "RTNo"
Me.RTNo.ReadOnly = True
Me.RTNo.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None
Me.RTNo.Size = New System.Drawing.Size(56, 104)
Me.RTNo.TabIndex = 4
Me.RTNo.Text = "*00000: " & Microsoft.VisualBasic.ChrW(10) & "*00001: " & Microsoft.VisualBasic.ChrW(10) & "*00002: " & Microsoft.VisualBasic.ChrW(10) & "*00003: " & Microsoft.VisualBasic.ChrW(10) & "*00004: " & Microsoft.VisualBasic.ChrW(10) & "*00005: " & Microsoft.VisualBasic.ChrW(10) & "*00006: "
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 12)
Me.ClientSize = New System.Drawing.Size(560, 366)
Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.RTNo, Me.Rtedit})
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)

End Sub

#End Region




'リッチテキストの各行の行番号の文字書式は次の通り。
' "*00000 " 'で6文字
'ユーザーはユーザー領域 Rtedit のリッチテキストボックスに記入
'ユーザーがスクロールすると行番号を書き換える
Const EditLines As Integer = 6 'エッジト行=6
'コントロール内の先頭文字の位置(point)
Dim TopPt As New Point(2, 5)
Dim LineNo() As String


Private Sub Rtedit_KeyPress(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Rtedit.KeyPress
Dim i, j As Integer
i = Me.Rtedit.SelectionStart
If e.KeyChar = Chr(13) Then
j = Me.Rtedit.GetLineFromCharIndex(i)
Me.Rtedit.Text = Me.Rtedit.Text.Insert(i - 1, "↓")
Me.Rtedit.SelectionStart = i + 1
e.Handled = True
End If

If e.KeyChar = CChar(" ") Or e.KeyChar = Chr(30) Then
Me.Rtedit.Text = Me.Rtedit.Text.Insert(i, "┸")
Me.Rtedit.SelectionStart = i + 1
e.Handled = True
End If

End Sub


Private Sub Rtedit_VScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles Rtedit.VScroll
'行番号確認
Rtedit_Linecheak()
End Sub


Private Sub Rtedit_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Rtedit.TextChanged
'行番号確認
Rtedit_Linecheak()
End Sub


'行番号確認
Private Sub Rtedit_Linecheak()
Dim i, j, k As Integer
'Rtedit コントロールの先頭テキストから行番号を取得します。
'指定した位置の一番近くにある文字のインデックスを取得します。
i = Rtedit.GetCharIndexFromPosition(TopPt)
j = Rtedit.GetLineFromCharIndex(i) 'コントロール内の先頭行の行番号
k = Rtedit.Lines.GetUpperBound(0) - j
'行番号表示枠分のみ再表示させる
If k > EditLines - 1 Then
k = EditLines - 1
End If
ReDim LineNo(k)
For i = j To j + k
LineNo(i - j) = i.ToString("*00000: ")
Next
RTNo.Lines = LineNo
End Sub


Private Sub Rtedit_VerticalScrolled(ByVal sender As Object, ByVal e As System.EventArgs) Handles Rtedit.VerticalScrolled
'行番号確認
Rtedit_Linecheak()

End Sub
End Class



'外部に公開されたRitchtextコントロールクラス
Public Class EXRichTextBox
'RichTextBoxコントロールを継承
Inherits System.Windows.Forms.RichTextBox

'外部に公開されたイベントを定義します(引数はプログラマの自由です)
Public Event VerticalScrolled(ByVal sender As Object, ByVal e As EventArgs)

'this::WndProc
Protected Overrides Sub WndProc(ByRef m As Message)
Const WM_VSCROLL As Integer = &H115

If m.Msg = WM_VSCROLL Then
RaiseEvent VerticalScrolled(Me, New EventArgs())
End If

MyBase.WndProc(m)
End Sub
End Class



#長くなって申し訳ありません
このプログラムは2つのリッチテキストを使用しています。
右側のリッチテキストがEdit用です。
右側でスクロール、編集できます。
改行、スペースは別文字で置き換えています。
改行、スペースをこの様な方法で置き換えるのは良くないのか?解りません
皆様はどのようにお考えでしょうか?
またEdit用のリッチテキストボックスにはスクロールバーのつまみによる移動時のイベントがありませんので以前 java.lang.Nullpoさん が Listviewのスクロール にサンプルとして書いてあったものを使用し、ユーザーコントールとしました。
また新しいファイルの入出力時には改行、スペースをReplace関数などで置換すれば特に問題ないような気がしますけれど?


なぜ今回こんなに長く書き込みしたかと言いますと冒頭でも記しました様にVB.Netの準備されている機能ではなぜだめかを、私はまだ知らないので、是非教えていただきたいためです。
どなたでも結構ですから宜しくお願いします。

深山様 失礼なことと思われましたらお詫びいたします。
常日頃VB.Netで出来ない事を考えていましたので、投稿しました。
> どなたでも結構ですから宜しくお願いします。
>
> 深山様 失礼なことと思われましたらお詫びいたします。
> 常日頃VB.Netで出来ない事を考えていましたので、投稿しました。

深山さんが投稿する前に書くのは失礼かと存じますが、ちょっと気になったので(^^;
#お先に失礼しますm(_ _)m

まず、改行やスペースが”目視”できるだけであって、
選択できてはいけないと思います。つまり、そのエディタで書いたコードを
どこかへコピペしたいときなどに困ってしまいます。
従って、マーカーは”Draw”しなければいけないのです。
また、この実装だとファイルからの入出力は勿論、外部からのペーストにも対応
すべく余分なコードを書くことになります。つまり、マークするという動作が
あちこちに分散してしまい、保守性に欠けます。

#これは、すぐ直ると思いますが、改行記号の右側でさらに改行すると、
#よからぬ事が起きるような気がします…。(^^;
■No6332に返信(平ちゃんさんの記事)

平ちゃんです
先ほどのコードですが誤りがありました。
Me.Rtedit = New Ritctext.EXRichTextBox()を
Me.Rtedit = New EXRichTextBox()
に修正してください。(ビルドエラー発生)
余談ですがMe.Rtedit = New Ritctext.EXRichTextBox()で開発しましたが
コピペするとMe.Rtedit = New EXRichTextBox()でないとビルドエラー発生します。Me.Rtedit = New Ritctext.EXRichTextBox()で動作するのがよくわかりません。
失礼しました。
■No6333に返信(antさんの記事)

antさんご指摘有難うございます。

>
> まず、改行やスペースが”目視”できるだけであって、
> 選択できてはいけないと思います。つまり、そのエディタで書いたコードを

仰るとおり”目視”にしないといけませんね。
ゆうこりんさんの質問にもそのように書いてありました。

> あちこちに分散してしまい、保守性に欠けます。

そうですね。

それでは次のようにサンプルプログラムを書き替えてみます。
1.改行、スペース表示文字をグラフィックス表示する。
  RichTextBoxのメッソドで対応できます。
   GetCharIndexFromPosition
   GetLineFromCharIndex
   GetPositionFromCharIndex
  RichTextBoxのPaintイベントを使う。
2.Paintイベントの再描画タイミング
   水平、垂直スクロールイベント時
   TextChanged イベント時
3.行番号再表示タイミングは上記2.と同じ
4.RichTextBox.Textは置換しない。
5.RichTextBox.Textの右端折り返し書式に対応したい。
問題点として
  Paintイベントの再描画タイミングを各イベントに分散して書く必要がある。
  エディタに書ける最大行数を固定する。従ってFont,FontSizeも固定。
  行番号表示部分はエディタと同じ行高さにするためにRichTextBoxを使っているのでフォーカスを受け取る。
動作イメージはRichTextBoxに表示されている文字のみを対象にしますから
改行、スペース、行番号の表示は少ないので軽いと思います。
とりあえずサンプルプログラムを作ってから連絡させて頂きます。
■No6332に返信(平ちゃんさんの記事)

 平ちゃんさん、antさん、こんにちは。深山です。

> 深山様 失礼なことと思われましたらお詫びいたします。
> 常日頃VB.Netで出来ない事を考えていましたので、投稿しました。

 いえいえ、失礼なんてことないですよ〜。寧ろご意見頂けて嬉しいくらいです(^^)
 でも‥‥ごめんなさい。平ちゃんさんがどの部分を気に掛けられてたのか、よく解りませんでした(汗)

> 3.私はVB.Netの限界がどれだけなのか良く解らないのですがVB.Netで出来る事はVB.Netでしたい。
> VB.Netの準備されている機能ではなぜだめか

 えっと、ひょっとして誤解を与えてしまっているのでしょうか。記載したコードは
.NET Freamwork 標準の機能しか使っていないと思うのですけど‥‥。
# 元質問者さまが VB.NET で開発されてるのに C# のコードを提示しているのは私のポカであって、
# VB.NET で同じことができないわけではありません。って、そういうことじゃないのかなぁ?(ーー;)
# あ、「描画を全て自分で管理すべき」って話のことでしょうか?

 取り敢えず
> 2.当初の(ゆうこりんさん)質問は単に改行、スペースを別の文字に置き換える方法を考えているだけではないのか?
についてはantさんがご返答下さってますし、既に平ちゃんさんも納得されてますよね。
# antさん、ありがとうございますm(__)m

> 1.深山様のコードでどのような動作をするのか?
については‥‥動かしてみて下さい、じゃダメですか?(^_^;)
 コメントにあるように、再描画をするタイミング( WM_PAINT 受信時)で改行位置を検索・取得し、
改行記号の描画をしています。
# やっぱりそういうことをお訊しきたいわけじゃないような気がする‥‥。


■No6334に返信(平ちゃんさんの記事)
> 余談ですがMe.Rtedit = New Ritctext.EXRichTextBox()で開発しましたが
> コピペするとMe.Rtedit = New EXRichTextBox()でないとビルドエラー発生します。Me.Rtedit = New Ritctext.EXRichTextBox()で動作するのがよくわかりません。

 開発したとき、プロジェクト名を Ritctext にされてたのではないでしょうか?
 もしそうでしたら、名前空間についてご確認下さいませ。
■No6347に返信(深山さんの記事)

>  えっと、ひょっとして誤解を与えてしまっているのでしょうか。記載したコードは
> .NET Freamwork 標準の機能しか使っていないと思うのですけど‥‥。
> # 元質問者さまが VB.NET で開発されてるのに C# のコードを提示しているのは私のポカであって、
>>1.深山様のコードでどのような動作をするのか?

そうですね。C# でないと出来ないと理解してました。

> については‥‥動かしてみて下さい、じゃダメですか?(^_^;)

C# は全然知りませんから動かすことが出来ませんでした。

> # やっぱりそういうことをお訊しきたいわけじゃないような気がする‥‥。
そういうことをお聞きしたいんですが、追記の部分が C# だと勘違いしてました。VB.Netでしたらヘルプなどで調べてみます。
>
No6316で深山様が次のように書かれていましてこの内容が理解できなかったのです。
--------------
■追記

 その後改良を加えて(と言っても知れてますが(^_^;))、次のようにしてみました。

 ・プライベート メンバに再描画用フラグA、日本語入力中フラグBを追加
 ・OnTextChanged 、 OnHScroll 、 OnVScroll 、 OnResize メソッドをオーバーライドし、
  フラグAを true にする処理を追加
 ・WM_IME_STARTCOMPOSITION メッセージ受信時にフラグBを true にする処理を追加
 ・WM_IME_ENDCOMPOSITION メッセージ受信時にフラグBを false にする処理を追加
 ・WM_PAINT メッセージ受信時、フラグAが true 且つ フラグBが false であれば
  フラグAを false にして描画処理を行うよう修正

 まだ数点問題は残っているものの、日本語入力もできるようになりましたし、前よりは
随分マシになったかと思います。とは言え‥‥やっぱり重いですね(ーー;)
 クライアント領域内以外は処理しないようにする等、検索&描画処理にも幾ばくか手を
入れてみたのですけど、焼け石に水でしたorz

# テキストエディタを造るのは大変だなぁと改めて感じた秋の夜更け‥‥<挫折経験のある人(汗)
------------

内容は理解できなかったのですが 「重い」 「挫折経験のある人」の言葉の意味はは理解できましてどのようなすごいプログラムを考えているのか解らなかった次第です。改行、スペース、日本語入力のできる簡単なエディタはできそうな気がしましたものですから。

>
> ■No6334に返信(平ちゃんさんの記事)
>>余談ですがMe.Rtedit = New Ritctext.EXRichTextBox()で開発しましたが
>>コピペするとMe.Rtedit = New EXRichTextBox()でないとビルドエラー発生します。Me.Rtedit = New Ritctext.EXRichTextBox()で動作するのがよくわかりません。
>
>  開発したとき、プロジェクト名を Ritctext にされてたのではないでしょうか?
>  もしそうでしたら、名前空間についてご確認下さいませ。

有難うございます。ご指摘の通りです。

#サンプルプログラムを作成中です。完成しましたら投稿させていただきます。
■No6350に返信(平ちゃんさんの記事)

 平ちゃんさん、こんにちは。深山です。

>># 元質問者さまが VB.NET で開発されてるのに C# のコードを提示しているのは私のポカであって、
> そうですね。C# でないと出来ないと理解してました。

 あぅ、そうだったのですね(^_^;;;) 申し訳ないですm(__)m


>>については‥‥動かしてみて下さい、じゃダメですか?(^_^;)
> C# は全然知りませんから動かすことが出来ませんでした。

 えっと、こういう言い方をすると気分を悪くされるかも知れませんけれども‥‥

 確かに C# と VB.NET では記述が異なります。場合によっては同じことが実現できないことも
あります。とは言え、同じライブラリを使用している言語、「知らないから動かせない」と
いうほどの隔たりがあることは少ないのではないでしょうか。
 こちらのサイトでは『 VB.NET、C#変換表』という Tips が紹介されてますし、そこには
MSDN の『各言語の比較』へのリンクも張られています。

http://dobon.net/vb/dotnet/vb2cs/vb2cstable.html
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/vsintro7/html/vxgrfLanguageEquivalents.asp
# ここから直接(ここで使ってるような) using ステートメントの説明にはいかないかも
# 知れません。が、だからといって調べられないわけではありませんし、ただの変数宣言として
# 動作を確認することもできるでしょう。

 もし動かす意欲があったのでしたら、動かせないということはないでしょう(少なくとも、
どこが上手くいかなかったとかいう表現になる筈です)。
 逆にそこまで至らなかったということは、その程度の興味しかなかったのではないかと。

‥‥なんて、問題があると解ってるコードの動作確認をする為にそこまでの労力はかけませんよね(^_^;)
 でも、「 VB.NET しか知らないから」といって C# のコードから目を背けるのは勿体無いと
思うのですよ。単純に考えても、世の中で参考にできるものが二倍になるのですから。
# 偉そうなこと(&一部無茶なこと)言ってすいませんm(__)m


> No6316で深山様が次のように書かれていましてこの内容が理解できなかったのです。

 「○○メッセージ受信時」とかいう部分でしょうか?
 このことでしたら、「 WndProc メソッド内で m.Msg の値を判断して」と置き換えることが
できます。
# 平ちゃんさんが WM_VSCROLL と比較されてたのと同じような感じで処理します。


> 内容は理解できなかったのですが 「重い」 「挫折経験のある人」の言葉の意味はは理解できましてどのようなすごいプログラムを考えているのか解らなかった次第です。改行、スペース、日本語入力のできる簡単なエディタはできそうな気がしましたものですから。

 フリーのテキスト エディタで見かけるような機能でも、いざ自分で実装しようとすると
色々大変だったというだけですので。気になさらないで下さいませ(汗)
2004/09/28(Tue) 10:04:15 編集(投稿者)

こんにちは、ゆうこりんです。
皆様のアツイ投稿、ありがとうございます!
実は、当方自前でサンプルを作成しました。
ソースそのままですが、ファイルを添付します。

現状、動きは遅いですが何とか動いています。
ただ問題がありまして、改行を表す"↓"より右にカーソルを
置きたくないので、RichTextKeyUp の処理内で調整しています。
動きは問題ないのですが、日本語入力中(変換確定前)に左ボタンなどを押すと
intTexLen = rtbGenko.TextLength
の部分で、変換が確定してしまいます。
これがクリアできれば、何とか形にできそうです。

よい回避方法をご存知の方、ご教授お願いします。
(この記事にはファイル"Editor.txt"が添付されていましたが、削除されました。)
■No6356に返信(ゆうこりんさんの記事)
> 2004/09/28(Tue) 10:04:15 編集(投稿者)
>
平ちゃんです。

> 変換が確定してしまいます。
> これがクリアできれば、何とか形にできそうです。
>
> よい回避方法をご存知の方、ご教授お願いします。
>

解決方法はわかりませんが 原因は矢印キーでリッチテキストボックスからフォーカスが他に移っています。フォーカスが移ると変換が確定されます。
どこか解りませんがフォーカスの移動するプログラムになっているとおもいます。
ご参考まで
■No6356に返信(ゆうこりんさんの記事)

 ゆうこりんさん、こんにちは。深山です。

> 動きは問題ないのですが、日本語入力中(変換確定前)に左ボタンなどを押すと
> intTexLen = rtbGenko.TextLength
> の部分で、変換が確定してしまいます。

 文字列の長さを取得するために、入力中のものを確定してしまうようですね。

> intTexLen = rtbGenko.TextLength
という処理を何箇所かでやってましたけど、これを RichTextChanged メソッド内でのみ
行うようにしたらどうでしょうか? intTexLen はプライベート メンバにしてしまって。
# こちらで軽く触った感じでは何となく大丈夫そうでした。



 で、以下余談になりますが、少し気になった点を。

・改行を連続で入力した後、日本語入力を行うと未確定の文字列色が青になってしまう
# 私の環境だけかなぁ(^_^;)

・”□”、”・”、”↓”の入力を行うと、文字色が青になってしまう
・”↓”を入力した直後に改行を入力すると、”↓”が削除されてしまう
# この二つは該当文字を入力しない仕様なら問題にはならないです。

・ No6333 でantさんも指摘されてましたが、コピーしたときに‥‥
# これも仕様で謳うなら気にしないで下さいね。
> ■No6356に返信(ゆうこりんさんの記事)
>
>よい回避方法をご存知の方、ご教授お願いします

平ちゃんです。解決しました?
まだでしたら

'*********************************************************************
'関数名:リッチテキスト描画停止処理
'*********************************************************************
Private Sub LockRichTextUpdate(ByVal rtbGenko As RichTextBox)

'画面描画停止
LockWindowUpdate(rtbGenko.Handle.ToInt64)

m_intSelStart = rtbGenko.SelectionStart
rtbGenko.Enabled = False

End Sub

の rtbGenko.Enabled = False でフォーカスが失われて確定してしまうのではないか?と思います。
一度検討してみてください。
違っていれば ”ごめん”
■No6376に返信(平ちゃんさんの記事)

ゆうこりんさん、深山さん、antさん 今日は
平ちゃんです。

目視サンプルを作ってみました。
フォームのサイズを変えるとエディタのサイズが変わります。
カット&コピー、ペーストも出来ます。
ソースを添付します。
コピペで動作しますので、不備な点のご指摘の程お願いします。

もっといい方法があるのでは?と疑問に思っているのは次の点です。
1.リッチテキストボックスは OnPaint イベント発生しない。?
  今回は RaiseEvent で作成しました。
2.TextCangeやスクロールイベント内で明示的に目視文字を表示させますと
  表示後にシステムがTextCangeやスクロールイベント処理をすることになり
  目視文字が消えてしまう。その為に50msタイマーでシステムの処理が終了した
  頃を見計らって目視文字を表示しています。その為パソコンのスピードにより不具合に
  なる可能性あり。(余裕を持たせて50msにしました)
3.フォントの種類により半角スペースの目視文字が見づらい。これはもともと半角スペースの
  間隔が少ないので仕方ないか?
4.目視文字表示はクライアント領域全部書き替えているのでチラツキがかなりある。
  作業している近辺のみ書き替えたらよいのか。検討中です。

まあ私としては良く出来ているほうでチラツキの件をじっくりと見直します。
(この記事にはファイル"Mokusi.txt"が添付されていましたが、削除されました。)
こんにちは、平ちゃんさん。

■No6396に返信(平ちゃんさんの記事)
> '外部に公開されたイベントを定義します(引数はプログラマの自由です)
「何か見覚えのあるコメントだ」なんて思っていたら、

■No6332に返信(平ちゃんさんの記事)
> リッチテキストボックスにはスクロールバーのつまみによる
> 移動時のイベントがありませんので以前
> java.lang.Nullpoさん が Listviewのスクロール に
> サンプルとして書いてあったものを使用し、ユーザーコントールとしました。

とありますね。何か微妙に嬉しいです。

まだ、実行していないですけど、このサンプルって選択状態にすると再描画されず消えてしまいませんか?
そんな気がするのですが...
こんにちは、平ちゃんさん。java.lang.Nullpoさん。

お返事遅くなりまして、申し訳ありません。

■No6356に返信(ゆうこりんさんの記事)
> 動きは問題ないのですが、日本語入力中(変換確定前)に左ボタンなどを押すと
> intTexLen = rtbGenko.TextLength
> の部分で、変換が確定してしまいます。

の件ですが、

■No6368に返信(深山さんの記事)
>  文字列の長さを取得するために、入力中のものを確定してしまうようですね。

そのとおりでした。

変換が確定しないように、現在変換中かどうかを、
e.KeyCode = Keys.ProcessKey
で判断することで解決しました。

平ちゃんさん。java.lang.Nullpoさん。
本当にありがとうございました。


■No6396に返信(平ちゃんさんの記事)
> 目視サンプルを作ってみました。

すばらしいですね。
java.lang.Nullpoさんがおっしゃるように、
選択状態にすると再描画されないのが気になりますが、
とても参考になりました。

今後の進展をお待ちしております。
> 目視サンプルを作ってみました。
> 1.リッチテキストボックスは OnPaint イベント発生しない。?
>   今回は RaiseEvent で作成しました。

おぉ、頑張っておられますね。(^^
1に関して少しだけ…。

通常OnPaintが呼び出されないコントロールは
SetStyleメソッドでUserPaintを設定しておけば呼び出される
はずです。
■No6402に返信(antさんの記事)

平ちゃんです。今日は
またまた難問にぶつかりました。お手数ですが教えて下さい。

>
> 通常OnPaintが呼び出されないコントロールは
> SetStyleメソッドでUserPaintを設定しておけば呼び出される
> はずです。

この実装ができればダブルバッファリングを使いチラツキの解消が出来るべく実装にかかりましたがうまく実装できません。
良い方法を教えて下さい。

新規にリッチテキストボックスを継承した RichTextBox1 だけの フォームをつくり OnPaint だけの実装テストをしました。

<問題点>
1.RichTextBox1 の既定のテキスト"RichTextBox1" が表示できない。しかしフォーカスは入ります。
継承クラス EXRichTextBox のコンストラクタをコメントアウトすると表示できる。
TextBox,ListBox などで確認しても同様でした。
2.Form1で EXRichTextBox の OnPaint 動作をさせるため、このように OnPaint イベントで RaiseEvent Painted(Me, e) させましたが
皆様もこのようにやっておられますよねぇ?

このテストプログラムを添付しますので宜しくお願いします。

#ゆうこりんさんの板を乗っ取ってしまいました。あと少し貸してください。
(この記事にはファイル"Test5.txt"が添付されていましたが、削除されました。)
> <問題点>
> 1.RichTextBox1 の既定のテキスト"RichTextBox1" が表示できない。しかしフォーカスは入ります。
> 継承クラス EXRichTextBox のコンストラクタをコメントアウトすると表示できる。
> TextBox,ListBox などで確認しても同様でした。

内部構造を少し書いておくと、
UserPaintが設定されている場合、WndProc内でWM_PAINTを受け取った
コントロールはWmPaintという内部メソッドを呼び出します。
その中で、実質的には、Win32APIのBeginPaintが呼び出されます。
そして、EndPaintが呼び出されるまでにOnPaintが呼び出されます。
(正確にはもう一つメソッドを経由する)
もうお分かりだと思いますが、UserPaintを設定した場合描画処理を
OSは一切手伝ってくれません。自分で描画するということです。

もし、BeginPaintを呼び出すことなく、描画したい場合は
深山さんが行ったようにWM_PAINTをインターセプトすることになります


> 2.Form1で EXRichTextBox の OnPaint 動作をさせるため、このように OnPaint イベントで RaiseEvent Painted(Me, e) させましたが
> 皆様もこのようにやっておられますよねぇ?

いえ、通常継承したクラスからそのようなことはしません。
普通はOnPaintをオーバーライドしたのですから、そこに
描画処理を記述します。又、マークアップはテキストボックスの
処理すべきことなのですから、その処理は継承したテキストボックス内に
収めるべきで、Formの継承クラスにその処理を書くなどということもしないほうが
いいと思います。(再利用の観点から…)
■No6461に返信(antさんの記事)

ant さん
有難うございます。予想していたとはいえ、やはり難解です。
>
> 内部構造を少し書いておくと、
> UserPaintが設定されている場合、WndProc内でWM_PAINTを受け取った
> コントロールはWmPaintという内部メソッドを呼び出します。
> その中で、実質的には、Win32APIのBeginPaintが呼び出されます。
> そして、EndPaintが呼び出されるまでにOnPaintが呼び出されます。
> (正確にはもう一つメソッドを経由する)
> もうお分かりだと思いますが、UserPaintを設定した場合描画処理を
> OSは一切手伝ってくれません。自分で描画するということです。
>
う〜ん。通常の描画(FormのPaint)も自分で座標、ペン、ブラシ、等を決めてOSが手伝ってるイメージは無かったのですが、さらに自分のすることが増えるという事でしょうか?あ、それは描画のタイミングを自分ですると言うことでしょうか?

> もし、BeginPaintを呼び出すことなく、描画したい場合は
> 深山さんが行ったようにWM_PAINTをインターセプトすることになります
>
私がOSにして欲しかったのはUserPaintでRichTextBoxのクライアント領域に重ねて透明なキャンバスで描画して欲しかったのですが、無理な感じですね。

>
> いえ、通常継承したクラスからそのようなことはしません。
> 普通はOnPaintをオーバーライドしたのですから、そこに
> 描画処理を記述します。又、マークアップはテキストボックスの
> 処理すべきことなのですから、その処理は継承したテキストボックス内に
> 収めるべきで、Formの継承クラスにその処理を書くなどということもしないほうが
> いいと思います。(再利用の観点から…)

これも私の OnPaint が良く解らないためです。
OnPaint を Paintの強力版?と考えてRichTextBoxを継承しOnPaint実装したクラスのインスタンスは、全てPaint機能をもったRichTextBoxになり、さらに各々に異なったSetStyleの設定ができるのですごい。..と考えてました。


#OnPaint , Paint の違い。 PictureBoxにPaintがあるのにTextBoxにないのは何故か?など等 調べて見ます。
有難うございました。
■No6462に返信(平ちゃんさんの記事)

antさん 皆様おせわになります。
結果を連絡したいのですが、ファイルを添付できませんので板をかえます。
続きの板をご覧下さい。

ゆうこりんさん 解決済みで板を閉めます。
有難うございました。
解決済み!

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