《Windows API每日一练》8.5 listbox控件

列表框是将一批文本字符串显示在一个具有滚动功能的方框中的控件。通过发送消息到列表框的窗口过程,程序可以添加或删除列表中的字符串。当列表框中的一个项目被选中时,列表框控件便发送 WM_COMMAND消息到其父窗口。然后父窗口确定哪个项目被选中。

本节必须掌握的知识点:

        列表框类控件

        第54练:列表框控件

        第55练:列表框控件—head程序

8.5.1 列表框类控件

列表框控件分类

列表框可以是单选的或多选的。后者允许用户从列表框中选择一个以上的项目。当一个列表框获得输入焦点时,它会在列表框的一个项目周围显示虚线框。这种光标并不表示列表框中的选中项。被选中的项目通过高亮显示来表示。

●在单选列表框中,用户可以按动空格键选择光标所在的项目。方向键可以同时移动光 标和当前的选择,并可以滚动列表框中的内容。上下翻页键也可通过移动光标来滚动列表框,但不会移动选择的项目。按下一个字母键可移动光标和当前选择到以那个字母开头的第一项(或下一项)。通过在某一项上单击或双击鼠标也可以选中该项。

●在多选列表框中,空格键用于切换光标所在项目的选择状态。(如果该项目已经被选定, 它的选定状态会被取消。)方向键取消所有以前选定的项目,并移动光标和选中项,就像在单选列表框中一样。然而,Ctrl键加方向键可以移动光标,但不移动选中项。Shift键加方向键可以扩展选中项。

单击或双击多选列表框中的一个项目,会取消所有先前选定的项目,只选择被单击的项目。然而,在单击一个项目的同时按下Shift键会切换该项目的选择状态而不改变任何其他项目的选择状态。

列表框控件的重要信息和功能

●创建列表框控件:可以使用 CreateWindowEx 或 CreateWindow 函数来创建列表框控件。需要指定控件类名为 "LISTBOX",并设置相应的样式和属性。

●添加项:使用 LB_ADDSTRING 消息或 ListBox_AddString 函数向列表框中添加文本项。每个项都具有唯一的索引,可以使用该索引进行引用和操作。

●删除项:使用 LB_DELETESTRING 消息或 ListBox_DeleteString 函数从列表框中删除指定索引的项。

●获取选中项:使用 LB_GETCURSEL 消息或 ListBox_GetCurSel 函数获取当前选中项的索引。可以进一步使用 LB_GETTEXT 消息或 ListBox_GetText 函数获取选中项的文本内容。

●选择项:使用 LB_SETCURSEL 消息或 ListBox_SetCurSel 函数设置列表框中指定索引的项为选中状态。

●多选功能:通过设置列表框控件的样式为 LBS_MULTIPLESEL,可以启用多选功能。用户可以按住 Ctrl 键或 Shift 键进行多项选择。

●滚动条:当列表框中的项超过可见区域时,会自动出现垂直滚动条,以方便导航。

●通知消息:列表框控件可以发送一系列的通知消息,用于响应用户的操作或状态变化。例如,LBN_SELCHANGE 消息在选中项发生变化时发送。

●自定义绘制:可以通过处理 WM_DRAWITEM 消息来自定义绘制列表框中的项,以改变其外观和样式。

●其他操作:还有许多其他的列表框操作和功能,如获取项的数量、清空列表框、滚动列表框等。

●键盘操作

键盘操作

单选列表框

多选列表框

空格键

选择光标所在项

切换选中状态

方向键

移动光标和当前的选择

取消以前所选,并移动光标和选中项

翻页键

移动光标,但不移动选择项

字母键

移动和选择以该字母开头的第一项

Ctrl+方向

移动光标,但不移动选中项

Shift+方向

扩展选中项

列表框的样式

列表框控件(List Box Control)提供了一些样式选项,可以用于自定义列表框的外观和行为。以下是一些常用的列表框样式:

●LBS_STANDARD:标准列表框样式,默认样式,显示垂直滚动条并支持单选。

●LBS_SORT:排序样式,列表框中的项按字母顺序排序。

●LBS_MULTIPLESEL:多选样式,允许用户选择列表框中的多个项。用户可以按住 Ctrl 键或 Shift 键进行多项选择。

●LBS_EXTENDEDSEL:扩展多选样式,类似于 LBS_MULTIPLESEL,但支持连续选择。用户可以按住鼠标左键拖动以选择多个连续项。

●LBS_OWNERDRAWFIXED:固定尺寸的自绘样式,允许自定义绘制列表框中的项。

●LBS_NOINTEGRALHEIGHT:禁用自动调整高度样式,列表框的高度将根据项的数量进行调整。

●LBS_DISABLENOSCROLL:禁用无项时的滚动条样式,即使列表框中没有项,也显示垂直滚动条。

●LBS_NODATA:无数据样式,仅用于通知列表框控件不包含任何数据。

●这些样式可以通过在创建列表框控件时使用 CreateWindowEx 或 CreateWindow 函数的 dwStyle 参数来设置。例如:

