| ■ 概略説明 |
| 大分以前から、やりたかった事ですがなかなか実行できませんでした。 今回のサンプルはCEditViewに対してですが、この実現はCEditのクラスメンバを見ていてひらめきました。 それは、SetMargins関数です。今まで見過ごしてきましたが、これはその名の通り、左右のマージンを設定するものです。試しに使ってみると、当然ですが左側に空白ができました。このとき、「ここに行番号を表示できるのでは」そう考えて、後は幾つかの問題はありましたが、一応クリアできました。以下のような感じです。 ![]() |
| ■ プログラムの説明(作成手順の概略) |
| 1. CEditViewの子供として、行番号表示用のウィンドウを作成します。(CLineWnd) 2. 編集する関数は、OnPaintだけです。ポイントは m_nStart = pParent->GetEditCtrl().GetFirstVisibleLine(); m_nLineCount = pParent->GetEditCtrl().GetLineCount(); この2行で、親(CEditView)から現在表示されている先頭の行番号と全体の行数を持ってきて、後は表示できるだけ行番号を表示しているだけです。 3. 次にCEditViewの編集ですが、まずメンバに上記のCLineWndのポインタメンバm_pWndを作成します。 4. OnCreate内で、子ウィンドウを作成します。 m_pWnd = new CLineWnd; m_pWnd->Create( NULL, "", WS_CHILD | WS_VISIBLE, rc, this, 0); このときに、CClientDCを使いdcを取り出し、現在のフォントと改行ピッチを取り出し、それをCLineWndに伝えておきます。 5. OnSizeを追加し、サイズの変更に伴いCLineWndのサイズを変更します。 子供が絶えずくっついた状態にします。 6. これだけで、行番号が表示されます。子ウィンドウなので自動的にCLineWndにペイント命令を発行します。 後は、エディタの変更時にCLineWndを更新するだけですが、ここからが厄介でした。 7. まずスクロールですが、スクロールバーに対するもの(WM_VSCROLL)と、エディターのスクロールに対するもの(EN_VSCROLL)の両方を追加します。 void CLEditorView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) void CLEditorView::OnVscroll() 処理は、どちらも同じで、CLineWndのRedrawWindow()呼ぶだけです。 ただし、OnVScrollは、 CEditView::OnVScroll(nSBCode, nPos, pScrollBar); の後に処理を入れます。 8. そしてエディターの修正にあわせるため、EN_CHANGEの関数OnChangeを追加し、前項と同じ処理を追加します。 ただしこのままだと、一字修正するたびに行番号を書き直してしまうので、行番号が変化したときだけ行番号を書き直すようにします。 9. 最後に今回のキーポイントとして、PreCreateWindowでのCEditViewのウィンドウスタイルを変更します。 cs.style |= WS_CLIPCHILDREN; cs.style |= (ES_MULTILINE|WS_VSCROLL); // マルチライン. cs.style |= ES_NOHIDESEL; cs.style |= WS_HSCROLL; WS_CLIPCHILDRENですが、「親ウィンドウの内部で描画するときに、子ウィンドウが占める領域を除外します」というなんともありがたいフラグで、これにより行番号付エディターができました。因みにこの行を削除するとどうなるかがわかります。 |
| ■ 更新情報 |
| こんやすさんから、コメントを追加した修正ファイルを頂きました。ありがとうございます。 また、以前は問題なかったのですが、Xp上でファイルを開いた直後行番号が更新されなくなったので、CLEditorViewにInitialUpdate()を追加しそこで行番号ウィンドウを更新する処理を追加しました。 |
| ■ファイルのダウンロード |