C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[8]: RichTextBoxのスクロール同期の方法


(過去ログ 20 を表示中)

[トピック内 10 記事 (1 - 10 表示)]  << 0 >>

■8105 / inTopicNo.1)  RichTextBoxのスクロール同期の方法
  
□投稿者/ tk (1回)-(2007/09/23(Sun) 20:06:05)

分類:[.NET 全般] 

はじめまして。

表題の通り、RichTextBoxの方法がどうしてもわからないので
どなたかご教授ください。

方法としては
1. 片方のRichTextBoxがスクロールイベントを受け取ったら
2.その移動量もしくは場所を取得して
3.もう一方のコントロールにSendMessageでスクロールイベントを発生させる

だと思っているのですが、イベントの受け取り方、
というよりもイベント名がわかりません。
あとSendMessageの方法です。

探し方が悪いのかなかなかwebでも見つからなくて

ちなみにキャレットのところにスクロールする方法は今回避けたいと思っています。
引用返信 編集キー/
■8108 / inTopicNo.2)  Re[1]: RichTextBoxのスクロール同期の方法
□投稿者/ れい (139回)-(2007/09/24(Mon) 05:34:28)
No8105 (tk さん) に返信
> 方法としては
> 1. 片方のRichTextBoxがスクロールイベントを受け取ったら
> 2.その移動量もしくは場所を取得して
> 3.もう一方のコントロールにSendMessageでスクロールイベントを発生させる

こちらの質問
http://bbs.wankuma.com/index.cgi?mode=al2&namber=8097
と同じなのですが、
その手順で基本はあっています。
スクロールバーをクリックしたり、ドラッグしたりした際には同期できます。
ですが、RichEdit内でカーソルの移動を行ったり、HOMEやENDを押したときの移動に関しては
スクロールバーのメッセージが来ないので同期できません。

> だと思っているのですが、イベントの受け取り方、
> というよりもイベント名がわかりません。
> あとSendMessageの方法です。

WM_VSCROLLかEM_SCROLLのどちらか、好きなほうを使えばよいのですが、
WM_VSCROLLでないとバーのドラッグがうまくいかなかったと思います。
SendMessageは特に特殊なことはありません。
片方に来たメッセージをほぼそのまま流せばいいだけです。

WM_VSCROLLを使うなら、
WPARAMがSB_THUMBTRACKの場合にSB_THUMBPOSITIONに変更したほうが
THUMBが美しく動くと思います。

最初に書いたように、RichEdit内でカーソルの移動を行った場合などは同期できませんので、
全ての変更、カーソル移動のたびにいちいち位置を調べなければなりません。
これは非常に煩雑で、他のロジックを入れるときにも障害になります。
ですので、スクロールバーの同期を取るのはお勧めしません。

いい方法を知ってる方がいたら私も教えて欲しいと思っています。
引用返信 編集キー/
■8110 / inTopicNo.3)  Re[2]: RichTextBoxのスクロール同期の方法
□投稿者/ @echo (6回)-(2007/09/24(Mon) 08:09:43)
> WM_VSCROLLかEM_SCROLLのどちらか、好きなほうを使えばよいのですが、

EM_SCROLL は位置指定ではなく行/頁単位の相対指定なので、
WM_VSCROLL が妥当だと思います。

ただし、WM_VSCROLL は 16 bit 指定なので、行数が多くなると
位置に誤差が生じます。(高さ/65536)
(最終行も怪しい)

SetScrollPos/SetScrollInfo API が使用できればいいのですが、
この API ではスクロールバーの位置が変わるだけでテキストは
スクロールしないようです。

> 最初に書いたように、RichEdit内でカーソルの移動を行った場合などは同期できませんので、
> 全ての変更、カーソル移動のたびにいちいち位置を調べなければなりません。

ドラッグ完了時やカーソル移動であれば、VScroll イベントで
処理すれば、同期可能と思います。
(スクロールバーを表示していないと発生しませんが...)

