{"id":34593,"date":"2005-08-12T10:00:10","date_gmt":"2005-08-12T10:00:10","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/08\/12\/adding-a-lookup-control-to-the-dictionary-searching-pinyin\/"},"modified":"2005-08-12T10:00:10","modified_gmt":"2005-08-12T10:00:10","slug":"adding-a-lookup-control-to-the-dictionary-searching-pinyin","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050812-10\/?p=34593","title":{"rendered":"Adding a lookup control to the dictionary: Searching Pinyin"},"content":{"rendered":"<p><P>\nFinally we start searching.\nFor now, the search algorithm is going to be very simple:\nThe string you type into the edit control will be treated as the\nstart of a Pinyin word or phrase.\nWe&#8217;ll make it fancier later.\n<\/P>\n<P>\nHere is where a lot of the groundwork\n(<A HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/05\/19\/420038.aspx\">some of which I called out explicitly<\/A>\nand some of which I slipped in without calling attention to it)\nstarts to pay off.\n<\/P>\n<P>\nUp until now, the items in the listview came directly from the\ndictionary.\nOf course, when a word is being looked up, we want to reduce the\nlist to those that match the word or phrase being searched for.\nWe will introduce a new member <CODE>m_vMatch<\/CODE> which is\na vector of pointers to the items we actually want to display.\n<\/P>\n<PRE>\nclass RootWindow : public Window\n{\n &#8230;\n <FONT COLOR=\"blue\"><STRIKE>\/\/ const DictionaryEntry&amp; Item(int i) { return m_dict.Item(i); }\n \/\/ int Length() { return m_dict.Length(); }<\/STRIKE>\n const DictionaryEntry&amp; Item(int i) { return *m_vMatch[i]; }\n int Length() { return m_vMatch.size(); }<\/FONT>\n &#8230;\n <FONT COLOR=\"blue\">void OnCommand(UINT id, UINT cmd);\n void Refilter();<\/FONT>\n &#8230;\nprivate:\n &#8230;\n <FONT COLOR=\"blue\">vector&lt;const DictionaryEntry*&gt; m_vMatch;<\/FONT>\n};\n<\/PRE>\n<P>\nBy tweaking our <CODE>Item<\/CODE> and <CODE>Length<\/CODE> member\nfunctions, we can now render out of the list of matches instead of\nout of the entire dictionary.\n<\/P>\n<PRE>\nLRESULT RootWindow::OnCreate()\n{\n &#8230;\n <FONT COLOR=\"blue\"><STRIKE>\/\/ ListView_SetItemCount(m_hwndLV, Length());<\/STRIKE><\/FONT>\n &#8230;\n m_hwndLastFocus = m_hwndEdit;\n <FONT COLOR=\"blue\">m_vMatch.reserve(m_dict.Length());\n Refilter();<\/FONT><\/p>\n<p> return 0;\n}\n<\/PRE>\n<P>\nSince the list of matches is at most the number of words in the\ndictionary, we can reserve that size up front and avoid needless\nreallocations.\nOnce we&#8217;ve done that, we call our new <CODE>Refilter<\/CODE> method\nto compute the matches (which populates the listview).\nIt is <CODE>Refilter<\/CODE> that will do the\n<CODE>ListView_SetItemCount<\/CODE>, so there&#8217;s no point in us\ndoing it here.\n<\/P>\n<PRE>\n<FONT COLOR=\"blue\">void RootWindow::OnCommand(UINT id, UINT cmd)\n{\n switch (id) {\n case IDC_EDIT:\n  switch (cmd) {\n  case EN_CHANGE:\n   Refilter();\n  }\n  break;\n }\n}<\/FONT><\/p>\n<p>  \/\/ add to RootWindow::HandleMessage()\n  <FONT COLOR=\"blue\">case WM_COMMAND:\n   OnCommand(GET_WM_COMMAND_ID(wParam, lParam),\n             GET_WM_COMMAND_CMD(wParam, lParam));\n   break;<\/FONT>\n<\/PRE>\n<P>\nWe also rebuild the list of matches if the user makes a change\nto the edit control.\nThis means that there is no need for a &#8220;Search&#8221; button.\nThe listview auto-filters as you type.\n<\/P>\n<PRE>\n<FONT COLOR=\"blue\">void RootWindow::Refilter()\n{\n WCHAR szBuf[256];\n DWORD cchBuf = GetWindowText(m_hwndEdit, szBuf, 256);\n m_vMatch.clear();\n for (int i = 0; i &lt; m_dict.Length(); i++) {\n  const DictionaryEntry&amp; de = m_dict.Item(i);\n  if (StrCmpNIW(de.m_pszPinyin, szBuf, cchBuf) == 0) {\n   m_vMatch.push_back(&amp;de);\n  }\n }\n ListView_SetItemCount(m_hwndLV, Length());\n ListView_SetItemState(m_hwndLV, -1, 0, LVIS_SELECTED);\n InvalidateRect(m_hwndLV, NULL, FALSE);\n}<\/FONT>\n<\/PRE>\n<P>\nBuilding the list of matches is rather simple and anticlimactic.\nWe get the string the user typed into the edit control and\nwalk through all the words in the dictionary, seeing if the\nPinyin begins with the user&#8217;s typing.\nIf so, then we add it to the match vector.\n<\/P>\n<P>\nOnce the match list is built up, we tell the listview\nhow many we found, clear the selection (so that the selection\ndoesn&#8217;t appear to move around from one word to another\nas items are filtered in or out), and invalidate the client\nrectangle to trigger a repaint.\n<\/P>\n<P>\nThat&#8217;s all there is to it.\nIf you run this program and start typing into the edit control,\nyou&#8217;ll see the list of words in the listview grow and shrink as\nyou type.\n<\/P>\n<P>\nThat&#8217;s all for this month.\nNext month, we&#8217;ll work on expanding the scope of the search.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Finally we start searching. For now, the search algorithm is going to be very simple: The string you type into the edit control will be treated as the start of a Pinyin word or phrase. We&#8217;ll make it fancier later. Here is where a lot of the groundwork (some of which I called out explicitly [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-34593","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Finally we start searching. For now, the search algorithm is going to be very simple: The string you type into the edit control will be treated as the start of a Pinyin word or phrase. We&#8217;ll make it fancier later. Here is where a lot of the groundwork (some of which I called out explicitly [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/34593","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=34593"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/34593\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=34593"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=34593"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=34593"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}