使用Win32 API创建表

Ser*_*rge 11 winapi frameworks visual-c++

我一直在网上搜索关于win32 API的不同内容,但似乎所有关于它的信息都相当稀疏.

我希望创建一个显示项目列表的简单窗口,但是我希望以表格式格式显示每个项目的不同数据列,在这种格式中,用户可能可以调整不同列宽的大小.

如果可能的话,我还希望能够在代码中更改不同行的背景颜色,只需要一般的白色,红色,黄色或绿色.

并且还允许用户右键单击不同的行,并且能够在其上调用函数,或者将数据复制到剪贴板(但该部分是不同的故事).

现在,我找到了可以放在窗口,按钮和右键菜单中的列表查看器对象(?)......但我无法弄清楚如何使用Win32 API来创建表.除了窗口本身之外,我还没有真正读过背景颜色.

我应该使用一个不同的,更好的框架,还是有一些我一直缺少的功能或项目?关于这个想法的所有帮助或指导将不胜感激......

我正在使用MSVC++来做......我正在做的一切.

arx*_*arx 10

Windows提供了一个相当基本的内置控件集合,在此处列出.

如果您想要更复杂的东西,您的选择是:

  • 自己编码.你必须自己绘制它,处理所有用户交互,滚动等.这是一项很大的工作.
  • 查找现有实施.
  • 放弃VC++并使用WinForms或WPF.

如果您遇到VC++,网格控制终极网格都是基于MFC的.

如果你没有使用MFC,那就是BABYGRIDWin32 SDK数据网格.

如果它们都不合适,那么搜索"grid"比"table"更有幸.


Ale*_*der 8

使用Windows API和标准控件ListView,您可以使用样式LVS_REPORT执行表

文档链接 - 不幸的是没有代码:( -

关于列表视图控件

我发现这篇好文章Windows Programmierung:列表查看 解释是用德语进行的,但谷歌翻译与代码一起应该足以理解它.从文章中,创建窗口:

#include "commctrl.h"

InitCommonControls();
hwndList = CreateWindow(WC_LISTVIEW, "", 
         WS_VISIBLE|WS_BORDER|WS_CHILD | LVS_REPORT | LVS_EDITLABELS, 
         10, 10, 300, 100, 
         hWnd, (HMENU)ID_LIST, hInst, 0);
Run Code Online (Sandbox Code Playgroud)

然后解释了如何在方法中创建列

int CreateColumn(HWND hwndLV, int iCol, char *Text, int iWidth)
Run Code Online (Sandbox Code Playgroud)

如何插入项目(一列)

int CreateItem(HWND hwndList, char *Text)
Run Code Online (Sandbox Code Playgroud)

或插入两列的项目

int Create2ColItem(HWND hwndList, char *Text1, char *Text2)
Run Code Online (Sandbox Code Playgroud)

等等...


Lau*_*arn 5

对于列表视图示例,没有什么比经典示例的清晰度更好的了!

与此同时,谷歌翻译以及 Unicode + 的微小修改来拯救列表视图的 @Alejadro 的德语链接- 搜索结果没有提供直接翻译,因为页面不包含适当的元标记。为了简洁起见,剪了一点:

后续风格变化

ListView 的样式在创建后可以更改。为此,使用函数 GetWindowLong 和 SetWindowLong。关于蒙版,可以定义不同的样式。

掩码................................掩码样式:
LVS_TYPEMASK............ ..LVS_ICON、LVS_LIST、LVS_REPORT 和 LVS_SMALLICON LVS_ALIGNMASK........................LVS_ALIGNLEFT 和 LVS_ALIGNTOP LVS_TYPESTYLEMASK...LVS_ALIGNLEFT 和 LVS_ALIGNTOP 还有 VS_NOCOLUMNHEADER 和 LVS_NOSORTHEADER

对于以下序列,dwView 包含要使用的样式,例如LVS_REPORT or LVS_ICON.

DWORD dwStyle = GetWindowLong(hwndLV, GWL_STYLE); // get current style
if ((dwStyle & LVS_TYPEMASK)! = dwView) // only on change
SetWindowLong(hwndLV, GWL_STYLE, (dwStyle & ~ LVS_TYPEMASK) | dwView); }
Run Code Online (Sandbox Code Playgroud)

ListView控件的控制

生成列表

列表视图是使用 CreateWindow 函数创建的。窗口类使用常量WC_LISTVIEW。为此,必须包含公共控制头文件。

#include "commctrl.h"

InitCommonControls();
hwndList = CreateWindow(WC_LISTVIEW, "",
  WS_VISIBLE | WS_BORDER | WS_CHILD | LVS_REPORT | LVS_EDITLABELS,
  10, 10, 300, 100,
  hWnd, (HMENU) ID_LIST, hInst, 0);
Run Code Online (Sandbox Code Playgroud)


在对话框中,它只是在资源中定义。

