Introduction
It is one more article devoted to autocompletion. I have written the program of the warehouse automation for one organization. The organization is the big warehouse with intensive movement of property that demands filling a plenty of electronic documents. For simplification of users life I used the windows built-in autocompletion, which works only for single-line editboxes (without style ES_MULTILINE
). I hoped that to users will be enough of it, but a bit later users have estimated advantages of autocompletion and have wanted it for all textual fields, including multiline editboxes. Attempts to force to work builtin autocompletion in multiline fields did not give of result as well as search of suitable code in the net and I have decided to fill in this blank.
In addition to typical properties of the builtin autocompletion my realization allows transfer a task of management of string storage to the user of the program. User may to add and delete lines from the list, removing thus from the programmer necessity of string storage management.
Description
Autocompletion is realized as COM object (Progid:Acmpl.AutoCompleteML
), which connects to editbox. The interface of object (IAutoCompleteML)
is defined by analogy to interface IAutoComplete
.
typedef enum ACMLFlags {
ACML_AutoSuggest = 1,
ACML_AutoAppend = 2,
ACML_UpDownKeyDropList = 4,
ACML_ToolTip = 8,
ACML_EnableUserAutoAdd = 16,
ACML_EnableUserDelete = 32
} ACMLFlags;
interface IAutoCompleteML: IDispatch
{
[id(1), helpstring("method Init")] HRESULT Init([in]
long hwndEdit, [in] IUnknown *punkACL);
[propget, id(3), helpstring("property Options")]
HRESULT Options([out, retval] ACMLFlags *pVal);
[propput, id(3), helpstring("property Options")]
HRESULT Options([in] ACMLFlags newVal);
[propget, id(4), helpstring("property ItemMaxLines")]
HRESULT ItemMaxLines([out, retval] long *pVal);
[propput, id(4), helpstring("property ItemMaxLines")]
HRESULT ItemMaxLines([in] long newVal);
[propget, id(5), helpstring("property Enabled")]
HRESULT Enabled([out, retval] VARIANT_BOOL *pVal);
[propput, id(5), helpstring("property Enabled")]
HRESULT Enabled([in] VARIANT_BOOL newVal);
};
Properties/methods of autocompletion object (Acmpl.AutoCompleteML
) "inherited" from built-in autocompletion:
Init()
- initialization of autocompletion object, takes handle of editbox, and pointer to autocompletion source object
- Flag
ACML_AutoAppend
- autoappend of a text tail
- Flag
ACML_AutoSuggest
- dropping out the suggest-list
- Flag
ACML_UpDownKeyDropList
- a call of the suggest-list by up/down keys
Enable()
- autocompletion switching-on/off
New properties (not in the builtin autocompletion):
ItemMaxLines
- a maximum number of lines in the one item of suggest-list
- Flag
ACML_EnableUserAutoAdd
- user can add a line into source of lines by Enter key. If editbox has ES_WANTRETURN
style a line can be added by Ctrl+Enter combination
- Flag
ACML_EnableUserDelete
- user can remove a line from a source of lines. When this option included elements of the suggest-list are displayed with the remove button
- Flag
ACML_ToolTip
- tooltip may be useful to display full text of suggest-list element not limited by ItemMaxLines
value
The autocompletion object may use any source of autocompletion wich supports IEnumStrings
interface, but thus some new properties of object will be inaccessible. For use of all properties of object it is necessary to use as a source of lines Acmpl.StringStorage
object which realizes IStringStorage
interface. Also object Acmpl.StringStorage
may be used for standard autocompletion object.
interface IStringStorage: IDispatch
{
[id(1), helpstring("method Add")] HRESULT Add([in] BSTR Item);
[id(2), helpstring("method LoadPrivateProfile")]
HRESULT LoadPrivateProfile([in] BSTR File, [in] BSTR Section);
[id(3), helpstring("method LoadXML")]
HRESULT LoadXML([in] VARIANT Source);
[id(4), helpstring("method SavePrivateProfile")]
HRESULT SavePrivateProfile([in, defaultvalue("")]
BSTR File, [in, defaultvalue("")] BSTR Section);
[id(5), helpstring("method SaveXML")]
HRESULT SaveXML([in] VARIANT Destination);
[id(6), helpstring("method Delete")] HRESULT Delete([in] BSTR Item);
};
Methods of object Acmpl.StringStorage
:
LoadPrivateProfile()/SavePrivateProfile()
loads/saves the list of lines in a textual file. Before saving multiline strings will be encoded in single-line. SavePrivateProfile()
may be called with empty parameters, in this case lines are saved in the same section of text file whence were loaded
LoadXML()/SaveXML()
loads/saves the list of lines in xml document, textual parameter are interpreted as name of file, and objective parameter as an xml document element in which will be loaded/saved an child element <strings>
Add()/Delete()
are automatically called for addition/removal of lines from a source of the data when flags ACML_EnableUserAutoAdd
and ACML_EnableUserDelete
are set in autocompletion object.
For user interface objects ATL/WTL classes are used. After initialization of autocompletion object subclasses for editbox and his(its) parental window are created. These subclasses process changes of editbox contents and depending of options of autocompletion object the list of suitable lines drops out and/or the suffix to editbox contents is added.
Structure of component project
class CACml
- COM autocompletion object
class CEditML
- a subclass of a multiline editbox
class CEditMLParent
- a subclass of the parent of a multiline editbox
class CListBoxML
- multiline list control
class CListBoxMLParent
- the parent for the multiline list control
class CStrStg
- COM string storage object
Using the code
For use of autocompletion in VC the project it is necessary to import type library from acml.dll
#import "acmpl.dll"
To create an autocompletion source, to load in it strings
ACMPLLib::IStringStoragePtr m_spStrings;
m_spStrings.CreateInstance(__uuidof(ACMPLLib::StringStorage));
m_spStrings->LoadXML(L"acml.xml");
To create autocompletion object, to connect it with a source of strings and editbox
ACMPLLib::IAutoCompleteMLPtr m_spac;
m_spac.CreateInstance(__uuidof(ACMPLLib::AutoCompleteML));
m_spac->Init((long)GetDlgItem(IDC_EDIT1), m_spStrings);
By default all options of autocompletion are set, for setting a subset of options add the next line.
m_spac->Options = ACML_AutoSuggest|ACML_ToolTip;
Bonus
For the multiline list in a component WTL-class CListBoxML
is used, which is designed portable at a level of source code, and it may be used separately from the component.