CEditView 雑記 |
Last Updated: Apr.4,2003 |
使用しているコンパイラは、Microsoft Visual C++ 6.0 です。これ以外のバージョンでは記述と食い違うことがあるかも知れません。 |
Windows 付属のワードパットのように、テキストをドラッグ&ドロップで編集できると非常に使いやすいエディタになります。これは、OLE という機能を利用して実装するのですが、OLE についての具体的な説明は私も詳しくは知らないので、ここでは割愛させて頂きます。手順としては、
といった感じです。
■ OLE の初期化とドロップターゲットへの登録
まず、OLE を利用するためには、アプリケーションでの初期化が必要です。CWinApp::InitInstance で一度だけ行います。
BOOL CMyApp::InitInstance() { if (!AfxOleInit()) /* OLE の初期化 */ return FALSE; ・・・
次に、CMyView に COleDropTarget 型のメンバ m_dropTarget を持たせ、OnCreate で COleDropTarget::Register を呼び出します。
int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CEditView::OnCreate(lpCreateStruct) == -1) return -1; /* ドロップターゲットへの登録 */ if (!m_dropTarget.Register(this)) return -1; return 0; }
■ OnLButtonDown での処理
OnLButtonDown が処理の入り口(であり出口)です。ドロップ位置を示す文字インデックスが分からないとドロップ後の処理ができないので、m_nDropChar メンバを追加しています。後で OnDrop でこの変数に値を設定することになります。
void CMyView::OnLButtonDown(UINT nFlags, CPoint point) { if (PtInSel(point)) { /* point が選択文字列内にあるとき */ int ss, se; CEdit& edit = GetEditCtrl(); edit.GetSel(ss, se); CString sSel; GetSelText(sSel); /* 選択文字列取得 */ /* OLE に文字列を保持 */ HGLOBAL hData = GlobalAlloc(GHND | GMEM_SHARE, (sSel.GetLength()+1)*sizeof(TCHAR)); lstrcpy((LPTSTR)GlobalLock(hData), (LPCTSTR)sSel); GlobalUnlock(hData); COleDataSource dataSource; dataSource.CacheGlobalData(CF_TEXT, hData); /* ドロップ&ドロップ操作を実行 */ DROPEFFECT result = dataSource.DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE); if (result == DROPEFFECT_MOVE) { /* 選択文字列を消す */ edit.Clear(); } if (result == DROPEFFECT_COPY || result == DROPEFFECT_MOVE) { if (m_nDropChar < ss) { /* ドロップ位置がドラッグより前 */ ss = m_nDropChar; edit.SetSel(ss, ss, TRUE); edit.ReplaceSel(sSel); edit.SetSel(ss, ss+sSel.GetLength()); } else if (m_nDropChar > se) { /* ドロップ位置がドラッグより後 */ if (result == DROPEFFECT_COPY) ss = m_nDropChar; else if (result == DROPEFFECT_MOVE) ss = m_nDropChar - sSel.GetLength(); edit.SetSel(ss, ss, TRUE); edit.ReplaceSel(sSel); edit.SetSel(ss, ss+sSel.GetLength()); } } return; } CEditView::OnLButtonDown(nFlags, point); }
■ OnDragEnter と OnDragOver
この2つはまったく同じ処理でもいけそうです。OnDragEnter のみ示します。
DROPEFFECT CMyView::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) { if (pDataObject->IsDataAvailable(CF_TEXT)) { CRect r; GetEditCtrl().GetClientRect(&r); if (!r.PtInRect(point)) return DROPEFFECT_NONE; /* カレット位置を更新・表示 */ int nChar = CharFromPos(point); CPoint pt = PosFromChar(nChar); if (!PtInSel(pt)) SetCaretPos(pt); return (dwKeyState & MK_CONTROL) ? DROPEFFECT_COPY : DROPEFFECT_MOVE; } return CEditView::OnDragEnter(pDataObject, dwKeyState, point); }
主な仕事はカレット位置を更新して、表示することです。この処理がないと「福笑い」になってしまいます。
■ OnDrop での処理
OnDrop では、m_nDropChar にドロップ位置を設定して、結果を返すだけです。
BOOL CMyView::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) { if (pDataObject->IsDataAvailable(CF_TEXT)) { /* カレット位置を更新・表示 */ m_nDropChar = CharFromPos(point); CPoint pt = PosFromChar(m_nDropChar); if (PtInSel(pt, TRUE)) return FALSE; SetCaretPos(pt); return TRUE; } return CEditView::OnDrop(pDataObject, dropEffect, point); }
案外簡単ですね。
■ その他の処理
骨組みはこれで大体 OK なのですが、残念ながら実用にならない点があります。ここでは示しませんが、
などの処理が必要です。項目2では、OnDragScroll 内で CEdit::LineScroll を使うとうまくできますので試してみてください。
←前ページ | 次ページ→ |
Back | Copyright (c) 2003 AOK. All Rights Reserved. |