HWND hListBox = CreateWindowEx(

    0,                          // 扩展窗口样式

    L"LISTBOX",                   // 窗口类名

    NULL,                       // 窗口标题

    WS_VISIBLE | WS_CHILD | LBS_STANDARD,  // 窗口样式

    x, y, width, height,                // 窗口位置和尺寸

    hWndParent,                 // 父窗口句柄

    (HMENU)IDC_LISTBOX,        // 控件标识符

    hInstance,                     // 应用程序实例句柄

    NULL                        // 创建参数

);

在上述示例中,我们创建了一个具有标准样式的列表框控件,并设置了一些常用的样式,如可见、子窗口。可以根据需求自由组合和设置其他样式。

●除了创建时设置样式,还可以使用 SetWindowLongPtr 或 SetWindowLongPtr 函数来动态修改列表框控件的样式。例如:

DWORD dwStyle = GetWindowLongPtr(hListBox, GWL_STYLE);

dwStyle |= LBS_SORT;  // 设置排序样式

SetWindowLongPtr(hListBox, GWL_STYLE, dwStyle);

在上述示例中,我们首先获取列表框控件的当前样式,然后通过按位或运算符将 LBS_SORT 样式添加到样式中,最后使用 SetWindowLongPtr 函数设置新的样式。

这些是一些常见的列表框样式,你可以根据具体的需求选择适合的样式来自定义列表框的外观和行为。

向列表框中添加字符串

要向列表框中添加字符串,你可以使用 LB_ADDSTRING 消息或 ListBox_AddString 函数。下面是一个示例:

●使用 LB_ADDSTRING 消息:

HWND hListBox = GetDlgItem(hWnd, IDC_LISTBOX); // 获取列表框控件句柄

SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)L"Item 1"); // 添加字符串项

SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)L"Item 2"); // 添加字符串项

●使用 ListBox_AddString 函数:

HWND hListBox = GetDlgItem(hWnd, IDC_LISTBOX); // 获取列表框控件句柄

ListBox_AddString(hListBox, L"Item 1"); // 添加字符串项

ListBox_AddString(hListBox, L"Item 2"); // 添加字符串项

在上述示例中,我们首先获取列表框控件的句柄 hListBox,然后使用 LB_ADDSTRING 消息或 ListBox_AddString 函数将字符串项添加到列表框中。每个字符串项都是一个以 null 终止的 Unicode 字符串,使用 LPARAM 类型进行传递。

你可以根据需要多次调用 LB_ADDSTRING 消息或 ListBox_AddString 函数来添加多个字符串项。列表框将按照添加的顺序显示这些项。

请确保在添加字符串之前,列表框已经被创建并且有效。你可以使用 GetDlgItem 函数根据控件标识符获取列表框的句柄。

注意:在使用 LB_ADDSTRING 消息或 ListBox_AddString 函数添加字符串项之前,你需要确保列表框控件已经创建,且在窗口中可见。

项目的选择和提取

要选择列表框中的项目并提取选中的项目,你可以使用 LB_GETCURSEL 消息或 ListBox_GetCurSel 函数来获取当前选中项目的索引。然后,使用 LB_GETTEXT 消息或 ListBox_GetText 函数来获取选中项目的文本内容。

下面是一个示例:

●使用 LB_GETCURSEL 消息和 LB_GETTEXT 消息:

HWND hListBox = GetDlgItem(hWnd, IDC_LISTBOX); // 获取列表框控件句柄

// 获取当前选中项目的索引

int selectedIndex = SendMessage(hListBox, LB_GETCURSEL, 0, 0);

if (selectedIndex != LB_ERR) {

    // 获取选中项目的文本长度

int textLength = SendMessage(hListBox, LB_GETTEXTLEN, selectedIndex, 0);

    if (textLength != LB_ERR) {

        // 分配内存来存储选中项目的文本

        wchar_t* buffer = new wchar_t[textLength + 1];

        // 获取选中项目的文本内容

        SendMessage(hListBox, LB_GETTEXT, selectedIndex, (LPARAM)buffer);

        // 在这里可以使用选中项目的文本内容

        delete[] buffer; // 释放内存

    }

}

●使用 ListBox_GetCurSel 函数和 ListBox_GetText 函数:

HWND hListBox = GetDlgItem(hWnd, IDC_LISTBOX); // 获取列表框控件句柄

// 获取当前选中项目的索引

int selectedIndex = ListBox_GetCurSel(hListBox);

if (selectedIndex != LB_ERR) {

    // 获取选中项目的文本长度

    int textLength = ListBox_GetTextLen(hListBox, selectedIndex);

    if (textLength != LB_ERR) {

        // 分配内存来存储选中项目的文本

        wchar_t* buffer = new wchar_t[textLength + 1];

        // 获取选中项目的文本内容

        ListBox_GetText(hListBox, selectedIndex, buffer);

        // 在这里可以使用选中项目的文本内容

        delete[] buffer; // 释放内存

    }

}

在上述示例中,我们首先获取列表框控件的句柄 hListBox。然后,使用 LB_GETCURSEL 消息或 ListBox_GetCurSel 函数获取当前选中项目的索引。如果索引不是 LB_ERR,表示有项目被选中。

