9.5 编辑类

来源:互联网 发布:网络mc第一红人大赛 编辑:程序博客网 时间:2024/06/05 10:23

摘录于《Windows程序(第5版,珍藏版).CHarles.Petzold 著》P315

        在一定程度上讲,编辑类是最简单的预定义窗口类,而另一方面却又是最复杂的。当你用“edit”作为类名创建子窗口时,可以基于 CreateWindow 调用的 x 坐标、y 坐标、宽度和高度参数定义一个矩形。这个矩形包含可编辑的文本。一旦子窗口控件获得输入焦点,你就可以输入文本,移动光标,使用鼠标或 Shift 键和光标键选择部分文本,按快捷键 Ctrl-X 删除选中的文本并将其放入剪贴板中,按快捷键 Ctrl-C 复制文本,按快捷键 Ctrl-V 从剪贴板粘贴文本

         最简单的编辑控件应用是单行输入框。但是编辑控件不仅仅限于单行,我会在 POPPAD1 程序展示具体操作。随着我们在本书中遇到各种各样的主题,我们会逐步增加 POPPAD 的功能,添加菜单、对话框(加载和保存文件)和打印功能。程序的最终版本将是一个简单但完整的文本编辑器,而且额外需要的代码非常少。

/*--------------------------------------------------------   POPPAD1.C --   Popup Editor using child window edit box                 (c) Charles Petzold, 1998  --------------------------------------------------------*/#include <windows.h>#define ID_EDIT 1LRESULT CALLBACK WndProc    (HWND, UINT, WPARAM, LPARAM) ;TCHAR szAppName[] = TEXT ("PopPad1");int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,                    PSTR szCmdLine, int iCmdShow){     HWND         hwnd ;     MSG          msg ;     WNDCLASS     wndclass ;     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;     wndclass.lpfnWndProc   = WndProc ;     wndclass.cbClsExtra    = 0 ;     wndclass.cbWndExtra    = 0 ;     wndclass.hInstance     = hInstance ;     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;     wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);     wndclass.lpszMenuName  = NULL ;     wndclass.lpszClassName = szAppName ;     if (!RegisterClass (&wndclass))     {          MessageBox (NULL, TEXT ("This program requires Windows NT!"),                      szAppName, MB_ICONERROR) ;          return 0 ;     }     hwnd = CreateWindow (szAppName, szAppName,                          WS_OVERLAPPEDWINDOW,                          CW_USEDEFAULT, CW_USEDEFAULT,                          CW_USEDEFAULT, CW_USEDEFAULT,                          NULL, NULL, hInstance, NULL) ;     ShowWindow (hwnd, iCmdShow) ;     UpdateWindow (hwnd) ;     while (GetMessage (&msg, NULL, 0, 0))     {          TranslateMessage (&msg) ;          DispatchMessage (&msg) ;     }     return msg.wParam ;}LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){     static HWND hwndEidt;     switch (message)     {     case WM_CREATE:          hwndEidt = CreateWindow(TEXT("edit"), NULL,                                  WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |                                  ES_AUTOHSCROLL | ES_AUTOVSCROLL,                                  0, 0, 0, 0, hwnd, (HMENU) ID_EDIT,                                  ((LPCREATESTRUCT)lParam)->hInstance, NULL);          return 0;     case WM_SETFOCUS:          SetFocus(hwndEidt);          return 0;     case WM_SIZE:          MoveWindow(hwndEidt, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);          return 0;     case WM_COMMAND:          if (LOWORD(wParam) == ID_EDIT)             if (HIWORD(wParam) == EN_ERRSPACE ||                    HIWORD(wParam) == EN_MAXTEXT)                MessageBox(hwnd, TEXT("Edit control out of space."),                           szAppName, MB_OK | MB_ICONSTOP);         return 0;     case WM_DESTROY:          PostQuitMessage (0) ;          return 0 ;     }     return DefWindowProc (hwnd, message, wParam, lParam) ;}

        POPPAD1 是一个不超过 100 行 C 代码编写的多行编辑器(不过没有文件 I/O(输入/输出)功能)。(不过,它有一个缺点,就是预定义的多行编辑控件最多只能处理 30000 字符的文本。)可以看出,POPPAD1 本身所做的事情并不多。预定义的编辑控件替我们做了大量工作。这个程序让你了解到在没有任何其他程序的帮助下编辑控件都能做些什么。

9.5.1  编辑类的样式

        如前所述,你已经在 CreateWindow 调用中通过“编辑”类创建了一个编辑控件。窗口样式是 WS_CHILD,外加几个选项。和在静态子窗口控件中一样,编辑控件的文本也可以以左对齐、右对齐或居中。这些格式可以通过 ES_LEFT,ES_RIGHT 或 ES_CENTER 窗口样式来指定。

        默认情况下,一个编辑控件只有一行。你可以用窗口样式 ES_MULTILINE 来创建一个多行编辑控件。对于单行编辑控件,可以正常输入文本直到编辑控件矩形的结尾处。要创建一个可以自动水平滚动的编辑控件,可以使用样式 ES_AUTOHSCROLL。对于一个多行编辑控件,文本会自动换行,除非你使用 ES_AUTOHSCROLL 样式。在使用 ES_AUTOHSCROLL 的情况下。必须按回车键才可以开始新行。对多行编辑控件,还可以使用窗口样式 ES_AUTOVSCROLL 来添加垂直滚动功能。

        对使用了这些滚动方式的多行编辑控件,可能还需要为编辑控件添加滚动条。具体做法与为非子窗口添加滚动条时的做法一样,都是通过使用窗口样式标识符 WS_HSCROLL  和 WS_VSCROLL。在默认情况下,一个编辑控件是没有边框的。可以用 WS_BORDER 样式来添加边框。

        当在编辑控件中选择文本时,Windows 会将选中的文本显示为反选高亮。一旦编辑控件失去输入焦点,被选中的文本便不再高亮显示。如果希望选中的文本在编辑控件失去输入焦点时仍然保持高亮显示,可以使用 ES_NOHIDESEL 样式

        在 POPPAD1 程序创建编辑控件时,相应样式是在 CreateWindow 调用中指定的:

WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |     WS_BORDER | ES_LEFT | ES_MULTILINE |     ES_AUTOHSCROLL | ES_AUTOVSCROLL,
在 POPPAD1 程序中,编辑控件的尺寸是后面在 WndProc 接收到 WM_SIZE 消息时所调用的 MoveWindow 中定义的。编辑控件的尺寸简单地设置为主窗口的尺寸:

MoveWindow(hwndEidt, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
对于单行编辑控件来说,控件的高度应容纳一个字符的高度。如果编辑控件有边框(大多数编辑控件都有),那么可以按一个字体高度(包括外部间距)的 1.5 倍计算

9.5.2  编辑控件的通知消息

        编辑控件向其父窗口过程发送 WM_COMMAND 消息。相应的 wParam 和 lParam 变量的含义与其在按钮控件中的含义一直:

 LOWORD(wParam) 子窗口 ID HIWORD(wParam) 通知码 lParam 子窗口句柄        通知码如下所示:

 EN_SETFOCUS 编辑控件得到了输入焦点 EN_KILLFOCUS 编辑控件失去了输入焦点 EN_CHANGE 编辑控件的内容将变化 EN_UPDATE 编辑控件的内容已变化 EN_ERRSPACE 编辑控件没有空间了 EN_MAXTEXT 编辑控件没有空间完成插入了 EN_HSCROLL 编辑控件水平滚动条被单击了 EN_VSCROLL 编辑控件垂直滚动条被单击了

        POPPAD1 只捕获 EN_ERRSAPCE 和 EN_MAXTEXT 通知码并显示一个一个消息框作为回应。

9.5.3  使用编辑控件

        如果在主窗口上使用了多个单行编辑控件,则需要利用窗口子类来将输入焦点从一个控件移动到另一个控件。这可以通过拦截 Tab 和 Shift-Tab 击键来完成,就和 COLORS1 程序一样。(另一个窗口子类的例子会在本章稍后的 HEAD 程序中讨论。)如何处理回车键由你自己决定。可以使用和处理 Tab 键相同的方法,或将其作为一个信号传递给程序,通知程序所有的编辑框已经准备就绪。

        如果要把文本插入编辑框,可以使用 SetWindowText 函数。从编辑控件中读取文本涉及调用 GetWindowTextLength 和 GetWindowText。我们会再以后改进的 POPPAD 版本中看见一些这方面的实例。

9.5.4  传递给编辑控件的消息

        我不会涵盖所有使用 SendMessage 发送给编辑控件的消息,因为这些消息太多了,其中的一些在更新的 POPPAD 版本中会用到。下面是一个概括的介绍。

        下面这些消息可以让你剪切、复制或清除当前选择的内容。用户可以使用鼠标或 Shift 键加光标键来选择需要的文本,从而高亮显示编辑控件中所选的文本:

SendMessage (hwndEdit, WM_CUT, 0, 0);SendMessage (hwndEdit, WM_COPY, 0, 0);SendMessage (hwndEdit, WM_CLEAR, 0, 0);
WM_CUT 把当前选择从编辑控件中移走并发送给剪贴板。WM_COPY 把当前选择从编辑控件中复制到剪贴板并保留在原地。WM_CLEAR 把当前选择从编辑控件中删除并且不传递给剪贴板。

        还可以把剪贴板上的文本插入到编辑控件的当前位置:

SendMessage (hwndEdit, WM_PASTE, 0, 0);
可以用如下函数获得当前选择文本的初始位置和终止位置:

SendMessage (hwndEdit, EM_GETSEL, (WPARAM)&iStart, (LPARAM) &iEnd);
终止位置其实是你选择的最后一个字符的位置加 1。

        可以如下选择文本:

SendMessage (hwndEdit, EM_SETSEL, iStart, iEnd);
也可以用其他文本取代当前选择的文本:

SendMessage (hwndEdit, EM_REPLACESEL, 0, (LPARAM)szString);
对于多行编辑器,可以如下得到编辑器的行数:

iCount = SendMessage (hwndEdit, EM_GETLINECOUNT, 0, 0);

        对于某一个指定的行,可以获得从编辑缓冲区的起点到这行的位移量

iOffset = SendMessage (hwndEdit, EM_LINEINDEX, iLine, 0);
行从 0 开始计数。如果传入 -1 给 iLine,可以返回插入符号所在行的位移量。如下可得到行的长度:

iLength = SendMessage (hwndEdit, EM_LINELENGTH, iLine, 0);

可以用如下函数来复制某一行到缓冲区

iLength = SendMessage (hwndEdit, EM_GETLIEN, iLine, (LPARAM)szBuffer);

0 0
原创粉丝点击