none
CEditのMultiLineで改行コードを追加しないで1行の文字数を制限する方法はありますか

    質問

  • MFC CEditのMultiLineを使って複数行の文字入力を行っています。

    やりたい事は1行の最大文字数を全角10文字、半角20文字などと決めて、それ以上入力されたら次の行に表示させる事ですが、
    改行コードを追加しないで実現したいです。

    CEditなどを使って、コントロールの機能では1行15文字表示できるのに、改行コードを使わずに、10文字で改行表示させる事はできますでしょうか?

    2017年4月12日 14:49

回答

  • なるほど、仕様の理由はわかりました。

    1.出力イメージ通りの編集を行いたい
    2.フォントはユーザーが選べるようになっている(・・後半削除)。

    という解釈でよろしいでしょうか。
    フォントを変更すると、当然当該の編集コントロールのサイズも変化するわけで、
    そのコントロールの親ウインドウも、子コントロールサイズ変更に合わせた処理が必要になりますね(イラレ等の機能)。
    大きなフォントにした場合、当比率で縮小するか、スクロールする必要もありそうです。
    結構面倒かもしれません。
    残念ながら、固有のコントロールを作成する、以外の提案はできそうにありません。
    あしからず。

    2017年4月13日 9:49

すべての返信

  • 簡単な実装方法はありません。提示の仕様は比較的困難な課題で、非常に高コストになります。
    CEditを使う場合でも、新たに相当機能を持つ文字列編集用コントロールを作成する場合でも多分大差ないでしょう。
    もし可能であれば、この様な仕様が必要になった理由を教えていただけますでしょうか。
    理由によっては他の解決策があるかもしれません。
    2017年4月13日 1:33
  • 簡単な実装方法はありません。提示の仕様は比較的困難な課題で、非常に高コストになります。
    CEditを使う場合でも、新たに相当機能を持つ文字列編集用コントロールを作成する場合でも多分大差ないでしょう。
    もし可能であれば、この様な仕様が必要になった理由を教えていただけますでしょうか。
    理由によっては他の解決策があるかもしれません。

    ご回答ありがとうございます。  やはりCEdit関係のコントロールを利用する方法は難しいですかね。

    要求仕様は
      ある文字数で改行表示したい
      単語でWordRapしたい、
      改行を入力した場合は、そのまま改行表示する
    という内容になります。

    現在は1行の最大文字数より長い文字を入力したとき改行コード追加して折り返しを表現してますが、
    これだと、その後、文字を追加/削除した場合、自分で改行を入力したのかプログラムで改行を付けたのか
    、WordRapで改行されたのか判らないので、 折り返しのつながり上手く行かなくなる事が分かりました。

    Wordやメモ帳が上手く処理しているようですの、できたらこれと同じような処理を行いたいを思っています。
    (が1ヶ月とかかかる場合は、現状仕様でクライアントに飲んでもらう事もあります)

    2017年4月13日 5:16
  • Word と同じ挙動にするのは大変だと思いますが、メモ帳と同じ挙動にするのはそれほど難しくないのかなと思います。(同じ Edit コントロールで実装されているようですので)

    複数行 Edit コントロールでウィンドウの右端で折り返すには、WS_HSCROLL や ES_AUTOHSCROLL のスタイルをつけなければ実現できると思います。

    • 編集済み kenjinote 2017年4月13日 5:43
    2017年4月13日 5:43
  • Word と同じ挙動にするのは大変だと思いますが、メモ帳と同じ挙動にするのはそれほど難しくないのかなと思います。(同じ Edit コントロールで実装されているようですので)

    複数行 Edit コントロールでウィンドウの右端で折り返すには、WS_HSCROLL や ES_AUTOHSCROLL のスタイルをつけなければ実現できると思います。

    ご回答ありがとうございます。

    現状では横スクロール関係は付けていません。   

    折り返すのは、ウィンドウの右端ではなくて、任意の文字数(全角が10文字とすると半角は20文字)で折り返す必要があります。

    (CEditは20文字表示できる幅があるのに、10文字で折り返すという意味です)

    良いアイディアがありましたら上げてください。 

    よろしくお願いします。

    2017年4月13日 5:51
  • 自分が求めたのは、その仕様が必要になった理由だったのですが、いずれにしても
    やはり「新たに相当機能を持つ文字列編集用コントロールを作成する」のが一番の近道かと思います。

    ところで、この仕様には
     (1)1行内文字数の制限を超えた文字数をもつ単語が入力できない。
     (2)入力確定前等に自動的ワードラップされた時に、多分に違和感のある挙動となる。
    といった問題があると考えられます。

    (1)は自明で、特に地名、病名や科学用語等は30文字程度は軽く超えてしまいます。調べておいたほうが良いかもしれません。
    (2)は文字を挿入してからDelキーで削除して修正する、といった操作の時に自動的に改行や改行解除されるため、かなりうっとおしい動作となります。ワードラップをリアルタイムに判定する場合では、入力中のキャレットが行を移動することになるでしょう。
    一般的な文字入力時の動作を期待したユーザーのクレームに対して、対策を考えておかなければならないかもしれません。

    2017年4月13日 6:27
  • 折り返すのは、ウィンドウの右端ではなくて、任意の文字数(全角が10文字とすると半角は20文字)で折り返す必要があります。

    この部分はメモ帳とは異なる挙動でしょうか?ウィンドウの右端ではなく、特定の幅で折り返すには、Edit コントロールのクライアント領域を設定してみると実現できるかもしれません。(ただし、Edit コントロールには等幅フォントを設定する必要があります。)

    下記のコードは参考になりますでしょうか?

    BEGIN_MESSAGE_MAP(CMyEdit, CEdit)
    	ON_WM_NCHITTEST()
    	ON_WM_NCCALCSIZE()
    END_MESSAGE_MAP()
    
    LRESULT CMyEdit::OnNcHitTest(CPoint point)
    {
    	return HTCLIENT;
    }
    
    void CMyEdit::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
    {
    	HFONT hFont = (HFONT)SendMessage(WM_GETFONT);
    	CDC* pDC = GetDC();
    	HFONT hOldFont = (HFONT)pDC->SelectObject(hFont);
    	RECT rectText = { 0 };
    	pDC->DrawText(TEXT("01234567890123456789_"), -1, &rectText, DT_CALCRECT);
    	pDC->SelectObject(hOldFont);
    	ReleaseDC(pDC);
    	lpncsp->rgrc[0].right = lpncsp->rgrc[0].left + rectText.right;
    	CEdit::OnNcCalcSize(bCalcValidRects, lpncsp);
    }
    
    

    Edit コントールにフォントを設定した後は、

    m_pEdit->SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED);

    Edit コントールにフレーム幅の変更を通知する必要があるようです。

    追伸:

    Edit コントロールの左右の余白を調整する方法ですが、上記よりもっと簡単に実現できそうな関数がありました。

    CEdit::SetMargins(UINT nLeft, UINT nRight)

    上記の関数でEdit コントロールの左側と右側の余白を調整できます。Edit コントロールの幅を取得し、半角20文字分の文字列の幅が収まるように、右左の余白を調整することで実現可能でしょうか?

    • 編集済み kenjinote 2017年4月13日 7:42
    2017年4月13日 6:37
  • 折り返すのは、ウィンドウの右端ではなくて、任意の文字数(全角が10文字とすると半角は20文字)で折り返す必要があります。

    この部分はメモ帳とは異なる挙動でしょうか?ウィンドウの右端ではなく、特定の幅で折り返すには、Edit コントロールのクライアント領域を設定してみると実現できるかもしれません。(ただし、Edit コントロールには等幅フォントを設定する必要があります。)

    下記のコードは参考になりますでしょうか?

    BEGIN_MESSAGE_MAP(CMyEdit, CEdit)
    	ON_WM_NCHITTEST()
    	ON_WM_NCCALCSIZE()
    END_MESSAGE_MAP()
    
    LRESULT CMyEdit::OnNcHitTest(CPoint point)
    {
    	return HTCLIENT;
    }
    
    void CMyEdit::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
    {
    	HFONT hFont = (HFONT)SendMessage(WM_GETFONT);
    	CDC* pDC = GetDC();
    	HFONT hOldFont = (HFONT)pDC->SelectObject(hFont);
    	RECT rectText = { 0 };
    	pDC->DrawText(TEXT("01234567890123456789_"), -1, &rectText, DT_CALCRECT);
    	pDC->SelectObject(hOldFont);
    	ReleaseDC(pDC);
    	lpncsp->rgrc[0].right = lpncsp->rgrc[0].left + rectText.right;
    	CEdit::OnNcCalcSize(bCalcValidRects, lpncsp);
    }

    Edit コントールにフォントを設定した後は、

    m_pEdit->SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED);

    Edit コントールにフレーム幅の変更を通知する必要があるようです。

    追伸:

    Edit コントロールの左右の余白を調整する方法ですが、上記よりもっと簡単に実現できそうな関数がありました。

    CEdit::SetMargins(UINT nLeft, UINT nRight)

    上記の関数でEdit コントロールの左側と右側の余白を調整できます。Edit コントロールの幅を取得し、半角20文字分の文字列の幅が収まるように、右左の余白を調整することで実現可能でしょうか?

    丁寧なご回答ありがとうございます。

    文字数によって改行表示する必要があるのと

    全角と半角が入って、行毎に表示できる幅が異ってますので、 CEditの領域設定では無理だと考えています。

    あと、フォントはユーザーが選べるようになっているので等幅フォント限定は出来ないです。


    2017年4月13日 8:23
  • 全角と半角が入って、行毎に表示できる幅が異ってます

    すみません。いまいち仕様を理解できていませんでしたが、行毎に折り返し位置が異なるということですね。これは メモ帳 でも実現できていない動作のような気がしますがいかがでしょうか?(全角10文字、半角20文字と書かれていましたので等幅だと勘違いしていました。)

    CEdit には各行別々の折り返し位置を設定することはできませんので、仲澤@失業者さんのおっしゃるように文字編集の独自コントロールを作成するか、CEdit の派生クラスでメッセージ ハンドラをオーバーライドして挙動を変えていくしかないように思います。いずれにしても簡単に実現できないと思います。

    • 編集済み kenjinote 2017年4月13日 9:23
    2017年4月13日 9:13
  • 自分が求めたのは、その仕様が必要になった理由だったのですが、いずれにしても
    やはり「新たに相当機能を持つ文字列編集用コントロールを作成する」のが一番の近道かと思います。

    ところで、この仕様には
     (1)1行内文字数の制限を超えた文字数をもつ単語が入力できない。
     (2)入力確定前等に自動的ワードラップされた時に、多分に違和感のある挙動となる。
    といった問題があると考えられます。

    (1)は自明で、特に地名、病名や科学用語等は30文字程度は軽く超えてしまいます。調べておいたほうが良いかもしれません。
    (2)は文字を挿入してからDelキーで削除して修正する、といった操作の時に自動的に改行や改行解除されるため、かなりうっとおしい動作となります。ワードラップをリアルタイムに判定する場合では、入力中のキャレットが行を移動することになるでしょう。
    一般的な文字入力時の動作を期待したユーザーのクレームに対して、対策を考えておかなければならないかもしれません。

    ご回答ありがとうございます。

    この仕様になったのは最終的に出力する文書のフォーマットが 1行~文字までと決まっている為、
    それに合わせて文字入力も~文字で改行させたいという流れです。

    (1)は折り返しで表示させます。

    2017年4月13日 9:16
  • なるほど、仕様の理由はわかりました。

    1.出力イメージ通りの編集を行いたい
    2.フォントはユーザーが選べるようになっている(・・後半削除)。

    という解釈でよろしいでしょうか。
    フォントを変更すると、当然当該の編集コントロールのサイズも変化するわけで、
    そのコントロールの親ウインドウも、子コントロールサイズ変更に合わせた処理が必要になりますね(イラレ等の機能)。
    大きなフォントにした場合、当比率で縮小するか、スクロールする必要もありそうです。
    結構面倒かもしれません。
    残念ながら、固有のコントロールを作成する、以外の提案はできそうにありません。
    あしからず。

    2017年4月13日 9:49
  • みなさんありがとうございました。

    簡単には実現できないという事で理解しました。

    2017年4月13日 10:33