如果存在未解析的外部,您应该检查是否包含公共控件库(comctl32.lib)。

ListView 的列

在将某些内容插入 a 之前REPORT,必须先定义列。列由结构描述LVCOLUMN。以下例程创建一个列。

int CreateColumn(HWND hwndLV, int iCol, char * text, intwidth)
{
LVCOLUMN lvc;

lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
lvc.cx = iWidth;
lvc.pszText = text;
lvc.iSubItem = iCol;
return ListView_InsertColumn(hwndLV, iCol, & lvc);
}
Run Code Online (Sandbox Code Playgroud)

可以通过发送至 ListView 的消息或调用最终执行 SendMessage 的宏来修改列。

Message            Macro call                                    Function
LVM_INSERTCOLUMN   ListView_InsertColumn(HWND, int, LVCOLUMN * ) Insert column
LVM_DELETECOLUMN   ListView_DeleteColumn(HWND, int)              Delete column
LVM_GETCOLUMN      ListView_GetColumn(HWND, int, LVCOLUMN * )    Get properties of the column
LVM_SETCOLUMN      ListView_SetColumn(HWND, int, LVCOLUMN * )    Change properties of the column
LVM_GETCOLUMNWIDTH ListView_GetColumnWidth(HWND, int)            Determine column width
LVM_SETCOLUMNWIDTH ListView_SetColumnWidth(HWND, int, int)       Set column width
Run Code Online (Sandbox Code Playgroud)

插入一行

ListView 的元素由结构描述LVITEMW(见下文)。每个元素都可以表示为ICON, SMALLICON,LIST元素或行的左列REPORT

int CreateItem(HWND hwndList, wchar_t * text)
 {
 LVITEMW lvi = {0};
 lvi.mask = LVIF_TEXT;
 lvi.pszText = text;
 return ListView_InsertItem(hwndList, & lvi);
 }
Run Code Online (Sandbox Code Playgroud)

掩码字段确定LVITEMW真正使用结构的哪些元素。由于保留一个指向保存对象后面数据的内存对象的指针通常是有意义的,因此 lParam 字段很有用。为了使用它,LVIF_TEXT | LVIF_PARAM必须将其设置为掩码。

mask 的常量和启用它们的字段:

LVIF_IMAGE iImage
LVIF_INDENT iIndent
LVIF_PARAM lParam
LVIF_STATE 状态
LVIF_TEXT pszText

报告的其他栏目

元素本身始终保留在报表视图中并且可以选择。为了填充更多列,将文本添加到该项目中。

int Create2ColItem(HWND hwndList, wchar_t * Text1, wchar_t * Text2)
{
LVITEMW lvi = {0};
int Ret;
// Initialize LVITEMW members that are common to all items.
lvi.mask = LVIF_TEXT;
lvi.pszText = Text1;
Ret = ListView_InsertItem(hwndList, & lvi);
if (Ret >= 0)
{
ListView_SetItemText(hwndList, Ret, 1, Text2);
}
return Ret;
}
Run Code Online (Sandbox Code Playgroud)

以下Create2ColItem陈述可以最好地证明上述内容:

    LVHwnd = Your_Create_LV_Routine();
    if (LVHwnd)
    {
    CreateColumn(LVHwnd, 0, ptrColHeaderString1, iColSize1);
    CreateColumn(LVHwnd, 1, ptrColHeaderString2, iColSize2);
    Create2ColItem(LVHwnd, ptrItemText1, ptrItemText2);
    }
Run Code Online (Sandbox Code Playgroud)

结构LVITEMW

该结构LVITEMW(在CommCtrl.h中)描述了 ListView 的元素。这里简要描述了最重要的元素。首先定义:

typedef struct tagLVITEMW
{
  UINT mask;
  int iItem;
  int iSubItem;
  UINT state;
  UINT stateMask;
  LPWSTR pszText;
  int cchTextMax;
  int iImage;
  LPARAM lParam;
  #if (_WIN32_IE >= 0x0300) //historical note for IE3 users!
  int iIndent;
  #endif
  #if (NTDDI_VERSION >= NTDDI_WINXP)
    int iGroupId;
    UINT cColumns; // tile view columns
    PUINT puColumns;
  #endif
  #if (NTDDI_VERSION >= NTDDI_VISTA)
    int* piColFmt;
    int iGroup; // readonly. only valid for owner data.
  #endif
} LVITEMW, *LPLVITEMW;
Run Code Online (Sandbox Code Playgroud)

LVM_GETITEMW消息LVM_SETITEMW更改元素的属性。作为参数,您将获得一个指向 ListViewLVITEMW旁边的结构的指针HWND,该结构必须提前填充。

详细结构要素:

Mask:指定使用哪些元素。以下标志的组合是可能的:

LVIF_IMAGE iImage

LVIF_INDENT i缩进

LVIF_PARAM l参数

LVIF_STATE状态

LVIF_TEXT pszText

iItem 与结构相关的项目的索引(从 0 开始)。

