» ListView: список с колонками

K.A.V.
www.oszone.net
22.02.2010
Автор: K.A.V.
Последнее обновление: 17.05.2014

Примечание. Для работы с данным элементом необходимо добавить в код:
!include "nsDialogs.nsh"
!include "CommCtrl.nsh"

Т.к. данный тип элемента не поддерживается NIS Edit -  нам необходимо вручную прописать тип элемента в настройки с секцией элемента
Для этого создаём любой элемент, доступный в NIS Edit, для наглядности лучше создать элемент "ListBox", подгоните размеры элемента и читайте дальше :)
Затем переходим в режим редактирования (F12), ищем порядковый номер нашего созданного элемента и меняем значение параметра Type на ListView
[Field 1]
Type=ListView

Для создания взаимодействующего элемента:
NOTIFY=ONSELCHANGE


Необходимые стили

Начнем работу с данным элементом с того, что присвоим ему необходимый стиль для нашей работы, назначив параметру Flags значение REPORT_VIEW

Если вы хотите, чтобы при выделении мышкой пункта в списке выделялась вся строка целиком, а не только текст, то после инициализации необходимо присвоить ещё один стиль данному элементу командой:
SendMessage $HWND ${LVM_SETEXTENDEDLISTVIEWSTYLE} "${LVS_EX_FULLROWSELECT}" "${LVS_EX_FULLROWSELECT}"
где $HWND - HWND элемента


Создание колонок и их начальная ширина

Т.к. мы не можем изменять названия уже созданных колонок (либо я не знаю, в общем не особо интересовал этот вопрос, поэтому напишу так, как я сам делаю), нам необходимо сначала удалить первую колонку, чтобы потом добавить её с названием.
Делать это необходимо на этапе после инициализации
${NSD_LV_DeleteColumn} $HWND 0

Команда на добавление колонки следующая:
${NSD_LV_InsertColumn} $HWND "0" "100" "Название первой колонки"
где $HWND - HWND элемента
где 0 - порядковый номер колонки, отчет с 0
где 100 - начальная ширина колонки (ниже будет ещё информация, как скорректировать ширину колонок)

В примере я буду рассматривать элемент ListView с 3 колонками
Перед продолжением, хотел бы показать вам свой код, который я использую уже в озвученном SFX Creator для автоматического равного деления ширины элемента между всеми колонками в нашем элементе, данный код позволит отображать вам одинаковую и равную ширину колонок на разных настройках DPI у пользователя:
Обратите внимание на занятые переменные.
 System::Call "*(i,i,i,i)i.R0"
 System::Call `user32::GetClientRect(i$HWND, iR0)`
 System::Call "*$R0(i.R1, i.R2, i.R3, i.R4)"
IntOp $R3 $R3 / 3
где $HWND - HWND элемента
где 3 - количество колонок в нашем элементе
результат в $R3 - ширина, которая будет у всех колонок

А теперь пример кода, который создаёт 3 колонки с равной шириной, поделенной в зависимости от размера элемента:
Function MyDialog

  InitPluginsDir
  File /oname=$PLUGINSDIR\Project.ini "Project.ini"

        InstallOptionsEx::initDialog /NOUNLOAD "$PLUGINSDIR\Project.ini"

  Var /global HWND
  ReadINIStr $HWND "$PLUGINSDIR\Project.ini" "Field 1" "HWND"

 System::Call "*(i,i,i,i)i.R0"
 System::Call `user32::GetClientRect(i$HWND, iR0)`
 System::Call "*$R0(i.R1, i.R2, i.R3, i.R4)"
IntOp $R3 $R3 / 3
${NSD_LV_DeleteColumn} $HWND 0
${NSD_LV_InsertColumn} $HWND "0" "$R3" "Название первой колонки"
${NSD_LV_InsertColumn} $HWND "1" "$R3" "Название второй колонки"
${NSD_LV_InsertColumn} $HWND "2" "$R3" "3 колонка"

 SendMessage $HWND ${LVM_SETEXTENDEDLISTVIEWSTYLE} "${LVS_EX_FULLROWSELECT}" "${LVS_EX_FULLROWSELECT}"

        InstallOptionsEx::show
FunctionEnd


Подгонка ширины колонок после создания/во время работы

После добавления/удаления/редактирования пункта мы должны корректировать область видимости информации в элементе (ширину колонок), чтобы наше содержимое всегда корректно отображалось так, как мы хотим, мы будем использовать одну из команд:
1. Для выравнивания ширины колонки по самому длинному тексту в указанной колонке
SendMessage $HWND ${LVM_SETCOLUMNWIDTH} "0" "${LVSCW_AUTOSIZE}"
где $HWND - HWND элемента
где 0 - порядковый номер колонки, отчет с 0, по которому будет корректироваться горизонтальная граница перемотки
Примечание. Если вы хотите, чтобы ширина колонок была постоянной и горизонтальная перемотка в элементе корректировалась в зависимости от содержимого, советую вам выставлять корректировку по последней колонке в элементе

