文本输入框



一、文本输入框的介绍
    从用户那里获取文字信息是与用户进行交互的一个重要组成部分, 输入框的作用则是搭建起用户与软件交互的一个直接桥梁之一。
    
    通常, 当我们点击输入框的编辑区域时, 输入框中会出现插入光标,我们可以直接在输入框中输入文字或文本信息。 我们还可以使用一些快捷键例如Ctrl + C(复制)、Ctrl + V(粘贴)等快捷键操作, 前提是如果你想允许用户这么做的话。
    
    文本输入框分为单行输入框和多行输入框, 单行输入框即不能进行换行操作, 所有内容都将在一行写完, 常用来输入一些较短的文本, 例如常见的用户名/密码输入框。
    多行文本输入框常用于输入较长的段落时文本, 用户可以使用回车键进行换行, 例如Windows自带的记事本的文本编辑窗口。
    
    多行文本输入框通常会在紧靠右侧的地方带上一个垂直滚动条, 或者在底部带上一个水平滚动条, 方面用户快速查看输入框中的内容。图示中是一个带有水平滚动条和垂直滚动条的多行文本输入框:


    
    在本篇随笔的最后, 我们还将使用输入框以及按钮、组合框等已学到的控件来完成一个简易的文本编辑器。
    
    
   


二、文本输入框的创建
    创建文本输入框的步骤与创建一个按钮类似, 只需要调用CreateWindows创建一个输入框子窗口控件就可以了, 如果已经掌握了如何创建一个按钮, 那么创建一个文本输入框就会感觉很简单。
    
    创建一个编辑类控件的窗口类名为"edit", 例如创建一个上图中所演示的输入框的CreateWindow函数中的参数为:

复制代码
    case WM_CREATE:
        hwndInput = CreateWindow( TEXT("edit"), NULL,
            WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | WS_BORDER |
            ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
            20, 20, 350, 100,
            hwnd, (HMENU)1, ((LPCREATESTRUCT) lParam) -> hInstance, NULL ) ;
        return 0 ;
复制代码

   
    创建一个带有输入框的窗口, 完整示例代码如下(已折叠):

View Code - CreateWditBox-Demo.c
 1 /*C语言Windows程序设计 -> 创建文本输入框 -> 演示*/
 2 
 3 #include <windows.h>
 4 
 5 LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ) ;
 6 
 7 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )
 8 {
 9     static TCHAR szAppName[] = TEXT( "demo" ) ;
10     HWND        hwnd ;
11     MSG            msg ;
12     WNDCLASS    wndclass ;
13 
14     wndclass.lpfnWndProc    = WndProc ;
15     wndclass.style            = CS_HREDRAW | CS_VREDRAW ;
16     wndclass.hInstance        = hInstance ;
17     wndclass.cbClsExtra        = 0 ;
18     wndclass.cbWndExtra        = 0 ;
19     wndclass.hbrBackground    = (HBRUSH) GetStockObject(WHITE_BRUSH) ;
20     wndclass.hCursor        = LoadCursor( NULL, IDC_ARROW ) ;
21     wndclass.hIcon            = LoadIcon( NULL, IDI_APPLICATION ) ;
22     wndclass.lpszClassName    = szAppName ;
23     wndclass.lpszMenuName    = NULL ;
24     
25     if( !RegisterClass(&wndclass) )
26     {
27         MessageBox( NULL, TEXT("无法注册窗口类!"), TEXT("错误"), MB_OK | MB_ICONERROR ) ;
28         return 0 ;
29     }
30 
31     hwnd = CreateWindow( szAppName, TEXT("C语言Windows程序设计 -> 创建文本输入框 -> 演示"), WS_OVERLAPPEDWINDOW,
32         CW_USEDEFAULT, CW_USEDEFAULT,
33         CW_USEDEFAULT, CW_USEDEFAULT,
34         NULL, NULL, hInstance, NULL ) ;
35 
36     ShowWindow( hwnd, iCmdShow ) ;
37     UpdateWindow( hwnd ) ;
38 
39     while( GetMessage(&msg, NULL, 0, 0) )
40     {
41         TranslateMessage( &msg ) ;
42         DispatchMessage( &msg ) ;
43     }
44 
45     return msg.wParam ;
46 }
47 
48 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
49 {
50     static HWND hwndInput ;
51 
52     switch( message )
53     {
54     case WM_CREATE:
55         hwndInput = CreateWindow( TEXT("edit"), NULL,
56             WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | WS_BORDER |
57             ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
58             20, 20, 350, 100,
59             hwnd, (HMENU)1, ((LPCREATESTRUCT) lParam) -> hInstance, NULL ) ;
60         return 0 ;
61 
62     case WM_DESTROY:
63         PostQuitMessage(0) ;
64         return 0 ;
65     }
66 
67     return DefWindowProc( hwnd, message, wParam, lParam ) ;
68 }

   
    如果想创建一个单行输入框, 很简单, 去掉 ES_MULTILINE 属性就行了, 当然, 在单行输入的情况下也就没必要使用 ES_AUTOVSCROLL 属性了。
    
    关于CreateWindow函数部分的一些解释:
    
    1>. 输入框的样式:
        除了 WS_CHILD 样式外, 该子窗口控件还具有以下属性:

