Главная
Новости, анонсы ...


 Опыты
Статьи, исходники
и прочее






Чернопятов Е.А. Inplace-редактирование (редактирование "по-месту") в элементе управления CTreeCtrl


В этой короткой статье речь пойдет об "in-place" редактировании, т.е. редактирование текста элемента дерева без использования специального диалога. Так редактируются, например, именa файлов в Проводнике.

Смысл редактирования "на-месте" в том, что Windows создает некий временный контрол типа EDIT, в котором производится изменение текста элемента. Затем введенный текст может быть передан в элемент. Порядок работы следующий:

  1. перехватить сообщение о начале редактирования
  2. выполнить необходимые проверки (например, если нельзя редактировать корень) и разрешить или не разрешить собственно редактирование
  3. Windows сделает всю работу по созданию элемента редактирования
  4. пользователь введет новый текст
  5. перехватить сообщение об окончании ввода
  6. разрешить или запретить внесение изменений в текст элемента

Пример приводится для использования CTreeView. Если вы используете CTreeCtrl непосредственно, то часть функций будет выглядеть проще.

I. Прежде всего, дерево должно иметь стиль TVS_EDITLABELS. Его можно установить с помощью Resource Editora (если используется CTreeCtrl), при создании вида функцией Create или вот так:

void CTreeViewInPlaceEditView::OnInitialUpdate()
 {
	CTreeView::OnInitialUpdate();
 	//.................................
   	LONG TreeStyle = GetWindowLong(GetTreeCtrl().m_hWnd,   // handle of window
          			   GWL_STYLE);		// offset of value to retrieve
	TreeStyle|=TVS_EDITLABELS;
	SetWindowLong(GetTreeCtrl().m_hWnd,GWL_STYLE,TreeStyle);
 }

II. Далее с помощью ClassWizard-a (или вручную) нам необходимо перегрузить функции, отвечающие на нотификационные сообщения от CTreeCtrl-a, посылаемые CTreeView. Это сообщения TVN_BEGINLABELEDIT и TVN_ENDLABELEDIT. Коротко скажу, что эти сообщения посылаются перед началом и перед окончанием редактирования. Программист может модифицировать результат, возвращаемый ими, тем самым влияя на поведение CTreeCtrl -a.

В хэдер (.h) добавляем:

// Generated message map functions
protected:
//{{AFX_MSG(CLeftView)
// ................................
  afx_msg void OnTvnBeginlabeledit(NMHDR *pNMHDR, LRESULT *pResult);
  afx_msg void OnTvnEndlabeledit(NMHDR *pNMHDR, LRESULT *pResult);
// ................................
//}}AFX_MSG
DECLARE_MESSAGE_MAP()

В .cpp добавляем:

BEGIN_MESSAGE_MAP(CLeftView, CTreeView)
//{{AFX_MSG_MAP(CLeftView)
//................................
  ON_NOTIFY_REFLECT(TVN_BEGINLABELEDIT, OnTvnBeginlabeledit)
  ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnTvnEndlabeledit)
//................................
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

III. Теперь собственно реализация функций

-------------------------------------------------------------------


/* Эта функция вызывается системой непосредственно перед 
передачей управления элементу редакирования.
Программист имеет возможность запретить или разрешить  
редактирование путем модификации возвращаемого  значения pResult. 
0 - разрешить редактирование, не 0 - запретить
В данном примере запрещается редактировать название корневого элемента. */ 
void CTreeViewInPlaceEditView::OnTvnBeginlabeledit(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);

	CString sRootName;
	// предопределенное имя корневого элемента
	sRootName = _T("The root name");	

	// в этом примере мы явно запрещаеи редактировать корневой элемент
	if (sRootName.CompareNoCase(pTVDispInfo->item.pszText)==0)
	{
		*pResult = 1;
		return;
	}	

	*pResult = 0;
}
 
/* Эта функция вызывается системой непосредcтвенно перед  
потерей фокуса ввода элементом редакирования (CEdit).
Программист имеет возможность запретить или разрешить  
сохранение изменений, сделанных при редактировании  
путем модификации возвращаемого значения pResult. 
0 - отвергнуть изменения, не 0 - принять изменения. */
void CTreeViewInPlaceEditView::OnTvnEndlabeledit(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
	
	//был ли ввод нового текста?
	if(pTVDispInfo->item.pszText == NULL) // не было, пользователь отменил его
	{
		*pResult = 0;
		return;
	}	

	// пусть у нас для примера нельзя, чтобы новое имя элемента было "The item"
	CString sForbiddenName;
	sForbiddenName = _T("The item");	
	// если пользователь ввел запрещенное имя для элемента - отвергнуть его
	if(sForbiddenName.CompareNoCase(pTVDispInfo->item.pszText)==0)
	{
		*pResult = 0;
		return;
	}	
	// иначе принять изменения
	*pResult = 1;
}



Исходники

Здесь вы можете загрузить иллюстрирующий проект (VC++ 7.0)

Пример для CTreeCtrl, архив ZIP,~23 Кб
Пример для CTreeView, архив ZIP,~28 Кб




Оглавление


Последние изменения от 09.08.2013




e-mail:  Yegor A. Blackheel

Поиск по сайту с помощью Yandex

 www.guestbook.ru - лучший сервер гостевых книг