Создание таблицы с использованием API Win32

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

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

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

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

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

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

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

Ответ 1

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

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

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

Если вы застряли в VС++, The Grid Control и The Ultimate Grid - это MFC-based.

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

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

Ответ 2

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

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

О элементах управления списком просмотров

Я нашел эту хорошую статью Windows Programmierung: просмотр списка объяснение есть на немецком языке, но перевод 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)

и т.д...

Ответ 3

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

Тем временем, Google Translate with Unicode + крошечные модификации для спасения для ссылки @Alejadro German для 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. Класс window использует константу 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

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

Сообщения 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, и все элементы были отредактированы.