复制代码
            WS_VISIBLE    //初始时是可见的
            WS_VSCROLL    //带有一个垂直滚动条
            WS_HSCROLL    //带有一个水平滚动条
            WS_BORDER     //拥有四周的边界线
            
            ES_LEFT            //编辑区的文本为左对齐
            ES_MULTILINE       //多行输入框
            ES_AUTOHSCROLL     //当单行输入的文本总宽度大于输入框的宽度时自动水平滚动
            ES_AUTOVSCROLL     //当输入行数总高度大于输入框的高度时自动垂直滚动
复制代码

        其中, 以 WS_ (Windows Style)为前缀的标识符为窗口样式, 以 ES_ (Edit Style)为前缀的标识符为编辑类样式。


        更多窗口样式以及编辑框样式的介绍可以参见笔者的另一篇补充博文: C语言Windows程序设计 -> 补充 -> Windows窗口样式与编辑框样式
        


    2>. 输入框的坐标与输入框的大小
        在子窗口样式后紧跟的属性就是初始坐标位置, 如上面代码中的 20, 20 就是说明当该输入框控件初始创建时将在相对于客户区坐标(20, 20)的位置。
        在坐标参数的后面, 也就是上面代码中的 350, 100 就是输入框的大小了, 说明该输入框子窗口的宽和高分别为350和100。
        
        如果要创建一个像记事本那样铺满窗口客户区的多行输入框, 我们可以先创建一个无边框(WS_BORDER)的输入框, 初始位置和大小都置为0, 然后在处理 WM_SIZE 消息时使用 GetClientRect 函数获取窗口客户区的大小, 然后调整输入框子窗口大小使其能够完全铺满客户区。像下面这样:

复制代码
    case WM_CREATE:
        hwndInput = CreateWindow( TEXT("edit"), NULL,
            WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL |
            ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
            0, 0, 0, 0,
            hwnd, (HMENU)1, ((LPCREATESTRUCT) lParam) -> hInstance, NULL ) ;
        return 0 ;

    case WM_SIZE:
        GetClientRect(hwnd, &rect) ;
        MoveWindow( hwndInput, 0, 0, rect.right, rect.bottom, TRUE ) ;
        return 0 ;
复制代码

        完整代码(已折叠):