接下来,我们使用 LB_GETTEXTLEN 消息或 ListBox_GetTextLen 函数获取选中项目的文本长度。如果长度不是 LB_ERR,表示获取长度成功。

然后,我们分配足够的内存来存储选中项目的文本,使用 LB_GETTEXT 消息或 ListBox_GetText 函数获取选中项目的文本内容,并将其存储在我们分配的缓冲区中。

在获取到选中项目的文本内容后,你可以在相应的位置使用该文本进行处理。最后,不要忘记释放分配的内存,以避免内存泄漏。

接收来自列表框的消息

要接收来自列表框的消息,你需要在消息处理函数或窗口过程中处理列表框相关的消息。

当用户用鼠标单击一个列表框时,这个列表框将获得输入焦点。父窗口可以通过下面的调用把输入焦点给一个列表框控件:

SetFocus ( hwndList );

当一个列表框具有输入焦点时,光标移动键、字符键和空格键也可用于从列表框中选择项目。

—个列表框控件会发送WM COMMAND信息到其父窗口。相应的wParam和IParam 变量的含义和在按钮控件、编辑控件中是一样的:

LOWORD (wParam)     子窗口 ID

HIWORD (wParam)      通知码

IParam                子窗口句柄

通知码和它们的值如下:

LBN_ERRSPACE           -2    //表明该列表框控件己经用尽了它的空间

LBN_SELCHANGE      1     //表明当前的选择发生了变化

LBN_DBLCLK               2     //代码表明列表框中的某个项目己被鼠标双击

LBN_SELCANCEL         3     //通知应用程序用户已取消列表框中的选择

LBN_SETFOCUS           4     //通知应用程序列表框已收到键盘焦点

LBN_KILLFOCUS          5     //通知应用程序列表框已失去键盘焦点

只有在列表框窗口样式包含了 LBS_NOTIFY时,列表框控件才会向父窗口发送 LBN_SELCHANGE 和 LBN_DBLCLK。

LBN_ERRSPACE代码表明,该列表框控件己经用尽了它的空间。

LBN_SELCHANGE 代码表明当前的选择发生了变化:这些消息可能出现在当用户在列表框中移动高亮显示的选中项时,或是通过空格键切换选择状态时,又或者是用鼠标单击一个项目时。

LBN_DBLCLK代码表明列表框中的某个项目己被鼠标双击。(通知码LBN_SELCHANGE 和LBN_DBLCLK的值表明了鼠标单击的次数。)

根据你的应用程序,你可能想要使用LBN_SELCHANGE或LBN_DBLCLK,或同时使用这两者。程序将收到许多LBN_SELCHANGE消息,但只有当用户用鼠标双击时 LBN_DBLCLK才会出现。如果程序使用了双击,则需要提供一个键盘接口,以提供 LBN_DBLCLK的等效功能。

以下是一些常见的列表框消息及其处理方式:

●WM_COMMAND:列表框的选择变化会触发 WM_COMMAND 消息,其中的 wParam 参数指示了列表框的控件标识符,而 lParam 参数指示了列表框控件的句柄。可以使用 HIWORD(wParam) 来检查列表框事件类型。

case WM_COMMAND:

{

    int controlId = LOWORD(wParam); // 获取控件标识符

    if (controlId == IDC_LISTBOX) // 检查列表框控件标识符

    {

        int eventType = HIWORD(wParam); // 获取事件类型

        if (eventType == LBN_SELCHANGE) // 选择变化事件

        {

                  // 处理列表框选择变化的逻辑

                  // 可以使用 SendMessage 或 ListBox_GetCurSel 等函数

获取选中项的索引或文本

        }

    }

}

break;

●WM_NOTIFY:通过设置列表框的扩展样式为 LBS_NOTIFY,可以接收到更详细的通知消息。当列表框中的事件发生时,将会发送 WM_NOTIFY 消息,其中的 NMHDR 结构中的 code 成员表示事件类型。

case WM_NOTIFY:

{

    NMHDR* nmhdr = (NMHDR*)lParam;

    if (nmhdr->code == LBN_SELCHANGE) // 选择变化事件

    {

        // 处理列表框选择变化的逻辑

        // 可以使用 SendMessage 或 ListBox_GetCurSel 等函数

获取选中项的索引或文本

    }

}

break;

在上述示例中,我们检查了列表框相关消息中的事件类型,例如 LBN_SELCHANGE 表示选择变化事件。在事件处理逻辑中,你可以使用适当的函数(如 SendMessage 或 ListBox_GetCurSel)来获取选中项的索引或文本,并进行相应的处理。

需要注意的是,列表框控件是单列的,适用于显示简单的文本项。如果需要更复杂的布局或自定义内容,可以考虑使用组合框控件(Combo Box Control)或其他更高级的控件。

8.5.2 第54练:列表框控件

/*------------------------------------------------------------------

054  WIN32 API 每日一练

     第54个例子ENVIRON.C:列表框类控件——显示环境变量

     CreateWindow创建列表框控件

     FillListBox函数对环境变量内存块进行解析

     GetEnvironmentStrings 函数

     GetEnvironmentVariable函数

(c) www.bcdaren.com, 2020

----------------------------------------------------------------*/

