По мотивам письма
----- Original Message -----
From: Yegor A. Blackheel
To:
Sent: Friday, May 05, 2000 1:22 AM
Subject: MFCByStep
> Хочу рассказать, как делается "in-place" редактирование, т.е. редактирование названия
> элемента без использования диалога. Так редактируются, например, именa файлов в Проводнике.
> Смысл редактирования "на-месте" в том, что Windows создает некий временный
> CEdit контрол, в котором производится изменение текста элемента.
> Проблема в том, что сама система автоматически НЕ обновляет текст элемента
> дерева, хотя на экране пользователь его изменяет. Таким образом, порядок работы д.б.
> следующий:
> 1. перехватить сообщение о начале редактирования
> 2. выполнить необходимые проверки (например, если нельзя редактировать корень)
> и разрешить или не разрешить собственно редактирование
> 3. Windows сделает всю работу по созданию элемента редактирования
> 4. Пользователь введет новый текст
> 5. перехватить сообщение об окончании ввода
> 6. самое главное - изменить элемент дерева вручную
> Пример приводится для использования CTreeView (sorry, выдирал из
> собственного проекта)
> I. Прежде всего, дерево должно иметь стиль TVS_EDITLABELS. Его можно
> установить с помощью Resource Editora (если используется CTreeCtrl), при создании вида
> функцией Create, или вот так:
> void CLeftView::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. Далее с помощью ClassWizarda (или вручную) нам необходимо перегрузить
> функции,
> отвечающие на нотификационные сообщения от CTreeCtrl`a, посылаемые CTreeView
> Это сообщения TVN_BEGINLABELEDIT и TVN_ENDLABELEDIT
> Коротко скажу, что эти сообщения посылаются сразу перед началом и перед
> окончанием редактирования
> Программист может модифицировать результат, возвращаемый ими, тем самым
> влияя на поведение программы
> file://это кусок хэдера
> // Generated message map functions
> protected:
> file://{{AFX_MSG(CLeftView)
> ................................
> afx_msg void OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult);
> afx_msg void OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult);
> ................................
> file://}}AFX_MSG
> DECLARE_MESSAGE_MAP()
> ---------------------------------------------------
> file://это кусок срр файла
>
> BEGIN_MESSAGE_MAP(CLeftView, CTreeView)
> file://{{AFX_MSG_MAP(CLeftView)
> ................................
> ON_NOTIFY_REFLECT(TVN_BEGINLABELEDIT, OnBeginlabeledit)
> ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndlabeledit)
> ................................
> file://}}AFX_MSG_MAP
> END_MESSAGE_MAP()
>
> --------------------------------------------
> III. Теперь собственно реализация функций
>
> -------------------------------------------------------------------
> /*эта функция вызывается системой непосредственно перед
> передачей управления элементу редакирования (CEdit).
> программист имеет возможность запретить или разрешить
> редактирование путем модификации возвращаемого
> значения pResult. 0 - разрешить редактирование, не 0- запретить
> В данном примере запрещается редакитировать название корневого элемента
> */
> void CLeftView::OnBeginlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
> {
> TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
>
> CString name;
> name.LoadString(IDS_TREE_ROOT); /*загрузить строку с названием корня*/
> /*если название редактируемого элемента совпадает с корнем -
> запретить редактирование*/
> if (name==pTVDispInfo->item.pszText)
> {
> *pResult = 1;
> return;
> }
> else
> *pResult = 0;
> }
>
>
> /*эта функция вызывается системой непосредвтенно перед
> потерей фокуса ввода элементом редакирования (CEdit).
> программист имеет возможность запретить или разрешить
> сохранение изменений, сделанный при редактировании
> путем модификации возвращаемого
> значения pResult. 0 - принять изменения, не 0- отвергнуть изменения
> */
>
>
> void CLeftView::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
> {
> TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
> TVITEM newitem;
> newitem=pTVDispInfo->item;
> CTreeCtrl &tree = GetTreeCtrl();
> /* похоже, пользователь отменил ввод....*/
> if (newitem.pszText==0)
> {
> *pResult = 0;
> return;
> }
> *pResult = 0;
> /* вот тут и происходит самое интересное. на первый взгляд, абсолютно
> бессмысленные действия. На самом деле происходит следующее. наша функция получает
> указатель на элемент, который является копий редактируемого, но содержащий новый текст.
> А программист уже решает, заменить ли старый элемент на новый, или нет.*/
> newitem.mask=TVIF_TEXT; /*говорим, что меняем только текст*/
> tree.SetItem(&newitem); /* новый элемент */
> }
> С уважением, Yegor A. Blackheel (blackheel@mail.ru)
Уважаемые, Егор совершенно прав. Для того, чтобы можно было редактировать по месту прямо в дереве без дополнительных окон, во-первых, надо присвоить дереву стиль в функции Create этот стиль называется TVS_EDITLABELS.
dwStyle=dwStyle | TVS_EDITLABELS;
Установив этот стиль теперь можно вызывать функцию редактирования по месту на основе указателя.
GetTreeCtrl().EditLabel(hi);
Полное описание этой функции:
CEdit* EditLabel( HTREEITEM hItem );
Действительно создается временный элемент управления, который при желании можно и перехватить. Но вот только отредактировав этот элемент управления вы не сможете сохранить текст. Все нормально. После окончания редактирования дереву посылается сообщение TVN_ENDLABELEDIT, которое говорит о том, что редактирование дерева закончено. Это сообщение нужно связать с функцией через Add Windows Message Handle. И после этого написать код в функцию для изменения текста дерева. Вот такой:
void CLeftView::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
HTREEITEM hi=TestSelectItemTree();
GetTreeCtrl().SetItemText(hi,pTVDispInfo->item.pszText);
*pResult = 0;
}
Из структуры я извлек название, получил указатель на активный элемент и поменял текст элемента. Если корень изменять нельзя, то нужно определить функцию, которая проверяет, что это именно корень.