View Code - FullClientEdit-Demo.c
 1 /*C语言Windows程序设计 -> 铺满客户区的输入框 -> 演示*/
 2 
 3 #include <windows.h>
 4 
 5 LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ) ;
 6 
 7 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )
 8 {
 9     static TCHAR szAppName[] = TEXT( "demo" ) ;
10     HWND        hwnd ;
11     MSG            msg ;
12     WNDCLASS    wndclass ;
13 
14     wndclass.lpfnWndProc    = WndProc ;
15     wndclass.style            = CS_HREDRAW | CS_VREDRAW ;
16     wndclass.hInstance        = hInstance ;
17     wndclass.cbClsExtra        = 0 ;
18     wndclass.cbWndExtra        = 0 ;
19     wndclass.hbrBackground    = (HBRUSH) GetStockObject(WHITE_BRUSH) ;
20     wndclass.hCursor        = LoadCursor( NULL, IDC_ARROW ) ;
21     wndclass.hIcon            = LoadIcon( NULL, IDI_APPLICATION ) ;
22     wndclass.lpszClassName    = szAppName ;
23     wndclass.lpszMenuName    = NULL ;
24     
25     if( !RegisterClass(&wndclass) )
26     {
27         MessageBox( NULL, TEXT("无法注册窗口类!"), TEXT("错误"), MB_OK | MB_ICONERROR ) ;
28         return 0 ;
29     }
30 
31     hwnd = CreateWindow( szAppName, TEXT("C语言Windows程序设计 -> 铺满客户区的输入框 -> 演示"), WS_OVERLAPPEDWINDOW,
32         CW_USEDEFAULT, CW_USEDEFAULT,
33         CW_USEDEFAULT, CW_USEDEFAULT,
34         NULL, NULL, hInstance, NULL ) ;
35 
36     ShowWindow( hwnd, iCmdShow ) ;
37     UpdateWindow( hwnd ) ;
38 
39     while( GetMessage(&msg, NULL, 0, 0) )
40     {
41         TranslateMessage( &msg ) ;
42         DispatchMessage( &msg ) ;
43     }
44 
45     return msg.wParam ;
46 }
47 
48 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
49 {
50     static HWND hwndInput ;
51     RECT rect ;
52 
53     switch( message )
54     {
55     case WM_CREATE:
56         hwndInput = CreateWindow( TEXT("edit"), NULL,
57             WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL |
58             ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
59             0, 0, 0, 0,
60             hwnd, (HMENU)1, ((LPCREATESTRUCT) lParam) -> hInstance, NULL ) ;
61         return 0 ;
62 
63     case WM_SIZE:
64         GetClientRect(hwnd, &rect) ;
65         MoveWindow( hwndInput, 0, 0, rect.right, rect.bottom, TRUE ) ;
66         return 0 ;
67 
68     case WM_DESTROY:
69         PostQuitMessage(0) ;
70         return 0 ;
71     }
72 
73     return DefWindowProc( hwnd, message, wParam, lParam ) ;
74 }

        运行效果:

    


    3>. ((LPCREATESTRUCT) lParam) -> hInstance
        在这个参数中, 我们需要的是WinMain函数中的 HINSTANCE hInstance 这个实例句柄, 在 WM_CREATE 消息里的 lParam 实际上是指向 CREATESTRUCT 结构类型的指针, hInstance 则是这个结构的一个成员。因此我们先将 lParam 转换成 LPCREATESTRUCT 结构, 再从中取得 hInstance 成员。
        
        除了上面的方法获取 hInstance 外, 还可以使用 GetWindowLong 函数来获取, 该函数能够获得有关指定窗口的信息, 函数的原型:
            LONG GetWindowLong(HWND hWnd, int nlndex) ;
        第二个参数nlndex即为要获取的信息, 例如:

            GWL_STYLE          //获得窗口风格
            GWL_WNDPROC        //获得窗口过程的地址
            GWL_HINSTANCE      //获得应用实例句柄
            GWL_HWNDPARENT     //如果父窗口存在, 获得父窗口句柄
            GWL_ID            //获得窗口标识ID

        等等。
        当调用成功时, 返回的即为所要获取的32位值, 失败时返回值为0。
        
        这里我们需要的是 hInstance, 所以就这样写:

(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE)        //将所需的32位值转换成HINSTANCE型, 否则使用时会产生警告

 

 


      
三、编辑控件的通知消息
    当用户在编辑控件上进行操作时, 编辑控件会向父窗口发送 WM_COMMAND 消息, 其中的 wParam 值与 lParam 值的含义与按钮控件中的含义一致:
        LOWORD(wParam)            //子窗口ID
        HIWORD(wParam)            //通知码
        lParam                    //子窗口句柄
        
    文本编辑框所能产生的不同通知码以及其含义如下:

