P>>Не подскажете где икать информацию по реализации сабжа,
P>>под сабжем подразумеваю следующее:
P>> И как он правильно называется.
A>Называется это Auto Complete. Начать поиск можно с функции SHAutoComplete и интерфейса IAutoComplete.
SHAutoComplete — самый простой способ, но он позволяет вводить только URL'ы и имена файлов.
Если тебе нужно запоминать любой текст, то придется юзать IAutoComplete. Для этого создаешь объект
CComPtr<IAutoComplete> AutoComplete;
и инициализируешь его
AutoComplete->Init(GetDlgItem(IDC_CMD), m_SS, NULL, NULL);
CComQIPtr<IAutoComplete2> ac2(AutoComplete);
ac2->SetOptions(ACO_AUTOAPPEND|ACO_AUTOSUGGEST|ACO_UPDOWNKEYDROPSLIST);
Вторым параметром передается интерфейс, управляющий выводом строк в выпадающий список, их хранением и т.д. Он должен уметь предоставлять интерфейс IEnumSrting. Чтобы долго не мучаться я поступил просто: создал класс, производный от IEnumSrting
class CStringStorage : public IEnumString
{
...
};
и реализовал все требуемые методы. В частности, QueryInterface выглядит так:
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject)
{
HRESULT hr = E_NOINTERFACE;
if(ppvObject == NULL)
return E_POINTER;
*ppvObject = NULL;
if(riid == IID_IUnknown)
*ppvObject = static_cast<IUnknown*>(this);
if(riid == IID_IEnumString)
*ppvObject = static_cast<IEnumString*>(this);
if(*ppvObject != NULL)
{
((LPUNKNOWN)*ppvObject)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
Методы IEnumString'а (Next, Skip, Reset) реализуешь сам в зависимости от того, где будут храниться запомненные строки.
Самый сложный вопрос,
на который мне так никто и не ответилАвтор: SWW
Дата: 15.02.05
заключается в том, как удалять ненужные строки. Но мне таки удалось это сделать. Оказывается, еще есть интерфейс IAutoCompleteDropDown котрый в MSDN почему-то не описан. Получить его можно из IAutoComplete
CComQIPtr<IAutoCompleteDropDown> acdd(AutoComplete);
В нем есть два метода: ResetEnumerator(void) и GetDropDownStatus(/*[out]*/ DWORD *pdwFlags, /*[string][out]*/ LPWSTR *ppwszString). Первый вызывает повторное заполнение списка, а с помощью второго можно получить информацию о текущем состоянии вывавшего списка. Для этого я встроил его в PreTranslateMessage и проверяю: если нажата клавиша <del> && список при этом открыт, то вызывается функция CStringStorage для удаления выделенной строки:
BOOL CSendDlg::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message != WM_KEYDOWN || pMsg->wParam != VK_DELETE)
return IsDialogMessage(pMsg);
CComQIPtr<IAutoCompleteDropDown> acdd(AutoComplete);
if(acdd)
{
DWORD Flag = 0;
LPWSTR Cmd = NULL;
acdd->GetDropDownStatus(&Flag, &Cmd);
if((Flag & ACDD_VISIBLE) != 0 && Cmd != NULL)
{
m_SS->RemoveCmd(Cmd);
::CoTaskMemFree(Cmd);
CWindow wndCmd = GetDlgItem(IDC_CMD);
wndCmd.SetWindowText(_T(""));
acdd->ResetEnumerator();
wndCmd.PostMessage(WM_KEYDOWN, VK_DOWN);
}
}
return IsDialogMessage(pMsg);
}
PostMessage(WM_KEYDOWN, VK_DOWN) нужен для того, чтобы вновь отобразить выпавший список с новым содержимым (т.к. после нажатия на <del> он закрывается).