引用返信 編集キー/
■8112 / inTopicNo.4)  Re[3]: RichTextBoxのスクロール同期の方法
□投稿者/ tk (2回)-(2007/09/24(Mon) 13:35:14)
れいさん、@echoさん
ご回答有難うございます。なるほどよくわかりました。

方法としては合っているけど、スクロールバーをつかんで移動する以外の
イベントはつかめないということですね。

今回の実装はどんなときも二つのRichTextBoxのスクロールバーを同期させたいので、
WM_VSCROLLイベントをつかむ方法ではなくて、RichTextBoxの標準イベント関数の
VScrollを使って(全てのスクロールイベントをつかみます)、同期させた方がいいのかもしれません。

実はこれを一回考えたのですが、この関数

private void richTextBox1_VScroll(object sender, EventArgs e) {}

から移動量などが見つからないんです。だからWndProcで、(移動量が取得できるらしい)WM_VSCROLLから
やろうとした経緯がありました。

でも、そうなるとこのイベント関数何のためにあるんだろうって気もしますが。。。
きっとあるんだと思います。ご存知ですか?
引用返信 編集キー/
■8117 / inTopicNo.5)  Re[4]: RichTextBoxのスクロール同期の方法
□投稿者/ @echo (7回)-(2007/09/24(Mon) 17:49:30)
No8112 (tk さん) に返信
> private void richTextBox1_VScroll(object sender, EventArgs e) {}
> 
> から移動量などが見つからないんです。だからWndProcで、(移動量が取得できるらしい)WM_VSCROLLから
> やろうとした経緯がありました。

スクロール位置の取得・設定は、API で行うことになると思います。
※以下はドラッグ中のスクロールには対応していません。

[DllImport("user32")]
public static extern int GetScrollPos(IntPtr hWnd, int nBar);

[DllImport("user32", EntryPoint="SendMessageA")]
public static extern int SendMessage(
    IntPtr hWnd, int wMsg, int wParam, IntPtr lParam);

private void richTextBox1_VScroll(object sender, EventArgs e)
{
    const int
        SB_THUMBPOSITION = 4,
        SB_VERT = 1,
        WM_VSCROLL = 0x0115;
    int pos = GetScrollPos(((Control)sender).Handle, SB_VERT);
    SendMessage(richTextBox2.Handle,
        WM_VSCROLL, (pos << 16) | SB_THUMBPOSITION,
        IntPtr.Zero);
}

引用返信 編集キー/
■8127 / inTopicNo.6)  Re[5]: RichTextBoxのスクロール同期の方法
□投稿者/ tk (4回)-(2007/09/25(Tue) 00:26:10)
@echoさん

本当にありがとうございました!@echoさんの書いたソースだけで
ほぼ自分の希望する仕様になりました。目からウロコを初めて体験しました。
ドラッグ中のみWndProcから拾ってやってみようと思います。(競合しないかな?)

すみません、もう一点RichTextBoxなんですが、ご存知であれば教えていただきたい事があります。
RichTextBoxの仕様だからなのか、ホイールの動きに対してスクロールがかなり遅いような気がします。
よくフリーのテキストエディタなんかはホイールとスクロールはほぼ同期して動いているように見えますが、
あのような速さは仕様で仕方ないことなのでしょうか?


引用返信 編集キー/
■8130 / inTopicNo.7)  Re[6]: RichTextBoxのスクロール同期の方法
□投稿者/ 渋木宏明(ひどり) (379回)-(2007/09/25(Tue) 01:34:16)
渋木宏明(ひどり) さんの Web サイト
> RichTextBoxの仕様だからなのか、ホイールの動きに対してスクロールがかなり遅いような気がします。
> よくフリーのテキストエディタなんかはホイールとスクロールはほぼ同期して動いているように見えますが、
> あのような速さは仕様で仕方ないことなのでしょうか?

んー、どうでしょう?

その辺は

・システム設定
・マウスユーティリティ系アプリの設定
・リッチテキストコントロールの仕様(実装)
・RichTextBox クラスの仕様(実装)

