CCtrlView 雑記 |
Last Updated: Feb.14,2007 |
使用しているコンパイラは、Microsoft Visual C++ 6.0 です。これ以外のバージョンでは記述と食い違うことがあるかも知れません。 |
CCtrlView から派生させて CListBoxView を作ってみました。ポイントになるのは、コンストラクタと OnChildNotify あたりでしょうか。編集機能とシリアライズ機能も付けてみましたが、MFC の CListView の方が便利なのでほとんど用途はないかもしれません。ソースを丸ごと載せておきます。ヘッダーファイルはこちら。
// ListBoxView.cpp : インプリメンテーション ファイル // // Copyright (c) 2007 AOK. All Rights Reserved. // #include "stdafx.h" #include "ListBoxView.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CLBEdit - 編集用のエディットコントロール CLBEdit::CLBEdit() : m_nCurIndex(-1) { } CLBEdit::~CLBEdit() { } BEGIN_MESSAGE_MAP(CLBEdit, CEdit) //{{AFX_MSG_MAP(CLBEdit) ON_CONTROL_REFLECT(EN_CHANGE, OnChange) ON_CONTROL_REFLECT(EN_KILLFOCUS, OnKillFocus) ON_WM_KEYDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CLBEdit メッセージ ハンドラ CListBoxView* CLBEdit::GetView() const { CWnd* pWnd = GetParent(); ASSERT_VALID(pWnd); ASSERT_KINDOF(CListBoxView, pWnd); return (CListBoxView*)pWnd; } void CLBEdit::BeginEdit(int nItem, LPCTSTR pszText) { ASSERT(nItem != LB_ERR); m_nCurIndex = nItem; m_sPreText = pszText; SetFont(GetView()->GetFont()); SetWindowText(pszText); } void CLBEdit::EndEdit() { if (m_nCurIndex == -1) return; CString sText; GetWindowText(sText); CListBoxView* pView = GetView(); if (sText.IsEmpty()) { pView->GetListBox().DeleteString(m_nCurIndex); pView->AdjustListBox(); } else if (m_sPreText.Compare(sText) != 0) { pView->GetListBox().InsertString(m_nCurIndex, sText); pView->GetListBox().DeleteString(m_nCurIndex+1); pView->AdjustListBox(); } m_nCurIndex = -1; } void CLBEdit::OnChange() { CString sText; GetWindowText(sText); CListBoxView* pView = GetView(); if (m_sPreText.Compare(sText) != 0) pView->GetDocument()->SetModifiedFlag(TRUE); } void CLBEdit::OnKillFocus() { EndEdit(); ShowWindow(SW_HIDE); } void CLBEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (nChar == VK_RETURN) { int nSave = m_nCurIndex; ShowWindow(SW_HIDE); if (nSave != -1) GetView()->GetListBox().SetCurSel(nSave); } CEdit::OnKeyDown(nChar, nRepCnt, nFlags); } ///////////////////////////////////////////////////////////////////////////// // CListBoxView IMPLEMENT_DYNCREATE(CListBoxView, CCtrlView) CListBoxView::CListBoxView() : CCtrlView(_T("LISTBOX"), AFX_WS_DEFAULT_VIEW | WS_VSCROLL | WS_HSCROLL | WS_CLIPCHILDREN | LBS_NOINTEGRALHEIGHT | LBS_NOTIFY) { } CListBoxView::~CListBoxView() { } BEGIN_MESSAGE_MAP(CListBoxView, CCtrlView) //{{AFX_MSG_MAP(CListBoxView) ON_WM_CREATE() ON_WM_SIZE() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CListBoxView メッセージ ハンドラ int CListBoxView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CCtrlView::OnCreate(lpCreateStruct) == -1) return -1; //SendMessage(WM_SETFONT, (WPARAM)::GetStockObject(DEFAULT_GUI_FONT), 0); m_edit.Create(WS_CHILD|WS_BORDER|ES_AUTOHSCROLL, CRect(0,0,0,0), this, GetDlgCtrlID()+1); return 0; } CListBox& CListBoxView::GetListBox() const { return *(CListBox*)this; } void CListBoxView::AdjustListBox() { ASSERT((GetStyle() & LBS_MULTICOLUMN) == 0); CListBox& lb = GetListBox(); CString str; CSize size; int dx = 0; CDC* pDC = lb.GetDC(); CFont *pOldFont = pDC->SelectObject(GetFont()); int c = lb.GetCount(); for (int i = 0; i < c; i++) { lb.GetText(i, str); size = pDC->GetTextExtent(str + _T(' ')); if (size.cx > dx) dx = size.cx; } lb.SetHorizontalExtent(dx); pDC->SelectObject(pOldFont); lb.ReleaseDC(pDC); } void CListBoxView::SerializeRaw(CArchive& ar) { CListBox& lb = GetListBox(); CString sText; if (ar.IsStoring()) { int nCount = lb.GetCount(); for (int i = 0; i < nCount; i++) { lb.GetText(i, sText); if (!sText.IsEmpty()) ar.WriteString(sText + _T("\r\n")); } } else { lb.ResetContent(); while (ar.ReadString(sText)) lb.AddString(sText); AdjustListBox(); } } void CListBoxView::OnSize(UINT nType, int cx, int cy) { CCtrlView::OnSize(nType, cx, cy); if (m_edit.GetSafeHwnd()) { CRect rect; m_edit.GetWindowRect(&rect); m_edit.SetWindowPos(NULL, 0, 0, cx, rect.Height(), SWP_NOMOVE|SWP_NOZORDER); } } BOOL CListBoxView::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult) { if (message == WM_COMMAND) { switch (HIWORD(wParam)) { case LBN_ERRSPACE: break; case LBN_SELCHANGE: OnSelChange(GetListBox().GetCurSel()); return TRUE; case LBN_DBLCLK: OnDblClk(GetListBox().GetCurSel()); return TRUE; case LBN_SELCANCEL: break; case LBN_SETFOCUS: break; case LBN_KILLFOCUS: break; default: break; } } return CCtrlView::OnChildNotify(message, wParam, lParam, pLResult); } void CListBoxView::OnSelChange(int nItem) { if (nItem == LB_ERR) return; CString s; GetListBox().GetText(nItem, s); CWnd* pWnd = AfxGetMainWnd(); ASSERT_VALID(pWnd); ASSERT_KINDOF(CFrameWnd, pWnd); ((CFrameWnd*)pWnd)->SetMessageText(s); } void CListBoxView::OnDblClk(int nItem) { if (nItem == LB_ERR) return; CRect rect; GetListBox().GetItemRect(nItem, &rect); int cy = ::GetSystemMetrics(SM_CYBORDER); /* 全く同じサイズにすると編集状態かどうか分かりにくいため */ rect.InflateRect(0, cy+1, 0, cy+1); CString sText; GetListBox().GetText(nItem, sText); m_edit.BeginEdit(nItem, sText); m_edit.MoveWindow(&rect, FALSE); m_edit.ShowWindow(SW_SHOWNORMAL); m_edit.SetFocus(); }
新規行挿入と行削除は実装していませんが、
で、OK です。
Back | Copyright (c) 2007 AOK. All Rights Reserved. |