#include <windows.h>

#define ID_LIST 1

#define ID_TEXT 2

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

 PSTR szCmdLine, int iCmdShow)

{

     static TCHAR szAppName[] = TEXT("Environ");

    (略)

     return msg.wParam;

}

//填充列表框

void FillListBox (HWND hwndList) //对内存块进行解析

{

      int iLength ;

      TCHAR * pVarBlock, * pVarBeg, * pVarEnd, * pVarName ;

      //获取指向环境变量的指针

      pVarBlock = GetEnvironmentStrings () ;

      while (*pVarBlock) //获取成功

      {

           if (*pVarBlock != '=') // 跳过以'='开头的变量名

           { //变量名的开始位置。注意环境变量的格式varName=value

                pVarBeg = pVarBlock ;

                while (*pVarBlock++ != '=') ; //扫描到‘=’号

                pVarEnd = pVarBlock - 1 ;     // pVarCurr指向'='号

                iLength = pVarEnd - pVarBeg ; // 变量名的长度

                // 为变量名分配内存,复制变量名,结尾添加结束符0

                pVarName = calloc (iLength + 1, sizeof (TCHAR)) ;

                CopyMemory (pVarName, pVarBeg, iLength * sizeof (TCHAR)) ;

                pVarName[iLength] = '\0' ; //添加结尾0

                // 将变量名放入列表框并释放内存

                SendMessage (hwndList, LB_ADDSTRING, 0, (LPARAM) pVarName) ;

                free (pVarName) ; //释放内存

           }

// 找字符串的结束符'\0',并把指针移向下一行开始。

           while (*pVarBlock++ != '\0') ;

      }

      //正在使用,不能释放

    //FreeEnvironmentStrings (pVarBlock);//释放环境内存块,*pVarBlock=""空字符串

}

LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM

lParam)

{

      static HWND hwndList, hwndText ;

      int iIndex, iLength, cxChar, cyChar ;

      TCHAR * pVarName, * pVarValue ;

      switch (message)

      {

      case WM_CREATE :

           cxChar = LOWORD (GetDialogBaseUnits ()) ;

           cyChar = HIWORD (GetDialogBaseUnits ()) ;

           // 创建列表框和静态文本窗口

           hwndList = CreateWindow (TEXT ("listbox"), NULL,

              //LBS_STANDARD:(LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER )

                     WS_CHILD | WS_VISIBLE | LBS_STANDARD,

                     cxChar, cyChar * 3,

//最长字符串宽度+垂直滚动条的宽度

                     cxChar * 39 + GetSystemMetrics (SM_CXVSCROLL),

                     cyChar * 15,

                     hwnd, (HMENU) ID_LIST,

                     (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),NULL) ;

           hwndText = CreateWindow (TEXT ("static"), NULL,

                     WS_CHILD | WS_VISIBLE | SS_LEFT,

                     cxChar, cyChar,

                    GetSystemMetrics (SM_CXSCREEN), cyChar,//主显示屏的屏幕宽度

                     hwnd, (HMENU) ID_TEXT,

                     (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),NULL) ;

           FillListBox (hwndList) ; //对列表框控件内存模块进行解析

           return 0 ;

      case WM_SETFOCUS :

           SetFocus (hwndList) ; //捕获焦点

           return 0 ;

      case WM_COMMAND :

           if (LOWORD (wParam) == ID_LIST && HIWORD (wParam) == LBN_SELCHANGE)

           {

                //获取选中项的索引值

                iIndex = SendMessage (hwndList, LB_GETCURSEL, 0, 0) ;

//获取列表框中字符串的长度

               iLength = SendMessage (hwndList, LB_GETTEXTLEN, iIndex, 0) + 1 ;

                pVarName = calloc (iLength, sizeof (TCHAR)) ; //分配内存

//获取环境变量的名称

                SendMessage (hwndList, LB_GETTEXT, iIndex, (LPARAM) pVarName) ;

                //获得变量值的数据长度,含'\0'

                iLength = GetEnvironmentVariable (pVarName, NULL, 0) ;

                pVarValue = calloc (iLength, sizeof (TCHAR)) ;

                //获得变量的值

GetEnvironmentVariable (pVarName, pVarValue, iLength) ;

               

                //将变量的值显示在文本框中 

                SetWindowText (hwndText, pVarValue) ;

                free (pVarName) ;

                free (pVarValue) ;

           }

          return 0 ;

      case WM_DESTROY :

           PostQuitMessage (0) ;

           return 0 ;

      }

      return DefWindowProc (hwnd, message, wParam, lParam) ;

}

/******************************************************************************

创建列表框控件

列表框常用样式:

LBS_STANDARD:(LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER )

LBS_NOTIFY:默认的列表框样式不能发送WM_COMMAND到父窗口,须指定该样式才行

LBS_SORT:排序

LBS_MULTIPLESEL:多选

LBS_NOREDRAW:新增项目默认不会自我更新,可在WM_SETREDRAW中设置

******************************************************************************

对环境变量内存块进行解析

FillListBox函数:解析环境块字符串信息

******************************************************************************

GetEnvironmentStrings 函数:检索当前进程的环境变量

pVarBlock = GetEnvironmentStrings () ; // 获取指向环境块的指针

******************************************************************************

GetEnvironmentVariable函数:从调用过程的环境块中检索指定变量的内容

DWORD GetEnvironmentVariable(

  LPCTSTR lpName,   //环境变量的名称

  LPTSTR  lpBuffer, //指向缓冲区的指针

  DWORD   nSize     //缓冲区大小

);

*/