iSubItem 与结构相关的子项的索引(从 1 开始)。如果结构引用的是项目而不是子项目,则为 0。

pszText 指向一个以 null 结尾的字符串。如果值为LPWSTR_TEXTCALLBACK,则为回调项。如果发生变化,必须将 pszText 设置为并通过或LPSTR_TEXTCALLBACK通知 ListView 。 如果 ListView 具有样式或 ,则不得设置为。LVM_SETITEMWLVM_SETITEMTEXTpszTextLPWSTR_TEXTCALLBACKLVS_SORTASCENDINGLVS_SORTDESCENDING

cchTextMax 读取文本时缓冲区的大小。

iImage 图像列表中该元素的图标的索引。

lParam 特定于此元素的 32 位值。

元素动作

LVM_INSERTITEM 插入元素 LVM_DELETEITEM 删除元素 LVM_DELETEALLITEMS 删除所有元素 LVM_GETITEMW 读取元素的属性 LVM_GETITEMTEXT 读取元素的文本 LVM_SETITEMW 更改 LVM_SETITEMTEXT 更改为文本

在插入多个项目之前,LVM_SETITEMCOUNT将向 ListView 发送一条消息,指示最终将包含多少个项目。这使得ListView能够优化其内存分配和释放。可以使用 确定 ListView 包含多少个元素LVM_GETITEMCOUNT

编辑选定的元素

int Pos = -1;
LVITEMW Item;
Pos = ListView_GetNextItem(hwndList, Pos, LVNI_SELECTED);
while (Pos> = 0)
{
Item.iItem = Pos;
Item.iSubItem = 0;
ListView_GetItem(hwndList, & Item);
TuWasMitElement((Element Type * ) Item.lParam);
Pos = ListView_GetNextItem(hwndList, Pos, LVNI_SELECTED);
}
Run Code Online (Sandbox Code Playgroud)

事件 ListViewWM_NOTIFY向父窗口发送消息。该代码可以采用以下值:

消息............说明
LVN_BEGINDRAG......开始拖放操作
LVN_BEGINRDRAG......开始拖动使用鼠标右键进行拖放操作
LVN_BEGINLABELEDIT....开始编辑标签
LVN_ENDLABELEDIT.......结束编辑标签
LVN_DELETEITEM.........报告该项目已删除
LVN_DELETEALLITEMS ..报告所有项目都被删除
LVN_COLUMNCLICK ......指示用户单击了报告显示的标题
LVN_GETDISPINFO ......该控件从父窗口请求有关演示文稿的信息
LVN_SETDISPINFO ... ....该项目的父窗口的信息必须更新
LVN_INSERTITEM ......表示插入一个项目
LVN_ITEMCHANGED .....表示一个项目已更改
LVN_ITEMCHANGING ... .表示项目的预期更改
LVN_KEYDOWN........................按键被按下

编辑标签 列表视图必须是使用LVS_EDITLABELS样式创建的。然后就可以点击标签并接受输入。但是,输入之后会立即被丢弃。要允许更改标签,您只需捕获WM_NOTIFY并返回TRUE。为了访问其间输入的文本,需要访问该项目的文本。该示例显示消息框中的输入。

case WM_NOTIFY:
 switch (((LPNMHDR) lParam) -> code)
 {
  case LVN_ENDLABELEDIT:
  pItem = (NMLVDISPINFO) lParam;
  MessageBox (hWnd, pItem-> item.pszText, "entry", MB_OK);
  return TRUE;
Run Code Online (Sandbox Code Playgroud)

如果编辑被中止,该pszText元素将为 0。

如果您想阻止编辑,LVN_BEGINLABELEDIT则会捕获并返回该消息TRUE。这里,也可以通过相同的方式访问该项目lParam,因此,例如可以排除某个项目组。

单击 ListView 中的列标题

case WM_NOTIFY:
 switch (((LPNMHDR) lParam) -> code)
 {
 case LVN_COLUMNCLICK:
 ColumnNr = ((LPNMLISTVIEW) lParam) -> iSubItem;
 .....
Run Code Online (Sandbox Code Playgroud)

评选活动

LVN_ITEMACTIVATE当用户激活某个项目时发送该事件。与其他 ListView 事件一样,它作为WM_NOTIFY消息的一部分实现窗口功能。

case WM_NOTIFY:
switch (((LPNMHDR) lParam) -> code)
{
case LVN_ITEMACTIVATE:
HWND hwndFrom = (HWND) ((LPNMHDR) lParam) -> hwndFrom;MarkedItemIndex = 
ListView_GetNextItem(hwndFrom, -1, LVNI_SELECTED);
.....
Run Code Online (Sandbox Code Playgroud)

LVM_GETSELECTEDCOUNT消息可用于确定有多少项目已被激活。消息LVM_GETNEXTITEM随属性一起发送LVNI_SELECTED,并且所有项目均已编辑。