お世話になっております。
XP,2007です。
RichEditで、行の終わり付近で、スペースを入れて英単語を入力すると、単語の終わりがその行におさまらない長さの場合、スペースの位置で改行され、自動的に次の行に単語が表示されてしまいます。
これを、行の最後まで単語が表示され、単語の途中でも改行されるようにするには、どうしたらよいでしょうか。
よろしくお願いします。
検証する環境がないのでリンク先だけ
https://www.petitmonte.com/bbs/answers?question_id=2641
さらに、WB_ISDELIMITERなんかも見ると
いい感じに改行できるかもしれません。VC++ですが
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200301/03010004.txt
ありがとうございます。
教えていただいた
https://www.petitmonte.com/bbs/answers?question_id=2641
は、自分でも見ていたんですが、Cのコードらしく、Delphiでどうしたらよいか分かりませんでした。
int CALLBACK MyEditWordBreakProc(LPTSTR lpch,int ichCurrent, int cch, int code){
return 0;
}
↓
function MyEditWordBreakProc(lpch:string,ichCurrent:integer,cch:integer,code:integer):integer;
begin
result:=0;
end;
RichEdit1->Perform( EM_SETWORDBREAKPROC,0,(LPARAM)MyEditWordBreakProc);
↓
RichEdit1.Perform( EM_SETWORDBREAKPROC,0,(LPARAM)MyEditWordBreakProc);
みたいな感じで試してみましたが、エラーが出ます。
Cは分からないので、これ以上分かりません。
引き続き、よろしくお願いします。
WordBreakProcの置き換えは、真面目にやろうとするとCR+LFの組み合わせを判別したり、
Ctrl+Left, Ctrl+Right のアルゴリズムも自分で実装しないといけないので
違和感なく動かすためにはけっこうチューニングが大変そうですね。
EM_SET/GETWORDBREAKPROCEXならデフォルトの処理関数が利用できるかと思ったけれど
やっぱり自分で登録しないとnilのままだったり。
とりあえず試してみたコード。uses節にRichEditとMathが必要です。
uses RichEdit, Math;
function MyWordBreakProc(lpch: PChar; ichCurrent, cch, code: Integer): Integer; stdcall;
begin
case code of
WB_CLASSIFY: // 現在位置の文字種別を判定する
// 実際には呼ばれてないようなので、これで内容が正しいかどうかは不明
if lpch[ichCurrent] = ' ' then
Result := WBF_ISWHITE
else
Result := WBF_BREAKAFTER or WBF_BREAKLINE;
WB_ISDELIMITER: // 現在位置の文字が区切り文字か判定する
Result := 0;
WB_LEFT, WB_LEFTBREAK: // 単語の先頭/前の単語の終わりを左に探す
Result := ichCurrent; // すべての文字が単語の先頭
WB_MOVEWORDLEFT: // Ctrl+Leftで左に動く時に呼ばれる
Result := Max(ichCurrent - 1, 0); // とりあえず1文字だけ戻す
WB_RIGHT, WB_RIGHTBREAK: // 次の単語の先頭/単語の終わりを右に探す
Result := Min(ichCurrent + 1, cch - 1); // 次の単語は常に1文字右
WB_MOVEWORDRIGHT: // Ctrl+Rightで右に動くときに呼ばれる
Result := Min(ichCurrent + 1, cch - 1); // とりあえず1文字だけ進める
else // ここには来ないはず
Result := 0;
end;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
RichEdit1.Perform(EM_SETWORDBREAKPROC, 0, LPARAM(@MyWordBreakProc));
end;
ありがとうございます。
試してみましたが、
(@MyWordBreakProc)のところで、
「変数が必要です」というエラーが出ます。
(lpch: PChar; ichCurrent, cch, code: Integer)
に何か値を入れないといけないんでしょうか?
EM_SETWORDBREAKPROC や LPARAM を調べてみましたが、よく分かりませんでした。
すみませんが、引き続き、お願いします。
> (@MyWordBreakProc)のところで、
> 「変数が必要です」というエラーが出ます。
MyWordBreakProcをフォームのメソッドとして定義していませんか?
メソッドにすると関数の型が合わないのでそのエラーが出ます。
提示した例のとおり、ただの関数として定義してください。
× function TForm1.MyWordBreakProc(...)
○ function MyWordBreakProc(...)
呼び出し規約(stdcall)を付けるのも忘れずに。
参考までに、LPARAM(@MyWordBreakProc) という式の意味について
・Cのキャストは 「(型名)式」ですが、Delphiでは「型名(式)」になります。
・@を付ける理由についてはヘルプの「文と式での手続き型」を参照。
これがないと関数呼び出しとみなされて「実パラメータが足りません」のエラーになります。
お返事遅れてすみません。
教えていただいたとおり、
× function TForm1.MyWordBreakProc(...)
○ function MyWordBreakProc(...)
が原因でエラーが出ていたようです。
ただ、ボックスの右端でスペースキーを押すと、1回目は、次の行にカーソルが出ますが、もう一度スペースキーを押すと、カーソルが消えてしまいます。
なんとなく、元の行の右の奥の方にカーソルが行っているような感じがします。
そのままもう一度スペースキーを押すと、次の行にカーソルが出ます。スペースは、この行に3個あります。
しかし、もう一度スペースキーを押すと、カーソルが消えてしまいます。
このように、スペースキーを押すたびに、カーソルが出たり消えたりを繰り返します。
何か必要な処理がされていないのでしょうか。
よろしくお願いします。
そのあたりの細かい挙動は、MyWordBreakProcの中身を気に入るまで調整するしかありません。だからチューニングが大変だと書いたわけで……
私の書いたサンプルは、「すべての文字が単語の区切りとなる」という単純なルールで実装したもので
文字列の中身はちゃんと見ていないし、空白文字などの特例もいっさい考慮していません。
一応、codeの意味やそれぞれどんな時に呼ばれるかはMSDNで説明してあるので
それに従って文字列を解析し、きちんと一貫したルールで値を返してやればちゃんと動作するはずです。理論的には。
実際には、どのcodeに対してどういう値を返すのが正解かはっきりしないので
自力で完璧を目指すのはかなり無理があると思います。
せめてお手本になるコードでもあればいいのですが、なかなか見つかりませんね。
>torさん
近いのだと、これかなぁ
http://support.microsoft.com/kb/273139/ja
私には変換できる程のスキルはないので参考で。
>かんとくさん
torさんが書いているように、イベントが発生するのであれば
ルールを決めるのは仕様次第だと思います。
いろいろとご指導ありがとうございます。
かなり難しいです。
「どこが、どう分かりません」という質問もできないくらい分からないので、もう無理かな、と思います。
RichEditにかわる何かを探そうかな、と思います。
ありがとうございました。
ツイート | ![]() |