运行结果:

图8-7 环境变量列表框

 

总结

       实例ENVIRON.C将环境变量添加到一个列表框控件,并读取环境变量的值,显示在一个静态文本框中。

       实例自定义了一个FillListBox函数,对环境变量内存块进行解析。首先调用GetEnvironmentStrings函数获取环境变量指针,然后通过一个while循环结构逐个读取环境变量,并调用SendMessage函数向列表框控件发送LB_ADDSTRING消息,将环境变量添加到列表框。【注意】读取的环境变量名字符串结尾添加0,添加列表框后,及时释放保存环境变量的内存。

       窗口过程在处理WM_CREATE消息时,获取对话框字符的宽和高,然后调用CreateWindow函数分别创建一个列表框控件和一个静态文本控件。最后调用FillListBox函数将环境变量填充列表框控件。

       处理WM_COMMAND消息:首先调用SendMessage函数向列表框控件分别发送LB_GETCURSEL消息和LB_GETTEXTLEN消息,获取列表框选中项的索引和字符串长度。然后再次调用SendMessage函数向列表框控件分别发送LB_GETTEXT消息,获取选中项字符串。

接着两次调用GetEnvironmentVariable函数,第一次调用根据环境变量名获取环境变量的长度。第二次调用获取环境变量的值。最后调用SetWindowText函数将环境变量值显示在静态文本框中。      

8.5.3 第55练:列表框控件—head程序

/*------------------------------------------------------------------

055  WIN32 API 每日一练

     第55个例子HEAD.C:列表框控件--head程序

     窗口子类ListProc

     GetCurrentDirectory 函数

     SetWindowText函数

(c) www.bcdaren.com, 2020

----------------------------------------------------------------*/

#include <windows.h>

#define ID_LIST 1

#define ID_TEXT 2

#define MAXREAD 8192

#define DIRATTR (DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM |  \

               DDL_DIRECTORY | DDL_ARCHIVE | DDL_DRIVES) //文件属性代码

#define DTFLAGS (DT_WORDBREAK | DT_EXPANDTABS | DT_NOCLIP |DT_NOPREFIX) //格式化文本

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

LRESULT CALLBACK ListProc (HWND, UINT, WPARAM, LPARAM) ; //窗口子类--子窗口过程

WNDPROC OldList ; //Windows默认的子窗口过程

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

 PSTR szCmdLine, int iCmdShow)

{

     static TCHAR szAppName[] = TEXT("head");

    (略)

     return msg.wParam;

}

LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM

lParam)

