- PR -

TextBoxの表示が単語単位に自動改行される挙動を変更したい

1
投稿者投稿内容
Ariel
会議室デビュー日: 2007/04/02
投稿数: 5
投稿日時: 2007-04-02 13:16
いつも拝見させて頂いておりますが投稿は初めてです。
よろしくお願い致します。

C#のTextBoxコントロールを

Multiline = true;
WordWrap = true;

として使用しているのですが、
表示上の改行が「単語単位」で折り返されてしまいます。
(標準の挙動だと思います)

これを単語の途中であってもかまわないので、
「表示エリアの右端」で改行されるようにしたいのですが、
実現方法がわかりません。

一応「WordBreak」「WordWrap」「改行」等のワードで過去ログを拝見させて頂いて、
実際のテキスト自体に改行を追加すれば実現できそうではありますが、
(表示エリアの横幅からテキスト長を算出して、改行コードをインサートする等して、
その際には泣き別れのような別の問題も発生しますが)
できれば改行を追加しない方法で実現したいと考えております。

目論見としてはTextBoxを継承したクラスで
改行を制御(正確には表示上次の行へLFする制御?)しているような
メソッドをOverrideするのかな?と考えているのですが、、

判り難い文章で申し訳ございませんが、
どうぞよろしくお願い致します。
よねKEN
ぬし
会議室デビュー日: 2003/08/23
投稿数: 472
投稿日時: 2007-04-02 15:17
引用:

C#のTextBoxコントロールを

Multiline = true;
WordWrap = true;

として使用しているのですが、
表示上の改行が「単語単位」で折り返されてしまいます。
(標準の挙動だと思います)



WordWrap=trueはそういう指示ですけど・・・

引用:

これを単語の途中であってもかまわないので、
「表示エリアの右端」で改行されるようにしたいのですが、
実現方法がわかりません。



WordWrap=falseではうまくいきませんか?
#動作確認していないので判断がつかないのですが、
#実は質問の書き間違いで、WordWrap=falseにしているけどうまくいかない
#という質問だったりするのかもしれない・・・
Ariel
会議室デビュー日: 2007/04/02
投稿数: 5
投稿日時: 2007-04-02 15:29
おっしゃるようにWordWrapはそういう意味なのは理解しているのですが、
これをFalseにすると表示エリアをはみ出しても改行されなくなってしまいます。
(エリア外に突き抜ける感じです。スクロールバーを有効にしておくと自動的に付与される状態です)

表示エリア内で自動的に改行されて欲しいけど、
単語単位で改行されたくない。

という動作を実現したいのですが・・
私何かとても基本的な事を見落としているのでしょうか?
よねKEN
ぬし
会議室デビュー日: 2003/08/23
投稿数: 472
投稿日時: 2007-04-02 15:55
引用:

Arielさんの書き込み (2007-04-02 15:29) より:
おっしゃるようにWordWrapはそういう意味なのは理解しているのですが、
これをFalseにすると表示エリアをはみ出しても改行されなくなってしまいます。
(エリア外に突き抜ける感じです。スクロールバーを有効にしておくと自動的に付与される状態です)

表示エリア内で自動的に改行されて欲しいけど、
単語単位で改行されたくない。

という動作を実現したいのですが・・



>#実は質問の書き間違いで

申し訳ありません。私の読み間違い&WordWrap=Falseの動作勘違いでしたね。。。
#動作検証せずにレスするとこういうことに・・・orz

APIのSendMessage関数とEM_SETWORDBREAKPROCメッセージを使用して
独自のワードラップを実装すればいけそうな気がしますが、
今回もまた未検証です。
よねKEN
ぬし
会議室デビュー日: 2003/08/23
投稿数: 472
投稿日時: 2007-04-02 17:21
引用:

APIのSendMessage関数とEM_SETWORDBREAKPROCメッセージを使用して
独自のワードラップを実装すればいけそうな気がしますが、
今回もまた未検証です。



コード:
' vbc /out:WordWrapTest.exe WordWrapTest.vb /r:System.dll,System.Windows.Forms.dll,System.Drawing.dll /t:winexe
Imports System
Imports System.Drawing
Imports System.Windows.Forms

