当前位置: 首页 > news >正文

《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消息:打开文件,并在主窗口右侧显示文件。

相关文章:

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

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

使用Node.js 框架( Express.js)来创建一个简单的 API 端点

文章目录 使用Node.js 框架&#xff08; Express.js&#xff09;来创建一个简单的 API 端点什么是express安装修改代码 express 自动刷新 使用Node.js 框架&#xff08; Express.js&#xff09;来创建一个简单的 API 端点 什么是express Express 是一个保持最小规模的灵活的 …...

企业服务行业CRM解决方案

企业服务行业CRM解决方案 强大的功能满足企业服务行业对客户管理、业务管理等方面的真实需求&#xff1b; 细分企业服务行业的不同领域&#xff0c;为不同业务场景提供个性化配置&#xff1b; 打通钉钉、企业微信等平台&#xff0c;降低企业使用CRM门槛&#xff0c;提供高性…...

服务器怎么进PE系统?

服务器进PE是指将服务器的操作系统切换到预安装环境&#xff08;Pre-Installation Environment&#xff09;的状态。在PE环境下&#xff0c;可以进行一些系统管理和故障排除的操作。在进入PE&#xff08;Preinstall Environment&#xff09;之前&#xff0c;首先需要确保你的服…...

Linux内核编译与调试menuos-linux-3.18.6-在ubuntu20.04环境

1 具体操作 下载 linux-3.18.6内核 wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.18.6.tar.xz解压进入linux-3.18.6文件夹 tar -xvf linux-3.18.6.tar.xz cd linux-3.18.6/编译 #make x86_64_defconfig # 为x86_64生成配置 #make alldefconfig make i3…...

java-mysql 三层架构

在 Java 应用程序中&#xff0c;三层架构&#xff08;Three-Tier Architecture&#xff09;是一种常见的设计模式&#xff0c;用于分离应用程序的表示层、业务逻辑层和数据访问层。这种架构有助于提高代码的可维护性、可扩展性和可重用性。以下是详细解释 Java 应用程序中使用 …...

打工人如何应对AI对工作岗位的风险

面对AI对工作岗位的潜在取代&#xff0c;我们可以从多个层面制定应对策略&#xff0c;以确保劳动力市场的平稳过渡和社会的可持续发展。以下是一些具体的应对策略&#xff1a; 一、加强教育与培训 提升STEM教育&#xff1a;增加科学、技术、工程和数学&#xff08;STEM&#…...

C++:从C语言过渡到C++

在这篇博客中&#xff0c;我将会介绍从C语言过渡到C的一些基础知识。 目录 C起源 C的关键字 输出hello&#xff0c;world ​编辑 命名空间 1.什么是命名空间 2.namespace的作用 3.域作用限定符 4.命名空间的使用 IO流 缺省参数 函数重载 引用 1.引用的定义 2.引…...

在安卓中使用FFmpeg录制摄像头的视频并保存到本地MP4文件

在移动应用开发中&#xff0c;有时需要利用设备的摄像头录制视频&#xff0c;并且希望在录制过程中能够精确控制视频的质量、格式和时长。FFmpeg作为一个强大的多媒体处理工具&#xff0c;提供了广泛的功能和选项&#xff0c;能够帮助我们实现这样的需求。 添加依赖 在安卓平台…...

Vue从零到实战第一天

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…...

BUUCTF - Basic

文章目录 1. Linux Labs 【SSH连接漏洞】2. BUU LFI COURSE【文件包含漏洞】3. BUU BRUTE【暴力破解用户名密码】4. BUU SQL COURSE【SQL注入-当前数据库】5. Upload-Labs-Linux 1【文件上传漏洞】7. Buu Upload Course 1【文件上传包含漏洞】8. sqli-labs 1【SQL注入-服务器上…...

如何理解Node.js?NPM?Yarn?Vue?React?

一、背景 对后端技术栈更熟悉&#xff0c;对前端技术栈不了解&#xff0c;希望通过前后端的技术栈进行对比&#xff0c;可以更直观地了解前端技术栈。 二、Node.js Node.js 是一个基于 Chrome V8 JavaScript 引擎的 JavaScript 运行环境。它使得 JavaScript 可以在服务器端运…...

苹果入局,AI手机或将实现“真智能”?

【潮汐商业评论/原创】 “AI应用智能手机不就是现在的AI手机。” 当被问到现阶段对AI手机的看法时&#xff0c;John如是说。“术业有专攻&#xff0c;那么多APP在做AI功能&#xff0c;下载用就是了&#xff0c;也用不着现在换个AI手机啊。” 对于AI手机&#xff0c;或许大多…...