{

      static BOOL bValidFile ;

      static BYTE buffer[MAXREAD] ;

      static HWND hwndList, hwndText ;

      static RECT rect ; //在客户区指定的地方显示文件的内容

      static TCHAR szFile[MAX_PATH + 1] ; //保存选中的文件名

      HANDLE hFile ;

      HDC hdc ;

      int i, cxChar, cyChar ;

      PAINTSTRUCT ps ;

      TCHAR szBuffer[MAX_PATH + 1] ;

      switch (message)

      {

      case WM_CREATE :

           cxChar = LOWORD(GetDialogBaseUnits());//对话框字符宽度

           cyChar = HIWORD(GetDialogBaseUnits());//对话框字符高度

           rect.left = 20 * cxChar;

           rect.top = 3 * cyChar;

          //创建子窗口控件--列表框

           hwndList = CreateWindow(TEXT("listbox"), NULL,

//列表框-按字母顺序对列表框中的字符串进行排序

                WS_CHILDWINDOW | WS_VISIBLE | LBS_STANDARD,

                cxChar, cyChar * 3,

                cxChar * 15 + GetSystemMetrics(SM_CXVSCROLL),//加上滚动条宽度

                cyChar * 15,

                hwnd, (HMENU)ID_LIST,

                (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),

                NULL);

           GetCurrentDirectory(MAX_PATH + 1, szBuffer);//检索当前进程的当前目录

          //创建一个静态文本框控件

           hwndText = CreateWindow(TEXT("static"), szBuffer,

//静态控件:一个简单的矩形,将矩形中的文本左对齐

                WS_CHILDWINDOW | WS_VISIBLE | SS_LEFT,

                cxChar, cyChar, cxChar * MAX_PATH, cyChar,

                hwnd, (HMENU)ID_TEXT,

                (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),

                NULL);

           //窗口子类,创建一个自定义列表框窗口过程

           OldList = (WNDPROC)SetWindowLong(hwndList, GWL_WNDPROC,

                (LPARAM)ListProc);

           //向列表框控件发送目录消息,

//添加具有预定义的DIRATTR文件属性代码的所有目录和文件

           SendMessage(hwndList, LB_DIR, DIRATTR, (LPARAM)TEXT("*.*"));

           return 0;

     case WM_SIZE :

          rect.right = LOWORD(lParam);

          rect.bottom = HIWORD(lParam);

          return 0;

     case WM_SETFOCUS :

          SetFocus(hwndList);

          return 0;

     case WM_COMMAND :

//如果双击列表框子目录

          if (LOWORD (wParam) == ID_LIST && HIWORD (wParam) == LBN_DBLCLK)

          {

               //判断是否选中项目。在单选列表框中,返回值是当前所选项目的从零开

//始的索引。如果没有选择,则返回值为LB_ERR。

//在单选列表框中获取当前所选项目的索引(如果有)

               if (LB_ERR == (i = SendMessage(hwndList, LB_GETCURSEL, 0, 0)))

                    break;

               //获取选中项的文本

//从零开始的字符串的索引

               SendMessage(hwndList, LB_GETTEXT, i, (LPARAM)szBuffer);

               //打开文件,选中项为文件

               if (INVALID_HANDLE_VALUE != (hFile = CreateFile(szBuffer,

                    GENERIC_READ, FILE_SHARE_READ, NULL,

                    OPEN_EXISTING, 0, NULL)))

               {

                    CloseHandle(hFile);//关闭打开的文件句柄

                    bValidFile = TRUE;

                    lstrcpy(szFile, szBuffer);//保存选中项的文件名

                    //将文件及路径显示在文本框中

//检索当前进程的当前目录

                    GetCurrentDirectory(MAX_PATH + 1, szBuffer);

                    if (szBuffer[lstrlen(szBuffer) - 1] != '\\')//找到文件

                         lstrcat(szBuffer, TEXT("\\"));//最未尾加个“\”

//更改指定窗口标题栏的文本

                    SetWindowText(hwndText, lstrcat(szBuffer, szFile));

               }

               else //选中项为目录或驱动器

               {

                    //1、上级目录:[..]

                    //2、子目录如:[SubDir]

                    //3、驱动器符:[-c-]

                     bValidFile = FALSE ;

                    //判断是否目录

                     szBuffer [lstrlen (szBuffer) - 1] = '\0' ; //加个'\0'

                    //如果设置的目录不工作,也许它是

                    //更换驱动器,试试吧。

//SubDir加上当前目录为新路径。失败,说明选中的是驱动器

                     if (!SetCurrentDirectory (szBuffer + 1))

                     {

                          szBuffer[3] = ':';

                          szBuffer[4] = '\0';

//将当前路径设为驱动器符,如c:

                          SetCurrentDirectory(szBuffer + 2);

                     }

                     //获取新目录名并填充列表框

//检索当前进程的当前目录

                     GetCurrentDirectory (MAX_PATH + 1, szBuffer) ;

//更改指定窗口标题栏的文本

                     SetWindowText (hwndText, szBuffer) ;

//发送消息:从列表框中删除所有项目

                     SendMessage (hwndList, LB_RESETCONTENT, 0, 0) ;

                    //发送消息:将名称添加到列表框显示的列表中

                     SendMessage (hwndList, LB_DIR, DIRATTR,

(LPARAM) TEXT ("*.*")) ;

               }

               InvalidateRect (hwnd, NULL, TRUE) ; //重绘窗口

           }

           return 0 ;

      case WM_PAINT :

           if (!bValidFile) //文件打开失败,不做任何事,交给DefWindowProc处理

               break ;

          //打开文件

           if (INVALID_HANDLE_VALUE == (hFile = CreateFile (szFile,  

           GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)))

           {

                bValidFile = FALSE;//打开文件失败

                break;

           }

           ReadFile (hFile, buffer, MAXREAD, &i, NULL) ; //读取文件

           CloseHandle (hFile) ; //关闭文件句柄

          //显示读取到的内容,i为读取文本到buffer中的字节总数

           hdc = BeginPaint (hwnd, &ps) ;

           SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;

           SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT)) ;

           SetBkColor (hdc, GetSysColor (COLOR_BTNFACE)) ;

           // 假设文件是ASCII字符,未考虑UNICODE字符

           DrawText (hdc, buffer, i, &rect, DTFLAGS) ; //显示文本

           EndPaint (hwnd, &ps) ;

           return 0 ;

      case WM_DESTROY :

           PostQuitMessage(0);

           return 0;

      }

      return DefWindowProc (hwnd, message, wParam, lParam) ;

}

 //自定义列表框控件窗口过程

//子窗口类回调函数--接收键盘消息

LRESULT CALLBACK ListProc (HWND hwnd, UINT message,

 WPARAM wParam, LPARAM lParam)

{ //处理按键消息--如果按下回车键

     if (message == WM_KEYDOWN && wParam == VK_RETURN)

//向父窗口发送WM_COMMAND鼠标双击消息

          SendMessage(GetParent(hwnd), WM_COMMAND,

               MAKELONG(ID_LIST, LBN_DBLCLK), (LPARAM)hwnd);

     //调用默认列表框控件窗口过程——增加键盘接口

     return CallWindowProc(OldList, hwnd, message, wParam, lParam);

}