Public Class MainForm
	Inherits Form

	Private Const EM_SETWORDBREAKPROC As Int32 = &HD0
	Private Const EM_GETWORDBREAKPROC As Int32 = &HD1

	Private Delegate Function EditWordBreakProc( _
		ByVal lpch As IntPtr, _
		ByVal ichCurrent As Int32, _
		ByVal cch As Int32, _
		ByVal code As Int32 _
		) As Int32


	Private Declare Function SendMessageSet Lib "user32" Alias "SendMessageW" _
		( _
		ByVal hWndControl As IntPtr, _
		ByVal msgId As Int32, _
		ByVal wParam As IntPtr, _
		ByVal lParam As EditWordBreakProc _
		) As IntPtr

	Private Declare Function SendMessageGet Lib "user32" Alias "SendMessageW" _
		( _
		ByVal hWndControl As IntPtr, _
		ByVal msgId As Int32, _
		ByVal wParam As IntPtr, _
		ByVal lParam As IntPtr _
		) As EditWordBreakProc

	Private WithEvents TextBox1 As TextBox
	Private m_PrevProc As EditWordBreakProc
	Private m_CurrentProc As EditWordBreakProc
	

	Private Sub SetProc()
		m_CurrentProc = AddressOf MyEditWordBreakProc
		m_PrevProc = SendMessageGet(TextBox1.Handle, EM_GETWORDBREAKPROC, IntPtr.Zero, IntPtr.Zero)
		SendMessageSet (TextBox1.Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, m_CurrentProc)
	End Sub

	Private Sub UnsetProc()
		SendMessageSet(TextBox1.Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, m_PrevProc)
	End Sub

	Public Function MyEditWordBreakProc( _
			ByVal lpch As IntPtr, _
			ByVal ichCurrent As Int32, _
			ByVal cch As Int32, _
			ByVal code As Int32 _
			) As Int32

		Return ichCurrent
	End Function


	Public Sub New()
		TextBox1 = New TextBox()
		TextBox1.MultiLine = True
		TextBox1.WordWrap = True
		TextBox1.Size = New Size(100,100)
		Me.Controls.Add(TextBox1)
		SetProc()
	End Sub

	Protected Overrides Sub Finalize()
		UnsetProc()
		MyBase.Finalize()
	End Sub

	Public Shared Sub Main()
		Application.Run(New MainForm())
	End Sub
End Class



VBですがテストプログラムを作ってみました。
一応それなりに動作しているようですが、十分な検証はしていません。
正式な情報源はたぶん英語しかありませんが、これらのドキュメントを
熟読せず作ってますし、怪しい部分もありますので、
参考にされる場合は、十分な調査と検証を行ってください。

EM_SETWORDBREAKPROC
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/editcontrols/editcontrolreference/editcontrolmessages/em_setwordbreakproc.asp

EditWordBreakProc コールバック
http://msdn2.microsoft.com/en-us/library/ms672125.aspx
Ariel
会議室デビュー日: 2007/04/02
投稿数: 5
投稿日時: 2007-04-02 17:33
よねKEN様

わざわざコードまで書いて頂いて恐縮です。
ありがとうございます。

私にVBの知識が乏しい為判らない部分もありますが、
頂いたコードと参考リンクを元にC#での実装を行ってみようと思います。

まずは頂いたコードが何をしているのか調べる所から始めますので、
時間がかかるかもしれませんが、進展がございましたらまた報告させて頂きます。
Ariel
会議室デビュー日: 2007/04/02
投稿数: 5
投稿日時: 2007-05-07 16:26
最後の書き込みから一月以上経過してからのレスで恐縮ですが
(別の作業をしており手がつけられませんでした)
下記のようなコードで対応することができました。

---------------------------------------------------------------------------

TextBoxを継承したクラスで、

// 定数とデリゲートの定義
private const int EM_SETWORDBREAKPROC = 0x00D0;
private delegate int EditWordBreakProc( IntPtr lpch, int ichCurrent, int cch, int code );

[DllImport("user32.dll")]
extern static IntPtr SendMessageW( IntPtr hWndControl, int msgId, IntPtr wParam, EditWordBreakProc lParam );

// 改行制御処理(常に制御しない)
private int MyEditWordBreakProc( IntPtr lpch, int ichCurrent, int cch, int code )
{
return ichCurrent;
}

// 改行制御処理セット
private void setNoWordWrap()
{
SendMessageW( this.Handle, EM_SETWORDBREAKPROC, IntPtr.Zero, new EditWordBreakProc( MyEditWordBreakProc ) );
}


// プロパティの上書き
public override bool Multiline
{
set
{
base.Multiline = value;
setNoWordWrap();
}
}

---------------------------------------------------------------------------

現状期待したように動作しております。

よねKEN様

本当にありがとうございました。
ぶさいくろう
ぬし
会議室デビュー日: 2005/11/22
投稿数: 1232
お住まい・勤務地: 川崎市(は俺も含めてロクな人間が住んでないよw)
投稿日時: 2007-05-07 16:59
引用:

Arielさんの書き込み (2007-05-07 16:26) より:
// プロパティの上書き
public override bool Multiline
{
set
{
base.Multiline = value;
setNoWordWrap();
}
}


上書き?
なんかオーバーライトと勘違いしている人最近多いな・・・
1

スキルアップ/キャリアアップ(JOB@IT)