が絡み合うところなので「遅い」だけではなんとも。です。

TexBox, RichTextBox で同じフォントを使って同じテキストを表示させた時、どれだけ差がありますか?
同じことをメモ帳でやった場合の差はどれだけでしょう?

また、他のPCでも似たような結果になりますか?

引用返信 編集キー/
■8132 / inTopicNo.8)  Re[6]: RichTextBoxのスクロール同期の方法
□投稿者/ @echo (8回)-(2007/09/25(Tue) 08:22:56)
No8127 (tk さん) に返信
> RichTextBoxの仕様だからなのか、ホイールの動きに対してスクロールがかなり遅いような気がします。
> よくフリーのテキストエディタなんかはホイールとスクロールはほぼ同期して動いているように見えますが、
> あのような速さは仕様で仕方ないことなのでしょうか?

一言で言えば "仕様" です。

ざっくり言うと、TextBox はいわゆるテキストエディタで
RichTextBox は MS Word のようなワープロエディタです。

RichTextBox は文字修飾や画像貼付けなど何でもできる分
処理が重くなり、動作も遅くなります。

なので、色付けなどをする必要がないのであれば
TextBox を使用すべきです。

ちなみに、フリーのテキストエディタの多くは、
TextBox や RichTextBox を使用せず、描画処理などを
すべて自前でプログラムしています。

特に Delphi 製アプリの多くは、TEditor という
優れもののシェアウェアのコンポーネントを
使用しているものが多いですね。

引用返信 編集キー/
■8259 / inTopicNo.9)  Re[7]: RichTextBoxのスクロール同期の方法
□投稿者/ tk (5回)-(2007/09/26(Wed) 23:30:22)
返信送れてすみません。色々試してみました。

渋木宏明さん>
他のPCでもやはり遅く、どうやら@echoさんの仰るところのようです。

@echoさん>
すごーくよく理解できました!ありがとうございました!
今回の要件からするとこの遅さでも全然ありなので
このままRichTextBoxを使います。

やっぱりフリーのエディタは自前描画だったんですね!
早すぎですよね。

今回は本当に目ウロコでした!
ありがとうございました!

解決済み
引用返信 編集キー/
■8667 / inTopicNo.10)  Re[8]: RichTextBoxのスクロール同期の方法
□投稿者/ tk (12回)-(2007/10/05(Fri) 15:18:38)
質問ではなく報告です。

前回こちらでVSCROLLイベントでスクロール同期する方法を教わりましたが、つまみドラッグには無効ということで
色々調べてたらつまみをドラッグしての同期もわかりましたので、書き込ませて頂きます。

まず、RichTextBoxを継承したクラスを作って、それのWndProcをオーバーライドします。
そうすれば、全てのスクロールイベント受け取ることができるので、
ここからそのスクロールの位置をSendMessage投げるように出来そうですが、
微妙にホイールのイベント発生の仕方がおかしいので、ここではつまみドラッグだけを
使うようにしました。

protected override void WndProc(ref Message m) {
	const int WM_VSCROLL = 0x115;
	
	const int SB_THUMBPOSITION = 0x4;
	const int SB_THUMBTRACK = 0x5;
	
	switch (m.Msg) {
		case WM_VSCROLL:
			int scrl = ((int)m.WParam) & 0x0000FFFF;
			int pos = (int)m.WParam;
			
			switch (scrl) {
				case SB_THUMBTRACK:  //つまみ中イベント
                                              //このイベントの時はこっちからSendMessage
				     SendMessage(richTextBox2.Handle,
                           WM_VSCROLL, pos | SB_THUMBPOSITION,
                           IntPtr.Zero);

				case SB_THUMBPOSITION:
					//これはつまみをはなした時なので、VSCROLLからSendMessageするようにします
					break;
			}					
			break;
		default:
			break;

	}
	base.WndProc(ref m);
}

お役にたてればと。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -