[ Next ] [ Previous ] | Chapter 18 |
When OS/2 was released in the middle of the MacintoshTM era, many people wondered why it didn't have
s control similar to that used in any of the Mac's popular, easy-to-use word
processors. IBM's answer in OS/2 1.2 was the multiline edit control
(usually abbreviated as MLE); this control provided a similar yet
simpler version of what people saw on the Macintosh. It supported
the multiline text entry and browsing that they were familiar with and
the anchor point selection style discussed in Chapter 17.
But let's not stop there: The MLE was also one of the first controls to
support a selectable font, and it can handle very large text buffers
easily. Being a stream-based editing control means that word wrap also came cheaply. Finally, it included a primitive undo capability.
Unfortunately, IBM tried (and failed) to emulate the Macintosh; it has
no multifont capability, which contributed heavily to ease-of-use that
made Mac such a big seller. Also, it seems clumsily written. Even with
all of these problems, the MLE still is quite usable and is nifty for
grabbing a chunk of text from the user when needed. MLEs are used
everywhere - in the WPS (setting pages), in containers (editing icon
text), and so on.
Table 18.1 shows the styles available for the MLE control.
Style | Description |
MLS_BORDER |
Creates an MLE with a surrounding border |
MLS_DISABLEUNDO |
Specifies that the MLE should ignore undo actions. |
MLS_HSCROLL | Specifies that the MLE should have a horizontal scrollbar. |
MLS_IGNORETAB |
Specifies that the MLE should ignore the tab key and instead pass the WM_CHAR message to its owner. |
MLS_READONLY |
Creates an MLE that is read-only. |
MLS_WORDWRAP |
Specifies that the MLE should wrap words to the next line that do not fit on the current line. |
MLS_VSCROLL | Specifies that the MLE should have a vertical scrollbar. |
Format |
Description |
CR-LF |
A carriage return (CR) followed by a line feed (LF) denotes the end of a line. |
LF |
LF denotes the end of a line |
Windows MLE
|
On import, CR CR LF is ignored, and CR LF is interpreted as end of
line. On export, CR LF is used to specify end of line and CR CR LF is
used to denote line breaks caused by word wrapping. |
The following sample shows an MLE and performs some rudimentary operations with it.
MLE1.C
|
![]() | |
Figure 18.1 MLE control. |
Upon
running MLE1, it is noticeable how the control repainted itself
whenever any changes took place. Whenever an application does a lot of
textual manipulations, this can look rather nasty. Fortunately, two
messages can be used to disable and enable updates - MLM_DISABLEREFRESH
and MLM_ENABLEREFRESH. The first messages tells the MLE that the
application is making many changes and that it should not update the
display until an MLM_ENABLEREFRESH message is sent.
![]() |
Gotcha!
The MLM_DISABLEREFRESH message does not work as advertised; instead
of disabling display updates and disabling the mouse pointer, it simply
disables the mouse pointer. A better way to perform this action is to
use the WinEnableWindowUpdate function specifying FALSE as the second
parameter (and reenabling using the same function with TRUE as the
second parameter). Also, the MLM_DISABLEREFRESH message disables the
mouse systemwide, instead of just over itself, which can be quite
annoying for operations that take up large amounts of time. An
application that is guilty of this is System Editor, readers can start
the editor and read a file that is greater than 500K to see an example
of this. |
MLE2 is the next sample to be looked at. It calls WinEnableWindowUpdate
to disable the window refresh before inserting the text and calls it
again to enable the window refresh afterward. Its behavior should be
compared with that of MLE1.
MLE2.C
MLE2.RC
MLE2.H
MLE2.MAK
MLE2.DEF
In Chapter 17, we discussed what the
clipboard is and which entry-field messages can be used to interface
with it. The MLE has a similar set of messages - MLM_COPY, MLM_CUT and
MLM_PASTE - that perform analogous functions. As with the entry field,
the first two messages require that some text is selected in the MLE,
so these two usually are used in conjunction with MLM_SETSEL message.
Because the concepts associated with the clipboard were explained
thoroughly in the last chapter, we will move on the next topic.
Suppose the insertion point corresponding to a known line number
withing an MLE has to be found. Or, given an insertion point, the line
number where the insertion point can be found to be determined. Because
of the word-wrap
capability of the MLE, these can be difficult - if not impossible - to
calculate without some help from the control. Fortunately, the MLE has
two such messages that perform these functions for you; they are
MLM_CHARFROMLINE and MLM_LINEFROMCHAR.
The following example uses the MLM_CHARFROMLINE message to read its contents line by line and to write each line to a file.
MLE3.C
MLE3.RC
MLE3.H
MLE3.MAK
MLE3.DEF
The main difference between this sample and the previous two is the addition of the function exportText.
Its purpose is to read, line by line the contents of the MLE and to
write each line to a file. To do this, we make use of the
MLM_QUERYLINECOUNT, MLM_CHARFROMLINE, and MLM_QUERYLINELENGTH messages.
First, we need to determine how many lines are in the MLE; the first
message does this.
lNumLines=LONGFROMMR(WinSendMsg(hwndMle,
MLM_QUERYLINECOUNT,
0,
0));
Obviously, we use this as the terminating condition of a for
loop. Each iteration of the loop performs the following: Determine the
offset of the first character on the line using MLM_CHARFROMLINE; query
the length of the line using MLM_QUERYLENGTH; finally, query the data
on the line using MLM_EXPORT.
for (lIndex=0; lIndex<lNumLines; lIndex++) {
iBegin=LONGFROMMR(WinSendMsg(hwndMle,
MLM_CHARFROMLINE,
MPFROMLONG(lIndex),
0));
lSzLine=LONGFROMMR(WinSendMsg(hwndMle,
MLM_QUERYLINELENGTH,
MPFROMLONG(iBegin),
0));
memset(achImpExp,0,sizeof(achImpExp));
WinSendMsg(hwndMle,
MLM_EXPORT,
MPFROMP(&iBegin),
MPFROMP(&lSzLine));
fputs(achImpExp,pfExport);
} /* endfor */
![]() |
Gotcha!
The MLM_QUERYLINECOUNT takes as its parameter an insertion point instead of a line number, as would be imagined. |
An action that
is commonly performed on large quantities of text is searching for a
particular string. Before digging out Knuth volumes, readers
should take note of the MLM_SEARCH message. This message will do both
search and search-and-replace actions on the text contained withing the
MLE. The method of communication is via the MLE_SEARCHDATA structure,
which specifies the string to search for and (optionally) a replacement
string.
typedef struct _SEARCH /* search */
{
USHORT
cb;
/* size of search spec structure */
PCHAR pchFind; /* string to
search
for
*/
PCHAR pchReplace; /* string to replace
with
*/
SHORT cchFind; /* length of
pchFindString
*/
SHORT cchReplace; /* length of replace
string
*/
IPT iptStart; /* point
at which to start search */
/* (negative indicates cursor pt) */
/* becomes pt where string found */
IPT iptStop; /*
point at which to stop search */
/* (negative indicates EOT) */
USHORT cchFound; /* Length of found string at iptStart */
} MLE_SEARCHDATA;
cb specifies the size of the structure, pchFind points to the search text. pchReplace points to the text to replace with. cchFind specifies the length of the search text. cchReplace specifies the length of the replacement text. iptStart
on entry specifies the search starting point. If this is -1, cursor
position is used. On exit, iptStart specifies the insertion point of
the first character of the occurrence found, if one is found. iptStop specifies the search ending point. If this is -1, the end of text is used. If this is less than iptStart, the search wraps to the beginning of the text after it reaches the end. cchFound specifies the length of the text found.
mpParm1 specifies one or more flags that are used to determine the action of the search.
Format |
Description |
MLFSEARCH_CASESENSITIVE | If set, only exact matches are considered a successful match.
If not set, any case-combination of the correct characters in the
correct sequence is considered a successful match. |
MLFSEARCH_SELECTMATCH | If set, the MLE selects the text and scrolls it into view when found,
just as if the application had sent an MLM_SETSEL message. This is not
done if MLFSEARCH_CHANGEALL is also indicated. |
MLFSEARCH_CHANGEALL | Using the MLE_SEARCHDATA structure specified in mpParm1, all occurrences of pchFind are found, searching from iptStart to iptStop, and replacing them with pchReplace. If this style is selected, the cchFound field has no meaning, and the iptStart
value points to the place where the search stopped, or is the same as
iptStop because the search has not been stopped at any of the found
strings. The current cursor location is not moved. However, any
existing selection is deselected. |
Finally, there is a number of messages that perform miscellaneous
functions. To select a font, there is the MLM_SETFONT message, which is
a bit tricky to use since it expects a font attributes structure(FATTRS). Fortunately, the Font Dialog (see Chapter 26)
returns the FATTRS structure for the font selected, so if we
consent to using this (a good idea), we can avoid a lot of work. The
current font is returned in a FATTRS structure by the MLM_QUERYFONT
message.
![]() |
Gotcha!
The MLM_SETFONT message is the only way to change the font of an MLE control. WinSetPresParam will not work as it does with the other window classes. |
[ Next ] [ Previous ] | Chapter 18 |