2. Для выравнивания ширины колонки по названию колонки
Если вы не хотите корректировать ширину колонок в зависимости от содержимого строк, можете после инициализации прописать команду авто-корректировки ширины колонок по названию
SendMessage $HWND ${LVM_SETCOLUMNWIDTH} "0" "${LVSCW_AUTOSIZE_USEHEADER}"
где $HWND - HWND элемента
где 0 - порядковый номер колонки, отчет с 0, по которому будет корректироваться ширина колонки
Чтобы скорректировать ширину всех колонок, вам необходимо прописать данную команду для каждой клонки, меняя порядковый номер, например при наличии у вас 3х колонок, после инициализации у вас должны быть такие команды:
SendMessage $HWND ${LVM_SETCOLUMNWIDTH} "0" "${LVSCW_AUTOSIZE_USEHEADER}"
SendMessage $HWND ${LVM_SETCOLUMNWIDTH} "1" "${LVSCW_AUTOSIZE_USEHEADER}"
SendMessage $HWND ${LVM_SETCOLUMNWIDTH} "2" "${LVSCW_AUTOSIZE_USEHEADER}"
В любом случае, тесты за вами, выберите самый подходящий для вас вариант ;)


Удаление всех строк в элементе

Для удаления всех в строк в элементе мы будем использовать следующую команду (после инициализации или в режиме реального времени):
SendMessage $HWND ${LVM_DELETEALLITEMS} 0 0
где $HWND - HWND элемента


Добавление строк и заполнение колонок строки

Чтобы наши добавляемые строки добавлялись в конец списка, нам сначала необходимо узнать количество уже существующих строк в элементе, делается это командой:
SendMessage $HWND ${LVM_GETITEMCOUNT} "" "" $1
где $HWND - HWND элемента
результат в $1 - количество существующих строк, отчет идет с 0

Затем мы добавляем нашу строку в последнюю позицию:
${NSD_LV_InsertItem} $HWND "$1" "Моя строка"
где $HWND - HWND элемента
где $1 - позиция, начиная с 0, в которую мы вставляем строку, т.к. до этого мы получили количество строк сообщением "LVM_GETITEMCOUNT", мы используем переменную $1 и вставляем нашу строку последней в список
Обратите внимание, что мы можем вставить строку в любую позицию, даже самой первой в уже существующем списке

Для заполнения необходимых колонок строки, мы будем использовать следующую команду:
${NSD_LV_SetItemText} $HWND "$1" "2" "Вставляемый текст"
где $HWND - HWND элемента
где $1 - позиция строки, начиная с 0, в которой мы хотим назначить текст определённой колонке
где 2 - порядковый номер колонки, начиная с 0, которой мы хотим назначить текст

Сначала некоторым может показаться сложно, но здесь на самом деле всё очень просто, меня по началу смущали "порядковые номера", отчет которых идёт с 0, но со временем уже привык :)

Пример добавления 3х строк с заполнением 3х колонок
Function MyDialog

  InitPluginsDir
  File /oname=$PLUGINSDIR\Project.ini "Project.ini"

        InstallOptionsEx::initDialog /NOUNLOAD "$PLUGINSDIR\Project.ini"

  Var /global HWND
  Var /global HWND_Text
  ReadINIStr $HWND "$PLUGINSDIR\Project.ini" "Field 1" "HWND"

 System::Call "*(i,i,i,i)i.R0"
 System::Call `user32::GetClientRect(i$HWND, iR0)`
 System::Call "*$R0(i.R1, i.R2, i.R3, i.R4)"
IntOp $R3 $R3 / 3

 SendMessage $HWND ${LVM_DELETEALLITEMS} 0 0
 ${NSD_LV_DeleteColumn} $HWND 0
 ${NSD_LV_InsertColumn} $HWND "0" "$R3" "Название первой колонки"
 ${NSD_LV_InsertColumn} $HWND "1" "$R3" "Название второй колонки"
 ${NSD_LV_InsertColumn} $HWND "2" "$R3" "3 колонка"

 ${NSD_LV_InsertItem} $HWND "0" "Моя первая строка"
${NSD_LV_SetItemText} $HWND "0" "0" "Первая строка, первая колонка"
${NSD_LV_SetItemText} $HWND "0" "1" "Первая строка, вторая колонка"
${NSD_LV_SetItemText} $HWND "0" "2" "Первая строка, третяя колонка"

 ${NSD_LV_InsertItem} $HWND "1" "Моя вторая строка"