AI网络爬虫019:搜狗图片的时间戳反爬虫应对策略

文章目录 一、介绍二、输入内容三、输出内容一、介绍 如何批量爬取下载搜狗图片搜索结果页面的图片?以孙允珠这个关键词的搜索结果为例: https://pic.sogou.com/pics? 翻页规律如下: https://pic.sogou.com/napi/pc/searchList?mode=2&start=384&xml_len=48&am…...

Windows 网络重置及重置网络可能出现的问题( WIFI 没有了 / WLAN 图标消失)

当 Windows 网络出现本机故障时&#xff0c;一般从以下两个方面解决&#xff1a;网络栈和使用网络栈的组件或程序。 1、Winsock 组件问题 以管理身份运行 cmd&#xff0c;输入以下命令 netsh winsock reset重置 Winsock 组件以修复网络连接问题。 Winsock 是 Windows 操作系…...

100 个网络基础知识普及,看完成半个网络高手!

1&#xff09;什么是链接&#xff1f; 链接是指两个设备之间的连接。它包括用于一个设备能够与另一个设备通信的电缆类型和协议。 2&#xff09;OSI 参考模型的层次是什么&#xff1f; 有 7 个 OSI 层&#xff1a;物理层&#xff0c;数据链路层&#xff0c;网络层&#xff0…...

高盛开源的量化金融 Python 库

GS Quant GS Quant是用于量化金融的Python工具包&#xff0c;建立在世界上最强大的风险转移平台之一之上。旨在加速量化交易策略和风险管理解决方案的开发&#xff0c;凭借25年的全球市场经验精心打造。 它由高盛的定量开发人员&#xff08;定量&#xff09;创建和维护&#…...

【Linux】docker和docker-compose 区别是什么

Docker 和 Docker Compose 是用于容器化应用的工具,它们在开发、部署和管理容器化应用程序时有不同的作用。以下是对它们的简要介绍和功能描述: Docker 定义: Docker 是一个开源的平台,允许开发者自动化地部署、扩展和管理应用程序容器。容器是一种轻量级、可移植、独立的软…...

Qt图片缩放显示

在Qt中&#xff0c;如果你想显示图片的像素或者对图片进行缩放显示&#xff0c;可以使用 QImage 类来处理图片数据&#xff0c;并使用 QLabel 或自定义的 QWidget 来显示图片&#xff0c;但是很难通过鼠标进行缩放显示 QGraphicsView可以实现此功能 在Qt中&#xff0c;QGraphi…...

47、lvs之DR

1、DR模式&#xff1a; 1.1、lvs三种模式&#xff1a; nat 地址转换 DR 直接路由模式 tun 隧道模式 1.2、DR模式的特点&#xff1a; 调度器在整个lvs集群当中是最重要的&#xff0c;在nat模式下&#xff0c;即负载接收请求&#xff0c;同时根据负载均衡的算法转发流量&…...

分布式技术栈、微服务架构 区分

1.分布式技术栈 这些技术栈都是为了更好的开发分布式架构的项目。 &#xff08;大营销平台的系统框架如下图&#xff0c;扩展的分布式技术栈&#xff09; &#xff08;1&#xff09;Dubbo——分布式技术栈 DubboNacos注册中心是应用可以分布式部署&#xff0c;并且提供RPC接…...

【JavaEE精炼宝库】文件操作(2)——文件内容读写 | IO流

文章目录 一、输入流1.1 InputStream 概述&#xff1a;1.2 read 方法详解&#xff1a;1.3 close 方法&#xff1a;1.4 利用 Scanner 进行读操作&#xff1a;1.5 Reader&#xff1a; 二、输出流2.1 OutputStream 概述&#xff1a;2.2 write 方法详解&#xff1a;2.3 利用 PrintW…...

C++ 指针变量做参数传递时的情况分析

前言 指针变量作为参数传递时&#xff0c;很容易混淆指针本身和指针指向的内容&#xff0c;实际应用中可能会导致无法预料的问题&#xff0c;所以做一下详细分析。 注意&#xff0c;在测试过程中为了看测试效果&#xff0c;有些指针变量分配了空间&#xff0c;但是未做回收&am…...

Linux环境下Oracle 11g的离线安装与配置历程

在成功体验了 Windows 版本的Oracle 11g 后&#xff0c;这几天心血来潮&#xff0c;决定再挑战一下Linux 环境下的安装&#xff0c;特别是在考虑到部门内部虚拟机无法联网的情况下&#xff0c;我选择了在CentOS 7上进行离线安装。这次安装之旅&#xff0c;主要参考了下面大佬的…...