复制代码
        EN_ALIGN_LTR_EC            //文本排列顺序更变为从左到右
        EN_ALIGN_RTL_EC            //文本排列顺序更变为从右到左
        EN_CHANGE                  //输入框中的内容将发生改变
        EN_ERRSPACE                //内存不足
        EN_HSCROLL                 //用户点击水平滚动条
        EN_KILLFOCUS               //输入框失去焦点
        EN_MAXTEXT                 //输入框没有足够地方输入了
        EN_SETFOCUS                //输入框获取焦点
        EN_UPDATE                  //输入框中的内容已变化
        EN_VSCROLL                 //用户点击纵向滚动条
复制代码


    例如, 当我们建立一个多行, 但不能水平/垂直滚动的输入框, 处理内容改变和输入框已满的消息:

复制代码
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case 1:
                switch(HIWORD(wParam))
                {
                case EN_UPDATE:
                    MessageBox(NULL, TEXT("输入内容已改变!"), TEXT("输入"), MB_OK) ;
                    break ;
                case EN_MAXTEXT:
                    MessageBox(NULL, TEXT("输入框已满!"), TEXT("输入"), MB_OK) ;
                    break ;
                default:
                    break ;
                }
                return 0 ;
        /*case 其他子窗口控件的ID*/
        }
        return 0 ;
复制代码

 


        
       
四、使用文本输入框
    一些常用的操作:
    
    1>. 获取输入内容 GetWindowText
        该函数将指定窗口的标题文本拷贝到一个缓存区内。如果指定的窗口是一个控件, 则拷贝控件的文本。因此可以用来获取输入框的文字, 函数原型:

            int GetWindowText(
                HWND hWnd,            //带文本的窗口或控件的句柄
                LPTSTR lpString,    //指向接收文本的缓冲区的指针
                int nMaxCount        //允许保存在缓冲区内字符的最大个数, 超过部分被截断
            ) ;

        调用成功时函数返回已拷贝的字符串的字符个数
    


    2>. 获取输入框中文本的长度 GetWindowTextLength
        该函数用来获得指定编辑控件中的字符数, 函数原型: int GetWindowTextLength( HWND hWnd );
        需要注意的是, 该函数获取到的文本长度不一定是准确的, 在一定的条件下, 函数GetWindowTextLength的返回值可能比实际的文本实际长度要大。这是由于ANSI和Unlcode的混和使用以及系统允许DBCS字符在文本内存在的原因。
        
        如果要获取准确的文本长度可以利用 GetWindowText 函数。


    3>. 设置输入框中的文字内容 SetWindowText
        在窗口有标题栏时, 该函数用于改变指定窗口的标题栏的文本内容。如果指定的窗口句柄为一个控件, 则改变控件的文本内容。
        函数原型: BOOL SetWindowText(HWND hwnd,LPCTSTR lpString) ;
        
        参数说明:
            hWnd :要改变文本内容的窗口或控件的句柄。
          lpString : 指向一个以空结束的字符串指针, 该字符串将作为窗口或控件的新文本。
        当调用成功时返回非0, 失败时返回0。
        
    4>. WINDOWSX.H 头文件中的一些常用操作
        下面这些宏定义在 WINDOWSX.H 头文件中, 所以使用时需要 #include <windowsx.h>
        
        ①. 获取文本行数 Edit_GetLineCount
            原型: int Edit_GetLineCount( HWND hwndCtl );
            
        ②. 获取某一行的文本内容 Edit_GetLine
            原型:

         int Edit_GetLine(
                    HWND hwndCtl,        //编辑框句柄
                    int line,            //从0开始的索引行
                    LPTSTR lpch,        //指向缓冲区的指针
                    int cchMax            //最大复制的字符数量
                );

            其返回值为实际复制的字符数量, 适用于多行输入框。
            
        ③. 限制输入框最大输入数量 Edit_LimitText
            原型:

            void Edit_LimitText(
                HWND hwndCtl,        //编辑框句柄
                int cchMax            //所允许输入的字符长度
            );

            当第二个参数值为0时, 字符长度设置为64000。 没有返回值。
            
        ④. 禁用输入框 Edit_Enable
            原型:

            BOOL Edit_Enable(
                HWND hwndCtl,        //编辑框句柄
                BOOL fEnable        //TRUE启用, FALSE禁用
            );

    更多关于编辑框控制函数以及宏的使用可以查阅MSDN Library。
    


    