${NSD_LV_SetItemText} $HWND "1" "0" "Вторая строка, первая колонка"
${NSD_LV_SetItemText} $HWND "1" "1" "Вторая строка, вторая колонка"
${NSD_LV_SetItemText} $HWND "1" "2" "Вторая строка, третяя колонка"

 ${NSD_LV_InsertItem} $HWND "2" "Моя третяя строка"
${NSD_LV_SetItemText} $HWND "2" "0" "Третяя строка, первая колонка"
${NSD_LV_SetItemText} $HWND "2" "1" "Третяя строка, вторая колонка"
${NSD_LV_SetItemText} $HWND "2" "2" "Третяя строка, третяя колонка"

 SendMessage $HWND ${LVM_SETEXTENDEDLISTVIEWSTYLE} "${LVS_EX_FULLROWSELECT}" "${LVS_EX_FULLROWSELECT}"

        InstallOptionsEx::show
FunctionEnd


Как узнать позицию и текст в строке всех колонок, которая выделена?

Примечание. Для использования флага вы должны сделать элемент взаимодействующим.
Данная возможность будет работать только при некоторых условиях:
Если вы пропишите соответствующую команду на событие при выделении строки пользователем. Вам необходимо выделить отдельную переменную для хранения информации о позиции выбранного пункта при работе кастомной странички.
SendMessage $HWND ${LVM_GETHOTITEM} "" "" $R9
где $HWND - HWND элемента
результат в R9 - позиция выбранного элемента, начиная с 0

Затем, вы уже можете в любом месте функции получать текст из всех колонок в выделенной строке, данной командой:
${NSD_LV_GetItemText} $HWND $R9 "0" $1
где $HWND - HWND элемента
где $R9 - позиция выбранной строки, начиная с 0
где 0 - порядковый номер колонки, начиная с 0, текст из которой мы "вытаскиваем"
результат в $1 - текст выделенной строки в указанной колонке

Пример кода, который получает данные из 3х колонок второй строки
${NSD_LV_GetItemText} $HWND 1 "0" $1
${NSD_LV_GetItemText} $HWND 1 "1" $2
${NSD_LV_GetItemText} $HWND 1 "2" $3
где $HWND - HWND элемента
где 1 - позиция второй строки (отчет с 0)
где 0 - порядковый номер первой колонки (отчет с 0)
где 1 - порядковый номер второй колонки (отчет с 0)
где 2 - порядковый номер третьей колонки (отчет с 0)
результат в $1 - текст из первой колонки второй строки
результат в $2 - текст из второй колонки второй строки
результат в $3 - текст из третьей колонки второй строки


Изменение содержимого строки в колонке

Для изменения содержимого строки мы будем использовать ту же команду, которую используем при назначении текста определённой колонке в определённой строке:
${NSD_LV_SetItemText} $HWND "$1" "2" "Вставляемый текст"
где $HWND - HWND элемента
где $1 - позиция строки, начиная с 0, в которой мы хотим назначить текст определённой колонке
где 2 - порядковый номер колонки, начиная с 0, которой мы хотим назначить текст


Удаление строки

Для удаления строки используйте следующую команду:
SendMessage $HWND ${LVM_DELETEITEM} "3" ""
где $HWND - HWND элемента
где 3 - позиция строки, начиная с 0, которую вы удаляете


Отключаем перерисовку элемента при активном добавлении строк

Если вы будете в режиме реального времени заполнять элемент большим количеством строкам, то можете столкнуться с таким эффектом у элемента, как искаженное отображение или вовсе исчезновение элемента, пока ваши строки добавляются.
Этого можно избежать, достаточно дать элементу команду не перерисовывать своё содержимое, пока вы добавляете элементы.
Перед командой добавления строк пропишите команду: 
SendMessage $HWND ${WM_SETREDRAW} "0" ""
где $HWND - HWND элемента
где 0 - запрет элементу перерисовывать своё содержимое

После добавления элементов необходимо выполнить эту же команду, но передать другое значение:
SendMessage $HWND ${WM_SETREDRAW} "1" ""
где $HWND - HWND элемента
где 1 - разрешение элементу перерисовывать своё содержимое


Как "проскроллить" (перемотать) список на определённую позицию?

Опять же, всё легко!
Достаточно выполнить следующую команду:
SendMessage $HWND ${LVM_ENSUREVISIBLE} $0 1
где $HWND - HWND элемента
где $0 - позиция, начиная с 0, на которую мы перематываем элемент
Соответственно, чтобы при активном добавлении строк вам показывалась самая последняя, необходимо после команды добавления строки добавить данную команду с последней позицией добавленной строки