/******************************************************************************

窗口子类ListProc

子类化窗口若要对窗口的实例进行子类化,

请调用SetWindowLong函数并指定该窗口的句柄以对GWL_WNDPROC标志和该子类过程的指针进行子类化。

SetWindowLong返回一个指向原始窗口过程的指针;

使用此指针将消息传递给原始过程。子类窗口过程必须使用CallWindowProc函数来调用原始窗口过程。

******************************************************************************

GetCurrentDirectory 函数:检索当前进程的当前目录

DWORD GetCurrentDirectory(

  DWORD  nBufferLength,//当前目录字符串的缓冲区长度

  LPTSTR lpBuffer   //指向接收当前目录字符串的缓冲区的指针

);

******************************************************************************

SetWindowText函数:更改指定窗口标题栏的文本

BOOL SetWindowTextA(

  HWND   hWnd, //要更改其文本的窗口或控件的句柄

  LPCSTR lpString   //新标题或控件文本

);

*/

       运行结果:

图8-8 head程序

 

总结

实例HEAD.C在列表框中列出了所有文件和子目录。在文件名上双击鼠标,或者当文件名被选择时按下回车键,可以显示这个文件。使用这些方法之一还可以更改子目录。该程序可在HEAD窗口的右侧客户区上显示出文件开头的内容,内容的大小不超过8KB。

实例窗口过程首先处理WM_CREATE消息,获取对话框字符宽和高,然后调用CreateWindow函数分别创建一个列表框控件和一个静态文本控件。静态文本控件用于显示目录信息。调用GetCurrentDirectory检索当前进程的当前目录,并向列表框控件发送LB_DIR消息,添加具有预定义的DIRATTR文件属性代码的所有目录和文件。

此外,为了给列表框控件增加一个键盘接口,创建了一个窗口子类,调用SetWindowLong函数为列表框控件添加一个自定义的窗口过程ListProc。ListProc窗口过程非常简单,当检测到列表框控件内按下回车键,给主窗口发送一个WM_COMMAND消息,模拟鼠标双击事件。

WM_COMMAND消息:如果检测到鼠标双击事件,则调用SendMessage函数获取鼠标选项及选中项文本字符串。如果是文件名,则调用CreateFile函数打开文件,并在静态文本框内显示文件路径。如果是磁盘根目录或驱动器,则更新目录名并重新填充列表框。最后调用InvalidateRect函数重绘主窗口,向主窗口发送一个WM_PAINT消息。

WM_PAINT消息:打开文件,并在主窗口右侧显示文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/372435.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Open3D 计算最近邻点的距离

目录 一、概述 1.1应用 1.2 应用实例 二、代码实现 2.1关键函数 2.2完整代码 2.3程序详解 三、实现效果 一、概述 在Open3D中&#xff0c;可以通过构建KD树&#xff08;K-D Tree&#xff09;来有效地进行最近邻搜索&#xff0c;从而计算点云中每个点的最近邻点距离。 …

Milvus lite start 及存储策略

背景 今天开始写下Milvus&#xff0c;为了方便&#xff0c;我直接使用的是 milvus-lite 版本&#xff0c;default 情况下&#xff0c;你可能不知道他到底将 db 存储到什么位置了。启动 default-server&#xff0c;看下Milvus 的start及存储逻辑 主逻辑 def start(self):sel…

STM32F446RE实现多通道ADC转换功能实现(DMA)

目录 概述 1 软硬件介绍 1.1 软件版本 1.2 ADC引脚介绍 2 STM32Cube配置项目 2.1 配置基本参数 2.2 ADC通道配置 2.3 DMA通道配置 3 项目代码介绍 3.1 自生成代码 3.2 ADC-DMA初始化 3.3 测试函数 3.4 ADC1、ADC2、ADC3轮询采集数据存贮格式 4 测试 源代码下载地…

小米MIX Fold 4折叠屏手机背面渲染图曝光

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 更多资源欢迎关注 7 月 3 日消息&#xff0c;消息源 Evan Blass 今天在 X 平台发布推文&#xff0c;分享了小米 MIX Fold 4 折叠屏手机的高清渲染图&#xff08;图片有加工成分在&#xff0c;最终零售版本可能会存在差异…

70.WEB渗透测试-信息收集- WAF、框架组件识别(10)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;69.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;9&#xff09; 关于waf相应的识…

【C++修行之道】类和对象(四)运算符重载

目录 一、 运算符重载 函数重载和运算符重载有什么关系&#xff1f; 二、.*运算符的作用 三、运算符重载的正常使用 四、重载成成员函数 五、赋值运算符重载 1.赋值运算符重载格式 传值返回和引用返回 有没有办法不生成拷贝&#xff1f; 2. 赋值运算符只能重载成类的…

【Elasticsearch】开源搜索技术的演进与选择:Elasticsearch 与 OpenSearch

开源搜索技术的演进与选择&#xff1a;Elasticsearch 与 OpenSearch 1.历史发展2.OpenSearch 与 Elasticsearch 相同点3.OpenSearch 与 Elasticsearch 不同点3.1 版本大不同3.2 许可证不同3.3 社区不同3.4 功能不同3.5 安全性不同3.6 性能不同3.7 价格不同3.8 两者可相互导入 4…