五、向编辑框传递消息
    与普通窗口一样, 向编辑框控件发送消息可以使用 SendMessage 函数, 由于可发送的消息太多, 这里仅介绍几个较为常用的, 其他完整的消息介绍可查阅 MSDN Library。
    消息:

        WM_CUT          //剪切选中文本
        WM_COPY         //复制选中文本
        WM_CLEAR        //删除选中文本
        WM_PASTE        //将剪贴板上的文字粘贴到当前输入位置

    选中的文本是指用户用鼠标或者Shift键加方向键选择的文本, 这部分文本会以高亮显示来与其他未选中的部分区别开来。
    例如我们要将当前剪切板上的内容粘贴到编辑框只需要:

        SendMessage(hwndInput, WM_PASTE, 0, 0) ;        

    我们也可以向编辑框发送消息来自己选中文本:

        SendMessage(hwndInput, EM_SETSEL, iStart, iEnd) ;

    还可以通过发送消息 EM_REPLACESEL 用其他文本来替代选中的文本:

        SendMessage(hwndInput, EM_REPLACESEL, 0, (LPARAM)szString) ;

   
    在上面"四、使用文本输入框"部分介绍了如何通过宏定义统计输入的行数, 通过发送 EM_GETLINECOUNT 消息也可以达到相同的目的:

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

 

 



六、实例: 一个简易的文本编辑器
    功能要求:
        这个简易的文本编辑器包含如下功能:
            1>. 能够保存编辑的文字 ;
            2>. 自动统计已输入的字符的个数和行数 ;
            3>. 有快速清空编辑区功能 ;
            
    功能分析:
        1>. 由于还没有学习打开文件和保存文件的标准对话框, 所以目前在保存文件时我们需要用户自己手动输入保存或读取的路径 ;
        2>. 统计输入的字符个数与行数可以通过上文中讲的宏或者向编辑框发送消息获得 ;
        3>. 快速清空编辑区可以用一个清空按钮来代替。
    
    细节处理:
        1>. 只有当编辑区的内容不为空时才能保存 ;
        2>. 当用户没有输入保存路径时点击"保存"按钮提示用户输入路径。
    
    其完整的实现代码如下(已折叠):