上位机图像处理和嵌入式模块部署(mcu项目2:串口日志记录器)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 淘宝上面有一个商品蛮好玩的&#xff0c;那就是日志记录器。说是记录器&#xff0c;其实就是一个模块&#xff0c;这个模块的输入是一个ttl串口&am…...

容器是线程不安全的,如果多线程下不加锁直接使用容器会发什么

可能存在的问题 数据竞争 当两个或多个线程同时读写同一个容器且至少有一个线程在写时&#xff0c;会导致数据竞争。这种情况下&#xff0c;容器的内部状态可能会被破坏&#xff0c;从而导致未定义行为。这些未定义的行为包括数据损坏&#xff0c;程序崩溃&#xff0c;以及无…...

配置光源——笔记

一、灯光的类型 (一&#xff09;Directional Light&#xff08;定向光&#xff09; 1、只改变方向变化&#xff0c;不记录位置变化 2、相当于太阳光 3、室外一般使用 (二&#xff09;Spot 聚光灯&#xff1a;昏暗&#xff08;凌晨或傍晚&#xff09;&#xff0c;有一个光斑…...

Java---SpringBoot详解一

人性本善亦本恶&#xff0c; 喜怒哀乐显真情。 寒冬暖夏皆有道&#xff0c; 善恶终归一念间。 善念慈悲天下广&#xff0c; 恶行自缚梦难安。 人心如镜自省照&#xff0c; 善恶分明照乾坤。 目录 一&#xff0c;入门程序 ①&#xff0c;创建springboot工程&#…...

MFC扩展库BCGControlBar Pro v35.0 - 可视化管理主题等全新升级

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中&#xff0c;并为您节省数百个开发和调试时间。 BCGControlBar专业版 v35.0已全新发布了&#xff0c;这个版本改进类Visual Studio 2022的视觉主题、增强对多个…...

Springboot 配置 log4j2 时的注意事项

感谢博主 https://www.cnblogs.com/fishlittle/p/17950944 依赖 SpringBoot 的 spring-boot-starter/ spring-boot-starter-web 自带的是 logback 日志&#xff0c;若要使用 log4j2 日志&#xff0c;需要引入对应依赖。logback 日志和 log4j2 日志都是对 slf4j 门面的实现&am…...

公司网站友情链接怎么做副链/谷歌浏览器下载安装2022最新版

文章目录1. 简介2. 示例2.1 文件内容修改2.2 在某一行前面插入一行2.3 在某一行后面插入一行2.4 删除某一行2.5 末尾加入一行2.6 替换或添加某一行– ansible 快速学习手册 1. 简介 lineinfile:文件内容修改、在某行前面添加一行、在某行后面添加一行、删除某一行、末尾加入一…...

山东东营疫情最新消息/网站排名优化外包公司

我们平时用printf函数打印整数&#xff0c;用的是%d。你可能会问&#xff1a;整型是int(英文单词integer的缩写)&#xff0c;为什么整型的格式说明符不是%i&#xff1f;这是因为计算机中对整数的表达&#xff0c;会很关注整数是用二进制、八进制、十进制还是十六进制的形式来表…...

wordpress 简单主题/免费个人网站怎么建立

为什么80%的码农都做不了架构师&#xff1f;>>> --查询死锁 select request_session_id spid, OBJECT_NAME(resource_associated_entity_id) tableName from sys.dm_tran_locks where resource_typeOBJECT --杀死单个死锁 kill spid--在master中创建删除指定数据…...

avada 做的网站/软文写作平台发稿

简述 CentOS8 引入新的module软件包管理机制,下面将介绍如何部署搭建本地module源。 部署流程&#xff1a; 思路&#xff1a; 先制作nginx-1.14的module.yaml&#xff08;需要微调&#xff09;&#xff0c;然后同法制作nginx-1.16的module.yaml(需要微调)。 然后将nginx-1.1…...

网站不稳定/seo搜索引擎优化是什么意思

01 最长上升子序列 给定一个无序的整数数组&#xff0c;找到其中最长上升子序列的长度。 示例: 输入: [10,9,2,5,3,7,101,18] 输出: 4 解释: 最长的上升子序列是 [2,3,7,101]&#xff0c;它的长度是 4。说明: 可能会有多种最长上升子序列的组合&#xff0c;你只需要输出对…...

企业网上登记注册平台/seo软件视频教程

1_zclevel level     战场等级atitle     联盟给的头衔IDhtitle      部落给的头衔IDatitlestring    联盟给的头衔文字 一般做公告显示htitlestring    部落给的头衔文字一般做公告显示xp        升级需要经验值addspell      给予的BUFFaddtalent …...