Создание таблицы с использованием Win32 API - PullRequest
11 голосов
/ 23 января 2012

Я искал в сети разные вещи о Win32 API, но кажется, что вся информация о нем довольно скудна.

Я ищу, чтобы создать простое окно, которое показывает список элементов,однако я хочу отображать разные столбцы данных для каждого элемента в формате таблицы, где пользователю может быть разрешено изменять размер столбцов различной ширины.

Если это вообще возможно, я бы хотелтакже можно изменять цвета фона различных строк в коде между обычным белым, красным, желтым или зеленым.

И пользователю также будет позволено щелкнуть правой кнопкой мыши разные строки ивозможность вызвать на них функцию или скопировать данные в буфер обмена (но эта часть - другая история).

Теперь я нашел объекты просмотра списка (?), которые можно поместить вокна, кнопки и меню правой кнопки мыши ... но я не могу понять, как сделать таблицу, используя Win32 API.Я даже на самом деле не читал о цветах фона для чего-либо, кроме самого окна.

Есть ли другая, лучшая структура, которую я должен использовать для этого, или есть какие-то функции или элементы, которые я 'пропал?Буду признателен за любую помощь или руководство по этой идее ...

Я использую MSVC ++ для выполнения ... всего, над чем я работаю.

Ответы [ 3 ]

10 голосов
/ 23 января 2012

Windows предоставляет довольно простую коллекцию встроенных элементов управления, перечисленных здесь .

Если вы хотите что-то более сложное, вы можете выбрать:

  • Кодируй это сам. Вы должны нарисовать это самостоятельно, обрабатывать все взаимодействия с пользователем, прокрутку и т. Д. Это большая работа.
  • Найти существующую реализацию.
  • Откажитесь от VC ++ и используйте WinForms или WPF.

Если вы застряли с VC ++, Grid Control и Ultimate Grid основаны на MFC.

Если вы не используете MFC, есть BABYGRID или Сетка данных Win32 SDK .

Если ни один из них не подходит, вам больше повезет в поиске "сетки", чем "таблицы".

8 голосов
/ 28 декабря 2013

Используя Windows API и стандартный элемент управления ListView, вы можете создать таблицу, используя стиль LVS_REPORT

ссылка на документацию - к сожалению, без кода :( -

О List-ViewЭлементы управления

Я нашел эту хорошую статью Программирование Windows: представление списка объяснение дано на немецком языке, но для его понимания достаточно перевода Google вместе с кодом.статья, чтобы создать окно:

#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);

, затем объясняется, как создать столбцы в методе

int CreateColumn(HWND hwndLV, int iCol, char *Text, int iWidth)

как вставить элемент (один столбец)

int CreateItem(HWND hwndList, char *Text)

или вставить элемент с двумя столбцами

int Create2ColItem(HWND hwndList, char *Text1, char *Text2)

и т. Д. *

0 голосов
/ 22 января 2018

Для примеров Listview ничто не сравнится с четкостью Classic Sample !

Тем временем Google Translate вместе с Юникодом + небольшие модификации для спасения немецкой ссылки @ Alejadro для Listview - прямой перевод в результатах поиска не предлагается, так как страница не содержит соответствующий метатег . Отрезал немного для краткости:

Последующие изменения стилей

Стиль 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); }

Элемент управления 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);


В диалоге это просто определяется в ресурсе.

Если есть неразрешенные внешние компоненты, следует проверить, включена ли библиотека для общих элементов управления (comctl32.lib).

Столбцы ListView

Прежде чем что-то вставить в 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);
}

Столбцы могут быть изменены сообщениями в 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

Вставить строку

Элемент 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);
 }

Поле маски определяет, какие элементы структуры LVITEMW действительно используются. Поскольку часто имеет смысл сохранять указатель на объект памяти, который содержит данные за объектом, поле lParam полезно. Чтобы это можно было использовать, LVIF_TEXT | LVIF_PARAM должен быть установлен в качестве маски.

Константы маски и поля для их включения:

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;
}

Вышеуказанное Create2ColItem лучше всего демонстрируется чем-то вроде следующего утверждения:

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

Структура LVITEMW

Структура LVITEMWCommCtrl.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;

Сообщения LVM_GETITEMW и LVM_SETITEMW изменяют атрибуты элемента. В качестве параметра вы получаете указатель на структуру LVITEMW рядом с HWND в ListView, которая должна быть заполнена заранее.

Детали конструкции в деталях:

маска : Определяет, какие элементы используются. Возможна комбинация следующих флагов:

LVIF_IMAGE iImage

LVIF_INDENT iIndent

LVIF_PARAM lParam

LVIF_STATE состояние

LVIF_TEXT pszText

iItem Индекс (на основе 0) элемента, к которому относится структура.

iSubItem Индекс (на основе 1) подэлемента, к которому относится структура. 0, если структура ссылается на элемент, а не на подпункт.

pszText указывает на строку с нулевым символом в конце. Если значение LPWSTR_TEXTCALLBACK, это элемент обратного вызова. Если это изменится, pszText должен быть установлен в LPSTR_TEXTCALLBACK, а ListView будет информирован LVM_SETITEMW или LVM_SETITEMTEXT pszText не должен быть установлен в LPWSTR_TEXTCALLBACK, если ListView имеет стиль LVS_SORTASCENDING или LVS_SORTDESCENDING.

cchTextMax Размер буфера при чтении текста.

iImage Индекс значка этого элемента из списка изображений.

LPARAM 32-разрядное значение, характерное для этого элемента.

Действия с элементами

LVM_INSERTITEM Вставка элемента LVM_DELETEITEM Удалить элемент LVM_DELETEALLITEMS Удалить все элементы LVM_GETITEMW Считать свойства элемента LVM_GETITEMTEXT Прочитать текст элемента LVM_SETITEMW изменить LVM_SETITEMTEXT Изменить на текст

Перед вставкой нескольких элементов в ListView будет отправлено сообщение LVM_SETITEMCOUNT, указывающее, сколько элементов в конечном итоге будет содержаться. Это позволяет 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);
}

События ListView отправляет WM_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;

Если редактирование было прервано, элемент pszText будет равен 0.

Если вы хотите запретить редактирование, сообщение LVN_BEGINLABELEDIT перехватывается и возвращается TRUE. Здесь также можно получить доступ к элементу таким же образом через lParam и, таким образом, например, можно исключить определенную группу элементов.

Щелкните заголовок столбца в ListView

case WM_NOTIFY:
 switch (((LPNMHDR) lParam) -> code)
 {
 case LVN_COLUMNCLICK:
 ColumnNr = ((LPNMLISTVIEW) lParam) -> iSubItem;
 .....

Событие выбора

Событие 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);
.....

Сообщение LVM_GETSELECTEDCOUNT может использоваться для определения количества элементов, которые были активированы. Сообщение LVM_GETNEXTITEM отправляется с атрибутом LVNI_SELECTED, и все элементы были отредактированы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...