unity知识点 专项四 一文彻底说清楚(锚点(anchor)、中心点(pivot)、位置(position)之间的关系)

一 概述 想要使UI控件在屏幕中达到正确的显示效果&#xff0c;比如自适应屏幕尺寸、固定边距等等&#xff0c;首先要理清楚几个基本概念和设置&#xff1a;锚点(anchor)、中心点(pivot)、位置(position)、UI缩放模式、父物件的transform设置 二 Anchor、Pivot与Position 2…

Javascript常见数据结构和设计模式

在JavaScript中&#xff0c;常见的数据结构包括两大类&#xff1a;原始数据类型&#xff08;Primitive Types&#xff09;和对象类型&#xff08;Object Types&#xff09;。对象类型又可以进一步细分为多种内置对象、数组、函数等。下面是一些JavaScript中常见的数据结构&…

Vulnhub靶场DC-6练习

目录 0x00 准备0x01 主机信息收集0x02 站点信息收集1. wordpress扫描2. wordlists字典爆破 0x03 漏洞查找与利用1. 漏洞查找2. CVE-2018-15877漏洞利用3. 反弹shell5. nmap提权 0x04 总结 0x00 准备 下载链接&#xff1a;https://download.vulnhub.com/dc/DC-6.zip 介绍&#…

近红外光谱脑功能成像(fNIRS):2.实验设计、指标计算与多重比较

一、实验设计的策略与方法 近红外光谱成像&#xff08;INIRS&#xff09;作为一种非侵入性脑功能成像技术&#xff0c;为研究大脑活动提供了一种高效、生态效度高的方法。然而&#xff0c;为了充分利用INIRS技术并确保实验结果的准确性和可靠性&#xff0c;研究者必须精心设计实…

高阶面试-dubbo的学习

SPI机制 SPI&#xff0c;service provider interface&#xff0c;服务发现机制&#xff0c;其实就是把接口实现类的全限定名配置在文件里面&#xff0c;然后通过加载器ServiceLoader去读取配置加载实现类&#xff0c;比如说数据库驱动&#xff0c;我们把mysql的jar包放到项目的…

【库架一体立体库】与【传统立体库】对比

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 随着冷链物流行业的快速发展&#xff0c;对于冷藏设施的要求也在不断提高。库架一体式智能立体冷藏库以其高效、节能、智能化的特点&#xff0c;正逐渐成为行业发展的新趋势。 分享一…

UML中用例之间的可视化表示

用例除了与参与者有关联关系外&#xff0c;用例之间也存在着一定的关系&#xff0c;如泛化关系、包含关系、扩展关系等。 4.2.1 包含关系 包含关系指的是两个用例之间的关系&#xff0c;其中一个用例&#xff08;称为基本用例&#xff0c;Base Use Case&#xff09;的行为包…

el-tree 获取当前勾选节点的选中状态以及选中值对象 触发check-change多次事件问题原因

1.需求 现在需要一个树状结构的资产树 但是现在需求是 获取当前选中的值的状态是选中还是取消选中 然后再用当前选中 or 取消选中的值 进行 选中 or 取消选中的操作 一开始使用的是 check-change 方法 接收参数如图 但是我勾选父节点 或者 子节点后 他会打印一堆数据 是因…

理解JS与多线程

理解JS与多线程 什么是四核四线程&#xff1f; 一个CPU有几个核它就可以跑多少个线程&#xff0c;四核四线程就说明这个CPU同一时间最多能够运行四个线程&#xff0c;四核八线程是使用了超线程技术&#xff0c;使得单个核像有两个核一样&#xff0c;速度比四核四线程有多提升。…

Vivado FFT IP核使用

1. 今日摸鱼任务 学习Vivado FFT IP核的使用 Vivado_FFT IP核 使用详解_vivado fft ip核-CSDN博客 这篇写的很详细啦 简单做一点笔记进行记录 2. FFT IP核 xfft_0 ff (.aclk(aclk), // input wire aclk.aresetn(aresetn)…

C++编译链接原理

从底层剖析程序从编译到运行的整个过程 三个阶段 一、编译阶段二、链接阶段三、运行阶段 为了方便解释&#xff0c;给出两端示例代码&#xff0c;下面围绕代码进行实验&#xff1a; //sum.cpp int gdata 10; int sum(int a,int b) {return ab; }//main.cpp extern int gdata…

Java基础---复习01

main方法 一个程序有且只有一个main方法&#xff0c;main方法是java程序的唯一入口。 修饰符 修饰类修饰方法修饰域public都可以访问都可以访问private私有类只能本类只能本类protected子类可以继承、访问&#xff0c;同包下的类也可以访问子类可以继承、访问&#xff0c;同…

[AI 大模型] Google Gemini

文章目录 [AI 大模型] Gemini简介模型架构发展新技术和优势示例 [AI 大模型] Gemini 简介 Google Gemini 是 Google 最新推出的多模态 AI 大模型&#xff0c;旨在提升 AI 在各个领域的应用能力。Gemini 能够处理文本、图像、音频、视频和代码等多种数据类型&#xff0c;展现出…