wxPython in Action. Глава 13. Создание списков (list control) и управление им (Перевод)

В этой главе мы поговорим о:

  • создании списков в различных стилях
  • работа с элементами в списке
  • реакции на выбор пользователем элемента из списка
  • редактирование меток и сортировка списка
  • создание большого списка (large list)

У всех нас есть списки, которые мы хотим просмотреть, и программисты на wxPython не исключение. В wxPython есть два управляющих элемента, которые Вы можете использовать для отображения информации при помощи списков. Самый простой — list box — обычный список из одной колонки, который можно прокручивать, похожий на то, что Вы можете получить в HTML при помощивидимо, всё же имеется ввиду глава 7

Эта глава будет говорить о более сложном способе отображения информации в форме списка — элементе управления list (list control), полноценном виджете списка. Он отображает ListCtrl с несколькими колонками информации для каждой строки, который можно отсортировать по каждой колонке и стиль отображения которого можно настроить. У Вас есть достаточно гибкости в настройке каждой части этого элемента.

13.1 Создание элемента управления list

List может быть создан в одной из 4-х форм:

  • иконка (плитка)
  • маленькая иконка (значки)
  • список
  • отчёт

Суть этого должна быть понятна всем, кто использует Проводник в Windows или Mac Finder — это соответствует способам отображения элементов в проводнике. Мы начнём наше исследование этого элемента с того, что посмотрим как его создать в каждой из этих форм.

13.1.1 Что такое режим «иконка»

List выглядит как панель отображения дерева файловой системы в MS Windows Explorer. Этот элемент управления отображает информацию в одном из четырёх режимов. По умолчанию используется режим иконка, где каждый элемент списка представлен иконкой с текстом под ней. Рисунок 13.1 показывает простой пример этого режима.
Код для отображения этого примера приведён в листинге 13.1. Обратите внимание, что этот код зависит от некоторых .png файлов, которые расположены в той же папке, что и наш модуль. Эти файлы можно получить с сайта этой книги.
Листинг 13.1

import wx
import sys, glob
 
class DemoFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1,
            «wx.ListCtrl in wx.LC_ICON mode»,size=(600,400))
        il = wx.ImageList(32,32, True)
        # Создаём image list
        for name in glob.glob(«icon??.png»):
            bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG)
            il_max = il.Add(bmp)
        
        # Создаём list
        self.list = wx.ListCtrl(self, -1
            style=wx.LC_ICON | wx.LC_AUTOARRANGE)
        self.list.AssignImageList(il, wx.IMAGE_LIST_NORMAL)
        for x in range(25):
        # Заполняем list
            img = x % (il_max+1)
            self.list.InsertImageStringItem(x,
                «This is item %02d» % x, img)
 
app = wx.PySimpleApp()
frame = DemoFrame()
frame.Show()
app.MainLoop()
 

 

Рисунок 13.1 Простой список в режиме «иконка»

В листинге 13.1 демонстрационный фрейм создаёт список изображений (image list), который содержит ссылки на изображения, которые мы будем отображать; затем мы создаём и заполняем элемент list. Список изображения мы обсудим позже в этой главе.

13.1.2 Что такое режим «маленькая иконка»

Режим «маленькая иконка» (small icon) похож на режим «иконка», только использует маленькие значки. Рисунок 13.2 приводит пример того же самого списка в режиме «маленькой иконки».

Этот режим особенно полезен когда Вы хотите уместить в виджете много элементов, особенно если сами иконки не настолько детализированы, чтобы показывать их в исходном размере.

Рисунок 13.2 Простой list в режиме «маленькая иконка»

13.1.3 Что такое режим списка (list mode)?

В режиме списка элементы отображаются в нескольких колонках, автоматически заполняя каждую из них по очереди, как показано на рисунке 13.3
Этот режим имеет те же достоинства, что и режим «маленькая иконка»; выбор между ними (т.е. между расположением в строчку или в столбик) зависит от ваших предпочтений.
Рисунок 13.3 Простой list в режиме «список»

 

13.1.4 Что такое режим отчёта (report mode)?

В режиме отчёта list отображается в формате нескольких колонок, где каждый строк может иметь любое число столбцов, связанных с ним, как показано на рисунке 13.4

Рисунок 13.4 Простой list в режиме «отчёт»

Этот режим настолько отличается от режима «иконка», что стоит привести код, который нужен для создания такого отображения:

Листинг 13.2 Пример создания list’a в режиме «отчёт»

import wx
import sys, glob, random
import data

class DemoFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1,
            «wx.ListCtrl in wx.LC_REPORT mode»,
            size=(600,400))

        il = wx.ImageList(16,16, True)
        for name in glob.glob(«smicon??.png»):
            bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG)
            il_max = il.Add(bmp)
        # Создаём list
        self.list = wx.ListCtrl(self, -1, style=wx.LC_REPORT)
        self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL)

        # Добавляем колонки
        for col, text in enumerate(data.columns):
            self.list.InsertColumn(col, text)
        # Добавляем строки
        for item in data.rows:
            index = self.list.InsertStringItem(sys.maxint, item[0])
            for col, text in enumerate(item[1:]):
                self.list.SetStringItem(index, col+1, text)

            # даём каждому элементу случайное изображение
            img = random.randint(0, il_max)
            self.list.SetItemImage(index, img, img)

        # Настраиваем ширину колонок
        self.list.SetColumnWidth(0, 120)
        self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(3, wx.LIST_AUTOSIZE_USEHEADER)

app = wx.PySimpleApp()
frame = DemoFrame()
frame.Show()
app.MainLoop()

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

13.1.5 Как я могу создать list?

Элемент list в wxPython является экземпляром класса wx.ListCtrl. Его конструктор похож на конструкторы других виджетов:

wx.ListCtrl(parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.LC_ICON, validator=wx.DefaultValidator,  name=»listCtrl»)

Эти параметры содержат значения, которые мы уже видели в конструкторах других виджетов. parent — это родительский виджет, в котором будет расположен list; id — идентификатор wxPython, где -1 обозначает автоматически сгенерированное значение. Явно расположение задаётся параметрами pos и size. style задаёт режим и остальные опции отображения — об этом мы ещё поговорим в этой главе. validator используется для проверки ввода и о нём мы говорили в 9 главе. Параметр name используется достаточно редко.

Флаг style — это битовая маска, которая определяет некоторые возможности этого элемента управления. Первый набор значений — это режим отображения элемента. Режим по умолчанию — wx.LC_ICON.

Таблица 13.1 содержит остальные доступные режимы.

СтильОписание
wx.LC_ICONРежим «иконка»
wx.LC_LISTРежим «список»
wx.LC_REPORTРежим «отчёт»
wx.LC_SMALL_ICONРежим «маленькая иконка»
В режимах «иконка» и «маленькая иконка» доступны ещё три флага, которые определяют расположение иконки относительно списка. Значение по умолчанию — wx.LC_ALIGN_TOP, которе выравнивает иконки по вершине списка. Для выравнивания по левой стороне используйте wx.LC_ALIGN_LEFT. Стиль LC.AUTOARRANGE заворачивает иконки по достижении ими нижнего или правого угла окна.
Таблица 13.2 содержит стили отображения для режима «отчёт»:
СтильЗначение по умолчанию
wx.LC_HRULESРисуе
т линии между строками list’a
wx.LC_NO_HEADERНе отображает заголовки колонок
wx.LC_VRULESРисует линии между колонками list’a

Флаги битовых масок могут быть скомбинированы при помощи операции или. Используйте wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES для того чтобы получить вид, похожий на решётку. По умолчанию все элементы list позволяют осуществлять множественный выбор. Для того, чтобы это изменить используйте флаг wx.LC_SINGLE_SEL.

В отличие от остальных виджетов, которые мы видели до сих пор, list имеет ещё несколько методов, которые позволяют Вам изменить его флаги стилей уже в процессе выполнения. Метод SetSingleStyle(style, add=True) позволяет Вам добавить или удалить один флаг стиля, в зависимости от параметра add. Вызов listCtrl.SetSingleStyle(LC_HRULES, True) добавит горизонтальную линейку, тогда как listCtrl.SetSingleStyle(LC_HRULES, False) удалит её. Вызов SetWindowStyleFlag(style) позволяет Вам переустановить весь стиль, задав новые флаги, например, SetWindowsStyleFlag(LC_REPORT | LC_NO_HEADER). Эти методы полезны для изменения list’a на лету.

13.2 Управление элементами в list’e

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

13.2.1 Что такое image list и как к нему добавлять изображения

Перед тем, как мы сможем говорить о том, как информация добавляется в list, мы должны сказать несколько слов о том, как list работает с изображениями. Все изображения, используемые в этом элементе, должны быть сперва добавлены в image list, который представляет из себя проиндексированный массив изображений, сохранённых в элементе list. Когда Вы связываете изображение с определённым элементом в list, то для ссылки на изображение используется его индекс. Этот механизм позволяет быть уверенным в том, что каждое изображение загружено только один раз, вне зависимости от того, как часто оно используется в list. Что, в свою очередь, помогает сэкономить память в случаях, когда изображения используются по нескольку раз. Кроме того, это обегчает связь между несколькими версиями одного и того же изображения, что может быть полезно для различных режимов. Более подробно создание изображений и bitmap в wxPython обсуждается в главе 12.

Создание image list

image list является экземпляром wx.ImageList и для его создания используется следующий конструктор:

wx.ImageList(width, height, mask=True, initialCount=1)

Параметры width и height задают в пикселях размер изображения, которое будет добавлено в list. Изображения больше, чем указанный размер добавить нельзя. Если параметр mask = True, nj изображение рисуется с его маской, если она у него есть. Параметр initialCount задаёт начальный внутренний размер list’a. Если Вы знаете, что list будет большой, то указание этого размера может сэкономить память и время позже.

Добавление и удаление изображений

Вы можете добавить изображение в list при помощи метода Add(bitmap, mask=wx.NullBitmap), где bitmap и mask оба являются экземплярами wx.Bitmap. Аргумент mask является монохромным битовым изображением, которое определяет прозрачные части изображения, если они должны быть. Если битовое изображение уже имеет свою маску, то его маска и будет использоваться по умолчанию. Если маски у изображения нет и у Вас нет монохромной карты прозрачности, но Вы хотите чтобы какой-то цвет в изображении служил маской, Вы можете использовать метод AddWithColourMask(bitmap, colour), где colour — цвет wxPython (или его имя), который будет использоваться в качестве маски. Если у Вас есть объект wx.Icon, который Вы хотите добавить в image list, то используйте метод AddIcon(icon). Все методы добавления возвращают индекс изображения в list’e, который

Вы можете позже использовать.

Следующий отрывок кода показывает пример создания image list (похоже на листинг 13.1)

il = wx.ImageList(32, 32, True)
for name in glob.glob(«icon??.png»):
    bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG)
    il_max = il.Add(bmp)
image list должен быть привязан к list при помощи следующего метода:
self.list.AssignImageList(il, wx.IMAGE_LIST_NORMAL)

 

Для того, чтобы удалить изображение из image list, воспользуйтесь методом Remove(index), где index — индекс изображения в списке. Этот метод изменяет индексы всех изображений после удалённого, что может создать проблему,