View Code - SimpleEdit-Demo.c
  1 /*C语言Windows程序设计 -> 简易文本编辑器 -> 演示*/
  2 
  3 #include <windows.h>
  4 #include <stdio.h>
  5 
  6 /*各控件所使用的ID*/
  7 #define ID_EDITBOX    1        //文本编辑框控件
  8 #define ID_TXTPATH    2        //路径编辑框控件
  9 #define ID_SAVEBTN    3        //保存文件按钮
 10 #define ID_CLSBTN    4        //清空编辑区按钮
 11 #define ID_GROUP    5        //组合框
 12 
 13 LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ) ;
 14 int CreateChildWindow(HWND, HWND *, LPARAM ) ;                //创建将使用到的子窗口控件
 15 int SavaInputContent( TCHAR *, TCHAR * ) ;                    //保存输入的文字到文件
 16 
 17 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )
 18 {
 19     static TCHAR szAppName[] = TEXT( "demo" ) ;
 20     HWND        hwnd ;
 21     MSG            msg ;
 22     WNDCLASS    wndclass ;
 23 
 24     wndclass.lpfnWndProc    = WndProc ;
 25     wndclass.style            = CS_HREDRAW | CS_VREDRAW ;
 26     wndclass.hInstance        = hInstance ;
 27     wndclass.cbClsExtra        = 0 ;
 28     wndclass.cbWndExtra        = 0 ;
 29     wndclass.hbrBackground    = CreateSolidBrush(RGB(236, 233, 216)) ;
 30     wndclass.hCursor        = LoadCursor( NULL, IDC_ARROW ) ;
 31     wndclass.hIcon            = LoadIcon( NULL, IDI_APPLICATION ) ;
 32     wndclass.lpszClassName    = szAppName ;
 33     wndclass.lpszMenuName    = NULL ;
 34     
 35     if( !RegisterClass(&wndclass) )
 36     {
 37         MessageBox( NULL, TEXT("无法注册窗口类!"), TEXT("错误"), MB_OK | MB_ICONERROR ) ;
 38         return 0 ;
 39     }
 40 
 41     hwnd = CreateWindow( szAppName, TEXT("C语言Windows程序设计 -> 简易文本编辑器 -> 演示"), WS_OVERLAPPEDWINDOW,
 42         CW_USEDEFAULT, CW_USEDEFAULT,
 43         CW_USEDEFAULT, CW_USEDEFAULT,
 44         NULL, NULL, hInstance, NULL ) ;
 45 
 46     ShowWindow( hwnd, iCmdShow ) ;
 47     UpdateWindow( hwnd ) ;
 48 
 49     while( GetMessage(&msg, NULL, 0, 0) )
 50     {
 51         TranslateMessage( &msg ) ;
 52         DispatchMessage( &msg ) ;
 53     }
 54 
 55     return msg.wParam ;
 56 }
 57 
 58 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
 59 {
 60     static        HWND hwndChild[5] ;
 61     HDC            hdc ;
 62     PAINTSTRUCT ps ;
 63 
 64     RECT    rect ;
 65     static    TCHAR *szBuffer ;        //缓冲区
 66     static    TCHAR szPath[256] ;        //文本路径
 67     static  TCHAR szLineNum[32] ;
 68     static    TCHAR szCharNum[32] ;
 69     static int        iLength ;
 70     int iLineCount, iCharCount ;
 71 
 72     switch( message )
 73     {
 74     case WM_CREATE:
 75         CreateChildWindow( hwnd, hwndChild, lParam ) ;
 76         return 0 ;
 77 
 78     case WM_SIZE:
 79         GetClientRect(hwnd, &rect) ;
 80         MoveWindow( hwndChild[ID_EDITBOX], 0, 0, rect.right, rect.bottom-50, TRUE ) ;        //调整文本编辑区
 81         MoveWindow( hwndChild[ID_TXTPATH], 60,  rect.bottom-31, 200, 20, TRUE ) ;            //调整文本路径输入框
 82         MoveWindow( hwndChild[ID_SAVEBTN], 280, rect.bottom-35, 50,  25, TRUE ) ;            //调整保存按钮
 83         MoveWindow( hwndChild[ID_CLSBTN ], 400, rect.bottom-35, 50,  25, TRUE ) ;            //调整清空按钮
 84         MoveWindow( hwndChild[ID_GROUP  ], 10,  rect.bottom-50, 330, 48, TRUE ) ;            //调整组合框
 85         return 0 ;
 86 
 87     case WM_PAINT:
 88         GetClientRect(hwnd, &rect) ;
 89         hdc = BeginPaint( hwnd, &ps ) ;
 90         TextOut( hdc, 20, rect.bottom-30, TEXT("路径:"), lstrlen(TEXT("路径:")) ) ;
 91         TextOut( hdc, 500, rect.bottom-30, szLineNum, lstrlen(szLineNum) ) ;
 92         EndPaint( hwnd, &ps ) ;
 93         return 0 ;
 94 
 95     case WM_COMMAND:
 96         switch(LOWORD(wParam))
 97         {
 98         case ID_EDITBOX:
 99             switch(HIWORD(wParam))
100             {
101             case EN_UPDATE:
102                 iLineCount = SendMessage( hwndChild[ID_EDITBOX], EM_GETLINECOUNT, 0, 0 ) ;
103                 iCharCount = GetWindowTextLength( hwndChild[ID_EDITBOX] ) ;
104                 wsprintf(szLineNum, "行数: %i    字符数量: %i", iLineCount, iCharCount) ;
105                 InvalidateRect(hwnd, NULL, FALSE) ;
106                 break ;
107             default:
108                 break ;
109             }
110             return 0 ;
111 
112         case ID_SAVEBTN:
113             iLength = GetWindowTextLength(hwndChild[ID_EDITBOX]) ;
114             if( iLength != 0)
115                 szBuffer = malloc(iLength*2) ;
116             else
117                 return -1 ;
118             GetWindowText( hwndChild[ID_EDITBOX], szBuffer, GetWindowTextLength(hwndChild[ID_EDITBOX]) + 1 ) ;
119             if(GetWindowText( hwndChild[ID_TXTPATH], szPath, 256 ) < 1)
120             {
121                 MessageBox(NULL, TEXT("路径不能为空"), TEXT("提示"), MB_OK | MB_ICONINFORMATION) ;
122                 return -1 ;
123             }
124             SavaInputContent( szPath, szBuffer ) ;
125             return 0 ;
126 
127         case ID_CLSBTN:
128             SetWindowText( hwndChild[ID_EDITBOX], TEXT("") ) ;
129             return 0 ;
130 
131         default:
132             break ;
133         }
134         return 0 ;
135 
136     case WM_DESTROY:
137         PostQuitMessage(0) ;
138         return 0 ;
139     }
140 
141     return DefWindowProc( hwnd, message, wParam, lParam ) ;
142 }
143 
144 int CreateChildWindow(HWND hwnd, HWND *hwndChild, LPARAM lParam)
145 {
146     HINSTANCE hInst = ((LPCREATESTRUCT) lParam) -> hInstance ;
147 
148     //创建编辑区
149     hwndChild[ID_EDITBOX] = CreateWindow( TEXT("edit"), NULL,
150         WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL |
151         ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
152         0, 0, 0, 0,
153         hwnd, (HMENU)ID_EDITBOX, hInst, NULL ) ;
154 
155     //路径输入框
156     hwndChild[ID_TXTPATH] = CreateWindow( TEXT("edit"), NULL,
157         WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL,
158         0, 0, 0, 0,
159         hwnd, (HMENU)ID_TXTPATH, hInst, NULL ) ;
160 
161     //保存按钮
162     hwndChild[ID_SAVEBTN] = CreateWindow( TEXT("button"), TEXT("保存"),
163         WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 0, 0, 0, 0,
164         hwnd, (HMENU)ID_SAVEBTN, hInst, NULL) ;
165 
166     //清空按钮
167     hwndChild[ID_CLSBTN] = CreateWindow( TEXT("button"), TEXT("清空"),
168         WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 0, 0, 0, 0,
169         hwnd, (HMENU)ID_CLSBTN, hInst, NULL) ;
170     
171     //组合框
172     hwndChild[ID_GROUP] = CreateWindow( TEXT("button"), NULL,
173         WS_CHILD | WS_VISIBLE | BS_GROUPBOX, 0, 0, 0, 0,
174         hwnd, (HMENU)ID_GROUP, hInst, NULL) ;
175 
176     return 0 ;
177 }
178 
179 int SavaInputContent( TCHAR *path, TCHAR *content )
180 {
181     FILE *fSvae ;
182 
183     fSvae = fopen( path, "w" ) ;
184     if(fSvae == NULL)
185     {
186         MessageBox(NULL, TEXT("文件创建失败!"), TEXT("提示"), MB_OK | MB_ICONINFORMATION) ;
187         return -1 ;
188     }
189     fputs( content, fSvae ) ;
190     fclose(fSvae) ;
191     MessageBox(NULL, TEXT("保存成功!"), TEXT("成功"), MB_OK | MB_ICONINFORMATION) ;
192 
193     return 0 ;
194 


    运行效果:

    

本篇随笔中所有的DEMO代码下载: https://files.cnblogs.com/mr-wid/Learn_WinC_day_14.rar




再长的路, 一步步也能走完, 再短的路, 不迈开双脚也无法到达。2013, 期待你的到来!

 


--------------------