Работа с сеткой (grid control)

Эта глава включает:

Сетка (grid) – это, наверное, самый сложный и гибкий виджет в wxPython. В этой главе мы покажем, как работать со многими из особенностей сетки. Мы поговорим о том, как вводить данные и управлять ими в сетке, а также о создании собственных редакторов. Сетка позволяет отображать данные в формате подобном электронной таблице. Этот виджет позволяет вам определять заголовки для строк и столбцов, изменять размер сетки, определять шрифт и цвет для каждой ячейки.

В большинстве случаев, значения в сетке отображаются как простые строки. Однако, вы можете определить свой способ отображения для любой ячейки, который позволит вам показать данные по-другому; например, отображать логическое значение как переключатель. Вы можете редактировать значение ячейки, непосредственно в сетке, и можете использовать другие типы редакторов для различных видов данных. Вы можете также создать ваш собственный редактор и способ отображения, чтобы иметь почти неограниченную гибкость в отображении и управлении данными ячейки. Сетки также имеют большое количество событий мыши и клавиатуры, которые вы можете перехватить и обработать в своем приложении.

Мы начнем наше обсуждение, показав два способа создания сетки.

Создание вашей сетки

Сетка отображает двумерный набор данных. Для управления и отображения данных, вы должны связать эти данные с сеткой. В wxPython, есть два различных механизма работы с данными в сетке. При этом добавление, удаление и редактирование данных обрабатывается по-разному.

Данные могут находиться непосредственно в сетке. Сетка может управлять данными косвенно, используя таблицу сетки.

Проще когда сетка содержит данные непосредственно. Но в этом случае, сетка должна поддерживать собственную копию данных. Это может быть неудобно, если данных слишком много, или если ваше приложение уже имеет существующую подобную таблице структуру данных. Если так, вы можете использовать таблицу сетки. См. главу 5, в которой дан обзор паттерна MVC.

Как создать простую сетку?

Хотя сетка имеет огромное количество методов, для начала достаточно всего нескольких. На рисунке 14.1 изображена типичная сетка, с некоторыми данными.

14-1.gif

Рисунок 14.1

Сетка – это объект класса wx.grid.Grid. Из-за размера этого класса и связанных классов, а также из-за того, что много программ его не используют, классы для сеток wxPython находятся в их собственном модуле, который автоматически не импортирован. Конструктор для wx.grid.Grid подобен другим конструкторам виджетов.

   1 wx.grid.Grid(parent, id, pos=wx.DefaultPosition,
   2     size=wx.DefaultSize, style=wx.WANTS_CHARS,
   3     name=wxPanelNameStr)

Все эти параметры подобны основному конструктору wx.Window, и имеют то же самое значение. Стиль wx.WANTS_CHARS - значение по умолчанию для сетки; кроме того, wx.grid.Grid не определяет никаких собственных флажков стиля. Так как класс сетки очень сложен, сетка в вашем приложении, скорее всего будет реализована через свой подкласс, вместо того, чтобы использовать объект wx.grid.Grid непосредственно.

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

   1 CreateGrid()
   2 SetTable()

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

Чтобы явно инициализировать сетку, используйте метод CreateGrid(numRows, numCols, selmode=wx.grid.Grid.SelectCells). Этот метод нужно вызвать после конструктора, и перед отображением сетки. Первые два параметра, numRows и numCols, определяют начальный размер сетки. Третий параметр, selmode, определяет, как выбирются ячейки. Значение по умолчанию, wx.grid.Grid.SelectCells, означает, что пользователь может выбирать отдельные ячейки. Другие значения - wx.grid.Grid.SelectRows, означает, что выбираются целиком строки, и wx.grid.Grid.SelectionColumns - выбираются столбцы. После создания, вы можете получить режим выбора методом GetSelectionMode(), и установить режим методом SetSelectionMode(). Вы можете получить количество строк и столбцов, используя методы GetNumberCols() и GetNumberRows().

При инициализации сетки методом CreateGrid(), wxPython создает двумерный массив строк. Как только сетка инициализирована, вы можете поместить в нее данные, используя метод SetCellValue(row, col, s). Параметры row и col - координаты ячейки, и s - текст строки. Если вы хотите получить значение из определенной ячейки, вы можете использовать функцию GetCellValue(row, col), которая возвращает строку. Чтобы очистить всю сетку сразу, используйте метод ClearGrid(). Листинг 14.1 содержит код, создающий сетку, изображенную на рисунке 14.1.

Листинг 14.1 Сетка, созданная с использованием CreateGrid()

   1 import wx
   2 import wx.grid
   3 
   4 class TestFrame(wx.Frame):
   5     def __init__(self):
   6         wx.Frame.__init__(self, None, title="Simple Grid",
   7                           size=(640,480))
   8         grid = wx.grid.Grid(self)
   9         grid.CreateGrid(50,50)
  10         for row in range(20):
  11             for col in range(6):
  12                 grid.SetCellValue(row, col,
  13                                   "cell (%d,%d)" % (row, col))
  14 
  15 app = wx.PySimpleApp()
  16 frame = TestFrame()
  17 frame.Show()
  18 app.MainLoop()

Использование CreateGrid() и SetCellValue(), для создания и заполнения сетки ограничивается случаем, когда ваши данные составлены из простых строк. Если ваши данные более сложны, или если таблица является особенно большой, вы, вероятно, предпочтете способ, который рассматривается далее.

Как создать сетку с таблицей сетки?

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

В главе 5, мы обсуждали таблицы сетки в контексте паттерна MVC, наряду с другими способами создания сетки в вашем приложении. В этой главе, мы сосредоточимся на особенностях использования таблицы сетки. На рисунке 14.2 изображена сетка, созданная с использованием таблицы сетки.

Чтобы использовать таблицу сетки, создайте ваш собственный подкласс wx.grid.PyGridTableBase. Ваш подкласс должен переопределить несколько методов родительского класса wx.grid.GridTableBase. Листинг 14.2 содержит код создания сетки, изображенной на рисунке 14.2.

Листинг 14.2 Использование механизма таблицы сетки

   1 import wx
   2 import wx.grid
   3 
   4 class TestTable(wx.grid.PyGridTableBase):
   5     
   6     def __init__(self):
   7         wx.grid.PyGridTableBase.__init__(self)
   8         self.data = { (1,1) : "Here",
   9                       (2,2) : "is",
  10                       (3,3) : "some",
  11                       (4,4) : "data",
  12                       }
  13         
  14         self.odd=wx.grid.GridCellAttr()
  15         self.odd.SetBackgroundColour("sky blue")
  16         self.odd.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
  17 
  18         self.even=wx.grid.GridCellAttr()
  19         self.even.SetBackgroundColour("sea green")
  20         self.even.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
  21 
  22 
  23     # these five are the required methods
  24     def GetNumberRows(self):
  25         return 50
  26 
  27     def GetNumberCols(self):
  28         return 50
  29 
  30     def IsEmptyCell(self, row, col):
  31         return self.data.get((row, col)) is not None
  32 
  33     def GetValue(self, row, col):
  34         value = self.data.get((row, col))
  35         if value is not None:
  36             return value
  37         else:
  38             return ''
  39 
  40     def SetValue(self, row, col, value):
  41         self.data[(row,col)] = value
  42 
  43 
  44     # the table can also provide the attribute for each cell
  45     def GetAttr(self, row, col, kind):
  46         attr = [self.even, self.odd][row % 2]
  47         attr.IncRef()
  48         return attr
  49 
  50 
  51 class TestFrame(wx.Frame):
  52     
  53     def __init__(self):
  54         wx.Frame.__init__(self, None, title="Grid Table",
  55                           size=(640,480))
  56 
  57         grid = wx.grid.Grid(self)
  58 
  59         table = TestTable()
  60         grid.SetTable(table, True)
  61         
  62 
  63 app = wx.PySimpleApp()
  64 frame = TestFrame()
  65 frame.Show()
  66 app.MainLoop()

В листинге 14.2, вся специфическая для приложения логика была перемещена в класс таблицы сетки. Таким образом, нет никакой потребности создавать собственный подкласс wx.grid.Grid.

14-2.gif

Рисунок 14.2

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

Таблица 14.1 Методы, переопределяемые в wx.grid.GridTableBase

Метод

Описание

GetNumberCols()

Возвращает количество столбцов в сетке

GetNumberRows()

Возвращает количество строк в сетке

GetValue(row, col)

Возвращает значение ячейки с координатами row и col

IsEmptyCell(row, col)

Возвращает True, если ячейка с координатами row и col пустая. В большинстве случаев этот метод возвращает False.

SetValue(row, col, value)

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

Для присоединения таблицы сетки к объекту сетки служит метод SetTable(table, takeOwnership=False, selmode=wx.grid.Grid.SelectCells). Используйте его вместо метода CreateGrid(). Параметр table - ваш объект wx.grid.PyGridTableBase. Параметр takeOwnership говорит сетке, что у нее есть связанная таблица. Если этот параметр - True, таблица будет удалена wxPython системой при удалении сетки. Параметр selmode работает также как в CreateGrid().

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

Один дополнительный метод, который вы можете переопределить - Clear(). Он вызывается, когда сетка вызывает ClearGrid(). Можно использовать этот метод, чтобы очистить основной источник данных. Теперь, когда вы присоединили данные к сетке, вы можете производить с этими данными различные операции. В следующем разделе, мы покажем вам, как управлять вашей сеткой.

Работа с сеткой

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

Как добавить и удалить строки, столбцы и ячейки?

Даже после того, как сетка была создана, вы все еще можете добавлять новые строки и столбцы. Отметьте, что механизм работает по-другому в зависимости от того, как сетка была создана. Вы можете добавить столбец справа от столбцов сетки, используя метод AppendCols(numCols=1). Чтобы добавить строку снизу сетки, используйте аналогичный метод AppendRows(numRows=1).

Если вы хотите добавить строку или столбец не в конец, а в середину сетки, вы можете использовать метод InsertCols(pos=0, numCols=1) или InsertRows(pos=1, numRows=1). В обоих случаях, параметр pos представляет индекс добавляемого элемента. Если numRows или numCols больше, чем один, дальнейшие элементы добавляются правее этой позиции (для столбцов), или ниже (для строк).

Чтобы удалить строку или столбец, вы можете использовать методы DeleteCols(pos=0, numCols=1) и DeleteRows(pos=0, numRows=1). В этих методах, параметр pos - индекс первой строки или столбца, который будет удален. Дальнейшие элементы будут удалены правее или ниже этого индекса соответственно.

Если сетка была инициализирована методом CreateGrid(), то методы описанные выше будут работать. При этом значением ячеек в новых строках или столбцах будут пустые строки. Однако, если сетка была инициализирована методом SetTable(), то объект таблицы сетки должен разрешить изменения в таблице. Потому что некоторые таблицы, возможно, не могут управлять изменением размеров таблицы (например, сетка отображает таблицу базы данных, которую вы не можете редактировать).

Чтобы разрешить изменение, ваша таблица сетки должна переопределить тот же самый метод изменения. Например, если вы вызываете метод сетки InsertCols(), то таблица сетки также должна определить метод InsertCols(pos=0, numCols=1). Метод таблицы сетки возвращает True, чтобы разрешить изменение или False, чтобы запретить. Например, чтобы создать таблицу, у которой предельное количество строк - 50, напишите следующий метод в таблице сетки

   1 def AppendRows(self, numRows=1):
   2     return (self.GetRowCount() + numRows) <= 50

Этот метод возвращает True, чтобы разрешить изменение, пока новое общее количество строк меньше или равно 50.

Содержимое новых строк зависит от метода таблицы сетки GetValue(). Если вы позволяете изменение размера в вашей таблице, вы должны убедиться, что метод GetValue() может обработать новый номер строки и столбца.

Некоторые изменения в сетке не отображаются немедленно, а ожидают, когда сетка будет обновлена. Вы можете вызвать немедленное обновление сетки, используя метод ForceRefresh(). Вообще, если вы делаете программное изменение в вашей сетке, то нужно вставить ForceRefresh(), чтобы гарантировать, что ваше изменение было отображено.

Если вы делаете большое количество изменений в сетке, и не хотите, чтобы изображение сетки мерцало в это время, то нужно выполнить эти изменения как пакет, используя метод BeginBatch(). Вызов этого метода увеличивает на единицу внутренний счетчик для сетки. Вы должны компенсировать BeginBatch() более поздним вызовом EndBatch(). Метод EndBatch() уменьшает на единицу внутренний счетчик. Пока счетчик больше нуля, сетка не будет перерисовывать себя. Вызовы этих методов могут быть вложенными.

Как управлять заголовками строк и столбцов сетки?

В wxPython каждая строка и столбец сетки имеет метку (заголовок). По умолчанию, строкам дают числовые метки, начинающиеся с 1, а столбцам дают алфавитные метки, начинающиеся с A и продолжающиеся к Z, потом AA, AB, и так далее. Если вы создаете электронную таблицу – здорово. Но для большинства других приложений это не подходит. К счастью в wxPython есть методы, позволяющие изменить метки. На рисунке 14.3 показана сетка с измененными заголовками.

14-3.gif

Рисунок 14.3

Листинг 14.3 содержит код для этого рисунка. В этом примере, сетка была инициализирована методом CreateGrid().

Листинг 14.3 Код для простой сетки со своими метками

   1 import wx
   2 import wx.grid
   3 
   4 class TestFrame(wx.Frame):
   5     
   6     rowLabels = ["uno", "dos", "tres", "quatro", "cinco"]
   7     colLabels = ["homer", "marge", "bart", "lisa", "maggie"]
   8     
   9     def __init__(self):
  10         wx.Frame.__init__(self, None, title="Grid Headers",
  11                           size=(500,200))
  12         grid = wx.grid.Grid(self)
  13         grid.CreateGrid(5,5)
  14         for row in range(5):
  15             grid.SetRowLabelValue(row, self.rowLabels[row])
  16             grid.SetColLabelValue(row, self.colLabels[row])
  17             for col in range(5):
  18                 grid.SetCellValue(row, col, 
  19                         "(%s,%s)" % (self.rowLabels[row],
  20                         self.colLabels[col]))
  21 
  22 app = wx.PySimpleApp()
  23 frame = TestFrame()
  24 frame.Show()
  25 app.MainLoop()

Как добавление и удаление строк, изменение заголовков, имеют отличия для разных типов сеток. Для сеток, которые созданы методом CreateGrid(), установите значения метки, используя методы SetColLabelValue(col, value) и SetRowLabelValue(row, value). параметр col и row - индекс соответствующего столбца или строки, а параметр value - строка, которая будет отображена в заголовке. Чтобы получить метки для строки или столбца, используйте методы GetColLabelValue(col) и GetRowLabelValue(row).

Для сетки, использующей внешнюю таблицу сетки, вы можете достигнуть того же самого эффекта, переопределив методы таблицы сетки GetColLabelValue(col) и GetRowLabelValue(row). Эти методы вызываются сеткой, когда необходимо отобразить заголовки, и сетка имеет связанную таблицу. Так как возвращаемое значение определяется вашим методом, нет необходимости переопределять или вызывать соответствующие Set-методы. Хотя эти методы SetColLabelValue(col, value) и SetRowLabelValue(row, value) существуют, они редко используются. Как правило, вы не нуждаетесь в этих методах. В листинге 14.4 показано, как изменять метки в сетке таблицы.

Листинг 14.4 Сетка с таблицей сетки, которая имеет свои заголовки

   1 import wx
   2 import wx.grid
   3 
   4 class TestTable(wx.grid.PyGridTableBase):
   5     def __init__(self):
   6         wx.grid.PyGridTableBase.__init__(self)
   7         self.rowLabels = ["uno", "dos", "tres", "quatro", "cinco"]
   8         self.colLabels = ["homer", "marge", "bart", "lisa", "maggie"]            
   9         
  10     def GetNumberRows(self):
  11         return 5
  12 
  13     def GetNumberCols(self):
  14         return 5
  15 
  16     def IsEmptyCell(self, row, col):
  17         return False
  18 
  19     def GetValue(self, row, col):
  20         return "(%s,%s)" % (self.rowLabels[row], self.colLabels[col])
  21 
  22     def SetValue(self, row, col, value):
  23         pass
  24         
  25     def GetColLabelValue(self, col):
  26         return self.colLabels[col]
  27        
  28     def GetRowLabelValue(self, row):
  29         return self.rowLabels[row]
  30 
  31 class TestFrame(wx.Frame):
  32     def __init__(self):
  33         wx.Frame.__init__(self, None, title="Grid Table",
  34                           size=(500,200))
  35         grid = wx.grid.Grid(self)
  36         table = TestTable()
  37         grid.SetTable(table, True)
  38         
  39 app = wx.PySimpleApp()
  40 frame = TestFrame()
  41 frame.Show()
  42 app.MainLoop()

По умолчанию, метки отцентрированы. Однако, вы можете изменить такое поведение, используя методы SetColumnLabelAlignment(horiz, vert) и SetRowLabelAlignment(horiz, vert). Параметр horiz управляет горизонтальным выравниванием и может иметь значения wx.ALIGN_LEFT, wx.ALIGN_CENTRE или wx.ALIGN_RIGHT. Параметр vert управляет вертикальным выравниванием и может иметь значения wx.ALIGN_TOP, wx.ALIGN_CENTRE или wx.ALIGN_BOTTOM.

Заголовки строк и столбцов совместно используют общие свойства шрифта и цвета. Вы можете управлять этими свойствами с помощью методов SetLabelBackgroundColour(colour), SetLabelFont(font) и SetLabelTextColour(colour). Параметр colour - это объект wx.Colour или строка с названием цвета, которую wxPython преобразует в цвет. Параметр font - объект wx.Font. Существуют соответствующие методы для получения этих атрибутов GetLabelBackgoundColour(), GetLabelFont() и GetLabelTextFont().

Как управлять размером элементов сетки?

У сетки есть несколько различных методов для изменения размеров ячеек, строк и столбцов. В этом разделе мы обсудим каждый из этих методов. На рисунке 14.4 изображены некоторые из способов изменения размеров ячейки.

14-4.gif

Рисунок 14.4

В листинге 14.5 создается сетка с измененными ячейками, строками и столбцами.

Листинг 14.5 Изменение размеров ячеек, строк и столбцов

   1 import wx
   2 import wx.grid
   3 
   4 class TestFrame(wx.Frame):
   5     
   6     
   7     def __init__(self):
   8         wx.Frame.__init__(self, None, title="Grid Sizes",
   9                           size=(600,300))
  10         grid = wx.grid.Grid(self)
  11         grid.CreateGrid(5,5)
  12         for row in range(5):
  13             for col in range(5):
  14                 grid.SetCellValue(row, col, "(%s,%s)" % (row, col))
  15          
  16         grid.SetCellSize(2, 2, 2, 3)        
  17         grid.SetColSize(1, 125)  
  18         grid.SetRowSize(1, 100)
  19 
  20 app = wx.PySimpleApp()
  21 frame = TestFrame()
  22 frame.Show()
  23 app.MainLoop()

Изменение размера ячейки

Один из способов изменить размер ячейки состоит в том, чтобы заставить ячейку охватить больше чем одну строку или столбец, аналогично атрибутам HTML rowspan и colspan. Чтобы управлять этим в wxPython, используйте метод SetCellSize(row, col, num_rows, num_cols). Он заставляет ячейку охватывать num_rows строк и num_col столбцов. При нормальных обстоятельствах, каждая ячейка занимает одну строку и один столбец, поэтому, чтобы заставить ячейку заполнить большее пространство, вы должны передать значения параметров большее единицы. Задание нулевых или отрицательных значений для num_rows и num_cols, вызовет ошибку. Если вы устанавливаете размер ячейки, который накладывается на другую измененную ячейку, то, предварительно, нужно отменить изменения другой ячейки. Вы можете также отключить отображение переполнения ячейки, используя метод SetCellOverflow(row, col, allow). Вызов этого метода препятствует ячейке переполняться, даже если ее размер был установлен методом SetCellSize().

Более типичный метод изменения размеров – это установка размеров в пикселях строки или столбца. Вы можете установить размер определенной строки или столбца, используя методы SetColSize(col, width) и SetRowSize(row, height). Естественно, вы можете определить текущий размер строки или столбца, используя GetColSize(col) или GetRowSize(row).

Установка размеров по умолчанию

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

   1 SetDefaultColSize(width, resizeExistingCols=False)
   2 SetDefaultRowSize(height, resizeExistingRows=False)

В обоих методах, первый параметр - новый размер в пикселях. Если второй параметр - True, то размеры всех существующих строк или столбцов будут немедленно изменены в соответствии с новым значением по умолчанию. Если параметр - False, существующие строки или столбцы не изменяются, и новое значение по умолчанию применяется только к новым строкам или столбцам. Обычно размеры по умолчанию устанавливаются в начале инициализации, даже перед вызовом CreateGrid() или SetTable(). Вы можете получить текущие размеры по умолчанию, используя методы GetDefaultColSize() и GetDefaultRowSize().

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

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

В wxPython, вы можете установить минимальное значение для всей сетки или установить его для отдельных строк и столбцов. Чтобы изменить минимальное значение для всей сетки, используйте метод SetColMinimalAcceptableWidth(width) или SetRowMinimalAcceptableHeight(height). Параметр - минимальный размер для всех строк или столбцов в пикселях. Чтобы установить минимум для отдельного столбца или строки, используйте SetColMinimalWidth(col, width) или SetRowMinimalHeight(row, height). Для этих методов, первый параметр - индекс устанавливаемого по размеру элемента, а второй параметр - новый размер в пикселях. Минимальный размер отдельной строки должен быть больше, чем минимальное значение, установленное для строк всей сетки. Существующие строки или столбцы, которые имеют размер меньший, чем новый минимум, не будут автоматически изменены. Поэтому, вы вероятно захотите вызвать эти методы в процессе инициализации прежде, чем добавить данные. Лучше сохранять минимальные приемлемые значения близкими к фактическим наименьшим размерам реальной ячейки. Каждый из этих методов имеет соответствующую функцию для получения значения.

   1 GetColMinimalAcceptableWidth()
   2 GetRowMinimalAcceptableHeight()
   3 GetColMinimalWidth(col)
   4 GetRowMinimalHeight(row)

Установка размеров заголовков

Область заголовков сетки имеет отдельный набор функций для установки размеров. В этом случае, вы устанавливаете ширину заголовка строки, и высоту заголовка столбца. При этом метка столбца обрабатывается как специальная строка, а метка строки как специальный столбец. Как пример, посмотрите на электронную таблицу. Метод SetRowLabelSize(width) устанавливает ширину меток строки, а метод SetColLabelSize(height) устанавливает высоту меток столбца. Вы можете получить эти размеры методами GetRowLabelSize() и GetColLabelSize().

Хотелось бы не заботиться о фактическом размере ячеек в пикселях. Желательно, чтобы размеры были установлены автоматически достаточно большими, чтобы отобразить данные. В wxPython вы можете установить авто размер для всей сетки методом AutoSize(). Когда он вызывается, все строки и столбцы изменяются так, чтобы минимально соответствовать их содержанию. Вы можете установить авто размер и для определенных строк и столбцов. Метод AutoSizeColumn(col, setAsMin=True) изменяет размер столбеца, чтобы минимально соответствовать его содержанию. Если параметр setAsMin - True, новый авто размер будет минимальным размером этого столбца. Точно так же метод AutoSizeColumns(setAsMin=True) изменяет размеры всех столбцов в сетке. Есть аналогичные методы и для строк, AutoSizeRow(row, setAsMin=True) и AutoSizeRows(setAsMin=True). Снова, параметр setAsMin позволяет одновременно установить минимальный размер строки.

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

Используя методы без параметра, мы разрешаем указанные действия. Существуют параллельные методы, которые позволяют отключить эти возможности:

И ряд методов для получения состояния:

   1 CanDragColSize()
   2 CanDragRowSize()
   3 CanDragGridSize()

Как можно узнать, какие ячейки выбраны или видимы?

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

Одновременно, в сетке могут быть выбраны следующие комбинации ячеек:

Пользователь может выбрать больше чем одну группу ячеек, используя клавишу Ctrl или щелчком мыши по ячейкам, заголовку строки или столбца. Чтобы определять, есть ли выбранные ячейки, используйте метод IsSelection(). Вы можете определить, выбрана ли какая-нибудь определенная ячейка, используя метод IsInSelection(row, col).

В таблице 14.2 показаны несколько методов, которые позволяют вам по-разному получить выбранные ячейки.

Таблица 14.2 Методы получения, выбранных ячеек

Метод

Возвращаемое значение

GetSelectedCells()

Возвращает список всех ячеек, которые были индивидуально выбраны. Каждый элемент списка - кортеж (row, col).

GetSelectedCols()

Возвращает список индексов столбцов, которые были выбраны, щелчком на заголовке столбца.

GetSelectedRows()

Возвращает список индексов строк, которые были выбраны, щелчком на заголовке строки

GetSelectionBlockTopLeft()

Возвращает список, каждый элемент которого - кортеж (row, col) левого верхнего угла каждого выбранного блока ячеек.

GetSelectionBlockBottomRight()

Возвращает список, каждый элемент которого - кортеж (row, col) правого нижнего угла каждого выбранного блока ячеек.

Есть также несколько методов для того, чтобы установить или изменить выбор. Первый - ClearSelection(), который удаляет любой текущий выбор. После вызова этого метода, IsSelection() возвращает False. Вы можете выполнить противоположное действие выбрав все ячейки методом SelectAll(). Весь столбец или всю строку можно выбрать методами SelectCol(col, addToSelected=False) и SelectRow(row, addToSelected=False). В обоих методах, первый параметр - индекс строки или столбца для выбора. Если параметр addToSelected - True, все другие в данный момент выбранные ячейки остаются выбранными и строка или столбец добавляются к существующему выбору. Если параметр addToSelected – False, то выбор всех других ячеек отменяется. Аналогично можно добавить прямоугольный блок методом SelectBlock(topRow, leftCol, bottomRow, rightCol, addToSelected=False), где первые четыре параметра - углы прямоугольника, и параметр addToSelected ведет себя как в предыдущих методах.

Вы можете определить, видима ли ячейка в текущем отображении, использовуя метод IsVisible(row, col, wholeCellVisible=True). Метод возвращает True, если ячейка с указанными координатами в настоящий момент отображается на экране, а не скрыта в прокручиваемой области. Если wholeCellVisible - True, вся ячейка должна быть видимой, чтобы метод возвратил True, если параметр - False, достаточно, чтобы была видима любая часть ячейки. Наоборот, метод MakeCellVisible(row, col) гарантирует, что ячейка в данных координатах видима без прокрутки.

В дополнение к выбранным ячейкам, сетка также имеет текущую ячейку (курсор). Вы можете определить текущую позицию курсора методами GetGridCursorCol() и GetGridCursorRow(), которые возвращают соответствующий целочисленный индекс. Вы можете установить курсор явно методом SetGridCursor(row, col). Этот метод перемещает курсор и неявно вызывает MakeCellVisible для новой позиции курсора.

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

Таблица 14.3 Методы преобразования координат.

Метод

Описание

BlockToDeviceRect(topLeft, bottomRight)

Параметры topLeft и bottomRight - координаты ячейки - в wxPython, передаются как кортежи (row, col). Возвращаемое значение - wx.Rect координаты в пикселях прямоугольника, ограниченного данными координатами сетки. В случае необходимости, прямоугольник отсечен по размеру окна сетки.

CellToRect(row, col)

Возвращает wx.Rect с координатами относительно контейнера для ячейки (row, col).

XToCol(x)

Возвращает целочисленный индекс столбца, содержащего данную координату x относительно контейнера. Если нет никакого столбца в этой координате, то возвращает wx.NOT_FOUND.

XToEdgeOfCol(x)

Возвращает целочисленный индекс столбца, правый край которого является самым близким к данной координате x. Если нет такого столбца, возвращает wx.NOT_FOUND.

YToRow(y)

Возвращает целочисленный индекс строки, содержащей данную координату y. Если нет такой строки, возвращает wx.NOT_FOUND.

YToEdgeOfRow(y)

Возвращает строку, нижний край которой является самым близким к данной координате y. Если нет такой строки, возвращает wx.NOT_FOUND.

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

Как изменить цвет или шрифт ячейки сетки?

Как и в других элементах управления, есть ряд свойств, которые вы можете использовать, чтобы изменить атрибуты изображения для каждой ячейки. На рисунке 14.5 изображена часть из того, что можно сделать, используя эти методы.

14-5.gif

Рисунок 14.5

В листинге 14.6 показан код для рисунка 14.5. Обратите внимание на использование методов сетки, нацеленных на определенную ячейку и создание объектов wx.grid.GridCellAttr.

Листинг 14.6 Изменение цвета ячеек сетки

   1 import wx
   2 import wx.grid
   3 
   4 class TestFrame(wx.Frame):
   5         
   6     def __init__(self):
   7         wx.Frame.__init__(self, None, title="Grid Attributes",
   8                           size=(600,300))
   9         grid = wx.grid.Grid(self)
  10         grid.CreateGrid(10,6)
  11         for row in range(10):
  12             for col in range(6):
  13                 grid.SetCellValue(row, col, "(%s,%s)" % (row, col))
  14          
  15         grid.SetCellTextColour(1, 1, "red")
  16         grid.SetCellFont(1,1, wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
  17         grid.SetCellBackgroundColour(2, 2, "light blue")
  18         
  19         attr = wx.grid.GridCellAttr()
  20         attr.SetTextColour("navyblue")
  21         attr.SetBackgroundColour("pink")
  22         attr.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
  23 
  24         grid.SetAttr(4, 0, attr)
  25         grid.SetAttr(5, 1, attr)
  26         grid.SetRowAttr(8, attr)
  27 
  28 
  29 app = wx.PySimpleApp()
  30 frame = TestFrame()
  31 frame.Show()
  32 app.MainLoop()

Мы начнем обсуждение с методов, используемых для установки значений по умолчанию для всей сетки. Вы можете установить выравнивание по умолчанию для всех ячеек в сетке методом SetDefaultCellAlignment(horiz, vert), где horiz - wx.LEFT, wx.CENTRE или wx.RIGHT, и vert - wx.TOP, wx.CENTRE или wx.BOTTOM. Получить, установленное по умолчанию выравнивание, можно с помощью метода GetDefaultCellAlignment(), который возвращает кортеж (horiz, vert).

Цвет фона и текста может быть установлен методами SetDefaultCellTextColour(colour) и SetDefaultCellBackgroundColour(colour). Как обычно, цвет может быть объектом wx.Colour или строкой названием цвета. Методы для получения значений - GetDefaultCellTextColour() и GetDefaultCellBackgroundColour(). Наконец, вы можете управлять шрифтом по умолчанию с помощью методов SetDefaultCellFont(font) и GetDefaultCellFont().

Используя следующие методы, вы можете установить эти же признаки для отдельной ячейки.

   1 GetCellAlignment(row, col)
   2 SetCellAlignment(row, col, horiz, vert)
   3 
   4 GetCellBackgroundColour(row, col)
   5 SetCellBackgroundColour(row, col, colour)
   6 
   7 GetCellFont(row, col)
   8 SetCellFont(row, col, font)
   9 
  10 GetCellTextColour(row, col)
  11 SetCellTextColour(row, col, colour)

Каждый метод аналогичен методу для значения по умолчанию, с добавлением параметров row и col, которые определяют координаты ячейки.

Выбранные ячейки имеют другой цвет фона и текста, которые могут быть изменены. Методы - SetSelectionBackground(colour) и SetSelectionForeground(colour), и связанные методы GetSelectionBackground() и GetSelectionForeground().

Вы можете поместить дополнительное пространство вокруг сетки при использовании метода SetMargins(extraWidth, extraHeight) - параметры указывают количество пикселей, которые используются, чтобы добавить пространство в пределах ее контейнера.

Внутренне, класс wx.grid.Grid использует класс wx.grid.GridCellAttr, чтобы управлять атрибутами каждой ячейки. Этот класс имеет методы для всех свойств, обсуждаемых в этом разделе. Вы можете получить объект attr отдельной ячейки при использовании метода GetOrCreateCellAttr(row, col) метода, который возвращает объект атрибутов ячейки, или создает такой объект в случае необходимости. Объект атрибутов ячейки создается только, если ячейка определила свойства, отличные от значения по умолчанию для сетки. Как только вы получаете объект атрибутов ячейки, вы можете использовать его, чтобы изменить свойства ячейки.

Чтобы создать ваш собственный объект атрибутов ячейки, используйте конструктор wx.grid.GridCellAttr(). Вы можете установить некоторые параметры, затем передать объект в методы SetColAttr(attr) или SetRowAttr(attr), которые применяют атрибуты к каждой ячейке, как это показано в листинге 14.6.

Если вы используете таблицу сетки, вы можете переопределить метод GetAttr(row, col), чтобы он возвращал объект wx.grid.GridCellAttr для определенной ячейки.

Вы можете также изменить цвет и отображение линий координатной сетки. Отображением линий координатной сетки управляет метод EnableGridLines(enable). Если параметр - True, линии отображаются, если False они не отображаются. Вы можете изменить цвет линий координатной сетки методом SetGridLineColor(colour).

Управление отображением ячеек и создание собственных редакторов

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

Как использовать способ отображения (renderer) ячейки?

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

В wxPython, каждая ячейка может иметь собственный способ отображения (renderer), который позволяет отображать ее данные по-другому. Следующие разделы обсуждают несколько предопределенных способов отображения. А также как определить ваш собственный способ отображения.

Предопределенные способы отображения Renderer сетки – это объект класса wx.grid.GridCellRenderer, который является абстрактным родительским классом. Как правило, вы используете один из его подклассов. Таблица 14.4 описывает несколько предопределенных renderers, которые вы можете использовать в ваших ячейках. Каждый из этих классов имеет конструктор и соответствующие Get- и Set- методы.

Таблица 14.4 Предопределенные способы отображения (renderers) ячеек сетки

Renderer class

Описание

wx.grid.GridCellAutoWrapStringRenderer

Печатает текстовые данные с переходом на новую строку в границах ячейки.

wx.grid.GridCellBoolRenderer

Используется для булевых данных. Отображается в виде переключателя, включенного для значения True, и выключенного для False.

wx.grid.GridCellDateTimeRenderer

Позволяет отображать в ячейке отформатированную дату и/или время.

wx.grid.GridCellEnumRenderer

Отображает номер как текстовый эквивалент. Другими словами, в ячейке находятся данные из списка [0,1,2], но ячейка отображает их как значение из списка ["Джон", "Фред", "Боб"].

wx.grid.GridCellFloatRenderer

Отображает числовые данные с плавающей запятой с определенной шириной и точностью. Конструктор для этого класса берет два параметра (width=-1, precision=-1), где width - минимальное число цифр, для показа, и precision - максимальное число цифр, после десятичной точки. Числа, отображенные этим renderer выровнены по правому краю по умолчанию.

wx.grid.GridCellNumberRenderer

Отдает числовые данные. Числа, отображенные этим renderer выровнены по правому краю по умолчанию.

wx.grid.GridCellStringRenderer

Отображает данные как простые строки. По умолчанию, данные, отображенные этим renderer выровнены по левому краю. Это renderer по умолчанию используемый сеткой для всех ячеек.

Чтобы получить renderer для определенной ячейки, используйте метод GetCellRenderer(row, col), который возвращает объект renderer для ячейки с указанными координатами. Чтобы установить renderer для ячейки, используйте SetCellRenderer(row, col, renderer), где параметр renderer - новый renderer для этой ячейки. Эти методы просто устанавливают renderer в объекте атрибутов ячейки, таким образом вы можете работать с GridCellAttr непосредственно, если предпочитаете. Вы можете получить и установить renderer по умолчанию для всей сетки при использовании методов GetDefaultRenderer() и SetDefaultRenderer(renderer).

Вы можете установить renderer для всего столбца в случае, когда определенные столбцы всегда отображают данные одного типа. Методы для этого - SetColFormatBool(col), SetColFormatNumber(col) и SetColFormatFloat(col, width, precision).

Создание своего renderer

Чтобы создавать ваш собственный renderer, нужно создать класс производный от wx.grid.PyGridCellRenderer. Создание собственного renderer позволит вам делать такие вещи как отображение числового значение в виде мини-диаграммы или выполнить специальное форматирование для строки или даты.

На рисунке 14.6 изображен простой собственный renderer, который случайным образом изменяет цвет фона ячейки. Этот renderer установлен для определенной строки. Вы обратите внимание, когда сетка будет мерцать при перерисовке, поскольку выбирается случайный цвет.

14-6.gif

Рисунок 14.6

В листинге 14.7 показано создание собственного класса renderer, и переопределение методов.

Листинг 14.7 Собственный renderer, который изменяет цвет случайным образом

   1 import wx
   2 import wx.grid
   3 import random
   4 
   5 class RandomBackgroundRenderer(wx.grid.PyGridCellRenderer):
   6     def __init__(self):
   7         wx.grid.PyGridCellRenderer.__init__(self)
   8 
   9 
  10     def Draw(self, grid, attr, dc, rect, row, col, isSelected):
  11         text = grid.GetCellValue(row, col)
  12         hAlign, vAlign = attr.GetAlignment()
  13         dc.SetFont( attr.GetFont() )
  14         if isSelected:
  15             bg = grid.GetSelectionBackground()
  16             fg = grid.GetSelectionForeground()
  17         else:
  18             bg = random.choice(["pink", "sky blue", "cyan", "yellow",
  19                                 "plum"])
  20             fg = attr.GetTextColour()
  21 
  22         dc.SetTextBackground(bg)
  23         dc.SetTextForeground(fg)
  24         dc.SetBrush(wx.Brush(bg, wx.SOLID))
  25         dc.SetPen(wx.TRANSPARENT_PEN)
  26         dc.DrawRectangleRect(rect)           
  27         grid.DrawTextRectangle(dc, text, rect, hAlign, vAlign)
  28 
  29 
  30     def GetBestSize(self, grid, attr, dc, row, col):
  31         text = grid.GetCellValue(row, col)
  32         dc.SetFont(attr.GetFont())
  33         w, h = dc.GetTextExtent(text)
  34         return wx.Size(w, h)
  35   
  36     def Clone(self):
  37         return RandomBackgroundRenderer()
  38 
  39 class TestFrame(wx.Frame):
  40     def __init__(self):
  41         wx.Frame.__init__(self, None, title="Grid Renderer",
  42                           size=(640,480))
  43 
  44         grid = wx.grid.Grid(self)
  45         grid.CreateGrid(50,50)
  46 
  47         # Set this custom renderer just for row 4
  48         attr = wx.grid.GridCellAttr()
  49         attr.SetRenderer(RandomBackgroundRenderer())
  50         grid.SetRowAttr(4, attr)
  51         
  52         for row in range(10):
  53             for col in range(10):
  54                 grid.SetCellValue(row, col,
  55                                   "cell (%d,%d)" % (row, col))
  56 
  57 app = wx.PySimpleApp()
  58 frame = TestFrame()
  59 frame.Show()
  60 app.MainLoop()

Ваш класс renderer должен переопределить три метода базового класса:

Самый важный из этих методов - это метод Draw(grid, attr, dc, rect, row, col, isSelected). Через параметры этого метода передается информация о сетке, в которой нужно нарисовать ячейку. Параметр grid - объект сетки, содержащий эту ячейку. Параметр attr содержит объект атрибутов ячейки. Параметр dc - контекст устройства, чтобы рисовать вы должны использовать его методы. Параметр rect - ограничивающий прямоугольник ячейки в логических координатах. Параметры row и col - координаты ячейки. Параметр isSelected - True, если ячейка в настоящий момент выбрана. В пределах этого метода вы можете делать что хотите. Вы можете вызвать метод базового класса, который рисует фон и устанавливает шрифт и цвет текста.

Второй метод - GetBestSize(grid, attr, dc, row, col). Этот метод возвращает объект wx.Size, который представляет предпочтительный размер ячейки для тех данных, размер которых вы можете вычислить самостоятельно. Параметры grid, attr, dc, row и col аналогичны параметрам метода Draw().

Наконец, вы должны определить метод Clone(), который возвращает объект wx.grid.GridCellRenderer, который должен быть равным вызываемому объекту. Как только renderer определен, Вы можете использовать его точно так же как предопределенный renderer, устанавливая его как renderer для определенных ячеек.

Как редактировать ячейку?

В wxPython сетка позволяет редактировать значения непосредственно в ячейке. Это поведение по умолчанию. Щелкните мышью на ячейке, или начните печатать новое значение, и откроется редактор, который позволит ввести другую строку. В этом разделе, мы обсудим множество способов изменить это поведение по умолчанию.

Вы можете отключить редактирование для всей сетки методом EnableEditing(enable). Если параметр enable - False, то никакая ячейка в сетке не может быть доступной для редактирования. Если редактирование выключено этим методом, то оно не может быть включено для отдельных ячеек. Однако, некоторые ячейки (или строки или столбцы) могут определяться как только для чтения при включенном редактировании для всей сетки. Вы можете определить, доступна ли сетка для редактирования методом IsEditable().

Вы можете установить состояние редактирования для определенной ячейки методом SetReadOnly(row, col, isReadOnly=True). Если параметр isReadOnly – True, то ячейка только для чтения. Значение параметра False делает ячейку доступной для редактирования. Метод SetReadOnly() - аналог метода с тем же названием класса wx.grid.GridCellAttr. Другими словами, вы могли установить признак ячейки только для чтения вот так GetCellAttr(row, col).SetReadOnly(isReadOnly). Преимущество использования механизма атрибутов ячейки состоит в том, что вы можете использовать методы SetRowAttr() и SetColAttr(), чтобы установить целые строки или столбцы как доступные для редактирования или только для чтения.

Вы можете также управлять редактором ячейки программно, используя методы EnableCellEditControl(enable=True) и DisableCellEditControl(), последний метод эквивалентен EnableCellEditControl(False). Метод EnableCellEditControl создаст и покажет редактор в текущей ячейке. Метод DisableCellEditControl скроет редактор в текущей ячейке, сохраняя отредактированные данные. Метод CanEnableCellControl() возвращает True, если сетка является доступной для редактирования и ячейка, не имеет признак только для чтения. Метод IsCellEditControlEnabled() возвращает True, если редактор ячейки активен.

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

Каждая отдельная ячейка имеет свой собственный объект редактора. Вы можете получить ссылку на этот объект редактора методом GetCellEditor(col, row), который возвращает объект класса wx.grid.GridCellEditor. Вы можете установить редактор методом SetCellEditor(row, col, editor), где параметр editor – объект класса wx.grid.GridCellEditor. Вы можете управлять редактором по умолчанию для всей сетки методами GetDefaultEditor() и SetDefaultEditor(editor). Точно так же как renderers, объект редактора хранится в объекте wx.grid.GridCellAttr, связанном с ячейкой, строкой, или столбцом.

Как использовать редактор ячейки?

Как и в случае renderers, wxPython предлагает нескольким стандартных редакторов для различных типов данных, и дает вам возможность определить собственный редактор.

Предопределенные редакторы

Все wxPython редакторы – это подклассы класса wx.grid.GridCellEditor. В таблице 14.5 дано описание стандартных редакторов.

Таблица 14.5 Редакторы ячейки в wxPython

Редактор

Описание

wx.grid.GridCellAutoWrapStringEditor

Использует многострочный редактор для редактирования текстовых данных

wx.grid.GridCellBooleanEditor

Редактор для Булевских данных ячейки, представляет собой переключатель, который пользователь может включить или выключить. Визуально он немного отличается от переключателя, используемого Булевским renderer. Вы не обязаны использовать Булевский renderer, чтобы использовать Булевский редактор. Вы можете отображать данные как 1 или 0 или вкл\выкл.

wx.grid.GridCellChoiceEditor

Редактор для определенного списка опций. При вызове, пользователь видит выпадающий список для выбора. Конструктор принимает параметры (choices, allowOthers=False). Параметр choices - список строк. Если allowOthers - True, тогда пользователь может также напечатать произвольную строку в дополнение к списку.

wx.grid.GridCellEnumEditor

Является производным от wx.grid.GridCellChoiceEditor и управляет соответствием числового значения данных и строки, представленной пользователю.

wx.grid.GridCellFloatEditor

Редактор для ввода чисел с плавающей запятой и определенной точностью. Конструктор принимает параметры (width=-1, precision=-1), где width - минимальное число цифр, чтобы показать все число, и precision - максимальное число цифр после десятичной точки. Числа, введенные этим редактором, преобразуются к соответствующей ширине и точности.

wx.grid.GridCellNumberEditor

Редактор для ввода целых чисел. Конструктор принимает параметры (min=-1, max=-1). Если минимум и максимум установлены, редактор делает проверку диапазона и запрещает вводить числа вне этого диапазона. Если редактор с проверкой диапазона, он использует spinner control, чтобы пользователь мог изменять значения мышью.

wx.grid.GridCellTextEditor

Редактор по умолчанию для ввода строк.

В следующем разделе, мы покажем, как создать собственный редактор ячейки.

Создание собственного редактора ячейки

Вы может понадобиться собственный редактор, чтобы сделать свою обработку введенного значения. Для создания собственного редактора, создайте подкласс класса wx.grid.PyGridCellEditor. Иерархия классов редактора более сложна, чем иерархия renderer. В таблице 14.6 показано несколько методов, которые вы должны переопределить.

Таблица 14.6 Методы PyGridCellEditor, которые вы должны переопределить

Метод

Описание

BeginEdit(row, col, grid)

Параметры row и col - координаты ячейки, и grid – сетка, содержащая ячейку. Этот метод вызывается в начале редактирования. В этом методе осуществляется подготовка к редактированию.

Clone()

Возвращает копию редактора.

Create(parent, id, evtHandler)

Этот метод создает элемент управления, используемый редактором. Параметр parent - содержащий виджет, id – идентификатор, и evtHandler - обработчик событий, связанный с новым элементом управления.

EndEdit(row, col, grid)

Возвращает True, если редактирование изменило значение ячейки. Также здесь производится любая другая необходимая очистка.

Reset()

Вызывается при отмене редактирования. Должен восстановить первоначальное значение.

В таблице 14.7 показаны дополнительные методы родительского класса, который вы можете переопределить, чтобы улучшить поведение или вид вашего редактора.

Таблица 14.7 Методы PyGridCellEditor, которые вы можете переопределить

Метод

Описание

Destroy()

Выполняет заключительную очистку, при удалении объекта редактора.

IsAcceptedKey(evt)

Возвращает True, если клавиша, нажатая в evt используется для запуска редактора. Клавиша F2 всегда запускает редактор. Версия базового класса предполагает, что нажатие любой алфавитно-цифровой клавиши запустит редактор.

PaintBackground(rect, attr)

Принимает два параметра. Параметр rect типа wx.Rect с экранными координатами элемента управления, и параметр attr типа wc.grid.GridCellAttr – атрибуты, связанные с ячейкой. Цель этого метода состоит в том, чтобы рисовать любую часть ячейки, не охваченной редактированием непосредственно. Версия базового класса берет цвет фона из атрибутов и заполняет прямоугольник этим цветом.

SetSize(rect)

Параметр rect – объект wx.Rect с экранными координатами. Используйте этот метод если нужно, чтобы установить редактор в пределах прямоугольника.

Show(show, attr)

Параметр show - Булевское признак показывающий, должен ли редактор быть отображен, параметр attr – объект атрибутов ячейки. Метод вызывается, чтобы показать или скрыть элемент управления.

StartingClick()

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

StartingKey(evt)

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

Когда вы создадите свой редактор, вы можете установить его как редактор для любой ячейки, используя метод SetCellEditor. В листинге 14.8 показан простой редактор, который автоматически преобразует текст, который вы вводите в верхний регистр.

Листинг 14.8 Создание редактора для ввода символов в верхнем регистре

   1 import wx
   2 import wx.grid
   3 import string
   4 
   5 class UpCaseCellEditor(wx.grid.PyGridCellEditor):
   6     def __init__(self):
   7         wx.grid.PyGridCellEditor.__init__(self)
   8 
   9     def Create(self, parent, id, evtHandler):
  10         """
  11         Called to create the control, which must derive from wx.Control.
  12         *Must Override*
  13         """
  14         self._tc = wx.TextCtrl(parent, id, "")
  15         self._tc.SetInsertionPoint(0)
  16         self.SetControl(self._tc)
  17 
  18         if evtHandler:
  19             self._tc.PushEventHandler(evtHandler)
  20 
  21         self._tc.Bind(wx.EVT_CHAR, self.OnChar)
  22 
  23     def SetSize(self, rect):
  24         """
  25         Called to position/size the edit control within the cell rectangle.
  26         If you don't fill the cell (the rect) then be sure to override
  27         PaintBackground and do something meaningful there.
  28         """
  29         self._tc.SetDimensions(rect.x, rect.y, rect.width+2, rect.height+2,
  30                                wx.SIZE_ALLOW_MINUS_ONE)
  31 
  32     def BeginEdit(self, row, col, grid):
  33         """
  34         Fetch the value from the table and prepare the edit control
  35         to begin editing.  Set the focus to the edit control.
  36         *Must Override*
  37         """
  38         self.startValue = grid.GetTable().GetValue(row, col)
  39         self._tc.SetValue(self.startValue)
  40         self._tc.SetInsertionPointEnd()
  41         self._tc.SetFocus()
  42         self._tc.SetSelection(0, self._tc.GetLastPosition())
  43 
  44     def EndEdit(self, row, col, grid):
  45         """
  46         Complete the editing of the current cell. Returns True if the value
  47         has changed.  If necessary, the control may be destroyed.
  48         *Must Override*
  49         """
  50         changed = False
  51 
  52         val = self._tc.GetValue()
  53         
  54         if val != self.startValue:
  55             changed = True
  56             grid.GetTable().SetValue(row, col, val) # update the table
  57 
  58         self.startValue = ''
  59         self._tc.SetValue('')
  60         return changed
  61 
  62     def Reset(self):
  63         """
  64         Reset the value in the control back to its starting value.
  65         *Must Override*
  66         """
  67         self._tc.SetValue(self.startValue)
  68         self._tc.SetInsertionPointEnd()
  69 
  70     def Clone(self):
  71         """
  72         Create a new object which is the copy of this one
  73         *Must Override*
  74         """
  75         return UpCaseCellEditor()
  76 
  77     def StartingKey(self, evt):
  78         """
  79         If the editor is enabled by pressing keys on the grid, this will be
  80         called to let the editor do something about that first key if
  81         desired.
  82         """
  83         self.OnChar(evt)
  84         if evt.GetSkipped():
  85             self._tc.EmulateKeyPress(evt)
  86 
  87     def OnChar(self, evt):
  88         key = evt.GetKeyCode()
  89         if key > 255:
  90             evt.Skip()
  91             return
  92         char = chr(key)
  93         if char in string.letters:
  94             char = char.upper()
  95             self._tc.WriteText(char)
  96         else:
  97             evt.Skip()
  98 
  99 class TestFrame(wx.Frame):
 100     def __init__(self):
 101         wx.Frame.__init__(self, None, title="Grid Editor",
 102                           size=(640,480))
 103 
 104         grid = wx.grid.Grid(self)
 105         grid.CreateGrid(50,50)
 106         grid.SetDefaultEditor(UpCaseCellEditor())
 107 
 108 
 109 app = wx.PySimpleApp()
 110 frame = TestFrame()
 111 frame.Show()
 112 app.MainLoop()

Для справки по методам, используемым в классе редактора, обращайтесь к таблицам 14.6 и 14.7.

Обработка событий

Сетка создает множество событий, которые вы можете обработать. Мы отделим события клавиатуры и события мыши. Это позволит более точно настроить реакцию вашей сетки на события.

Обработка событий мыши

Для сетки, есть несколько различных типов событий мыши, и есть также несколько различных классов событий для этих типов. Обычно используемый класс события - wx.grid.GridEvent. Класс события сетки – это подкласс wx.CommandEvent. Он обеспечивает несколько методов, чтобы получить детальную информацию о событии, как отображено в таблице 14.8.

Таблица 14.8 Методы wx.grid.GridEvent

Метод

Описание

AltDown()

Возвращает True, если при вызове события клавиша alt была нажата.

ControlDown()

Возвращает True, если при вызове события клавиша control была нажата.

GetCol()

Возвращает индекс столбца ячейки, где произошло событие.

GetPosition()

Возвращает объект wx.Point, представляющий координаты в пикселях точки, где произошло событие.

GetRow()

Возвращает индекс строки ячейки, где произошло событие.

MetaDown()

Возвращает True, если при вызове события клавиша meta была нажата.

Selecting()

Возвращает True, если событие – выбор ячейки, и False, если событие - отмена выбора ячейки.

ShiftDown()

Возвращает True, если при вызове события клавиша shift была нажата.

Есть несколько других типов событий, связанных с wx.grid.GridEvent. Они перечислены в таблице 14.9.

Таблица 14.9 Типы событий мыши для ячейки сетки

Тип события

Описание

wx.grid.EVT_GRID_CELL_CHANGE

Возникает, когда пользователь изменяет данные в ячейке через редактор.

wx.grid.EVT_GRID_CELL_LEFT_CLICK

Возникает, когда пользователь выполняет щелчок левой кнопкой мыши в ячейке.

wx.grid.EVT_GRID_CELL_LEFT_DCLICK

Возникает, когда пользователь выполняет двойной щелчок левой кнопкой мыши в ячейке.

wx.grid.EVT_GRID_CELL_RIGHT_CLICK

Возникает, когда пользователь выполняет щелчок правой кнопкой мыши в ячейке.

wx.grid.EVT_GRID_CELL_RIGHT_DCLICK

Возникает, когда пользователь выполняет двойной щелчок правой кнопкой мыши в ячейке.

wx.grid.EVT_GRID_EDITOR_HIDDEN

Возникает, когда редактор ячейки скрыт в конце сеанса редактирования.

wx.grid.EVT_GRID_EDITOR_SHOWN

Возникает, когда редактор ячейки показывается в начале сеанса редактирования.

wx.grid.EVT_GRID_LABEL_LEFT_CLICK

Возникает, когда пользователь выполняет щелчок левой кнопкой мыши в области заголовков столбца или строки.

wx.grid.EVT_GRID_LABEL_LEFT_DCLICK

Возникает, когда пользователь выполняет двойной щелчок левой кнопкой мыши в области заголовков столбца или строки.

wx.grid.EVT_GRID_LABEL_RIGHT_CLICK

Возникает, когда пользователь выполняет щелчок правой кнопкой мыши в области заголовков столбца или строки.

wx.grid.EVT_GRID_LABEL_RIGHT_DCLICK

Возникает, когда пользователь выполняет двойной щелчок правой кнопкой мыши в области заголовков столбца или строки.

wx.grid.EVT_GRID_SELECT_CELL

Возникает, когда пользователь перемещает курсор в новую ячейку, выбирая ее.

Есть еще два типа события wx.grid.GridSizeEvent. Тип события - wx.grid.EVT_GRID_COL_SIZE, возникает, когда изменяется размер столбца, и wx.grid.EVT_GRID_ROW_SIZE, возникает, когда изменяется размер строки. Событие размера сетки имеет пять тех же самых методов как и wx.GridEvent - AltDown(), ControlDown(), GetPosition(), MetaDown() и ShiftDown(). Есть еще метод GetRowOrCol(), который возвращает индекс строки или столбца, в зависимости от типа события.

Есть еще событие wx.grid.GridRangeSelectEvent. Тип события - wx.grid.EVT_GRID_RANGE_SELECT. Оно возникает, когда пользователь выбирает непрерывный блок ячеек. Объект события имеет методы GetBottomRightCoords(), GetBottomRow(), GetLeftCol(), GetRightCol(), GetTopRightCoords() и GetTopRow(). Они возвращают соответствующие индексы строки и столбца выбранного блока. Возвращаемым значением для координатных методов является кортеж (row, col).

И наконец, событие wx.grid.GridEditorCreatedEvent с типом события EVT_GRID_EDITOR_CREATED. Название подразумевает, что событие возникает, когда редактор создан сеансом редактирования. Объект события имеет методы GetCol(), GetRow() и GetControl(), которые возвращают индекс столбца, индекс строки и используемый элемент управления редактирования, соответственно.

Обработка событий клавиатуры

В дополнение к мыши, для навигации по сетке пользователь может использовать клавиатуру. Вы также можете программно изменить положение курсора методами перемещения, перечисленными в таблице 14.10. Многие из методов принимают параметр expandSelection. Этот параметр работает одинаково в каждом методе. Если параметр - True, текущий выбор будет изменен так, чтобы включить новую позицию курсора. Если параметр - False, текущий выбор будет заменен новым курсором.

Таблица 14.10 Методы перемещения курсора сетки

Метод

Описание

MoveCursorDown(expandSelection)

Перемещает курсор вниз. Метод эквивалентен нажатию клавиши «стрелка вниз» (если expandSelection=False) или shift-стрелка вниз (если expandSelection=True).

MoveCursorDownBlock(expandSelection)

Перемещает курсор на одну ячейку ниже выбранного блока. Метод эквивалентен нажатию ctrl-down (если expandSelection=False) или shift-ctrl-down (если expandSelection=True).

MoveCursorLeft(expandSelection)

Перемещает курсор влево. Метод эквивалентен нажатию клавиши «стрелка влево» (если expandSelection=False) или shift-стрелка влево (если expandSelection=True).

MoveCursorLeftBlock(expandSelection)

Перемещает курсор на одну ячейку левее выбранного блока. Метод эквивалентен нажатию ctrl-left (если expandSelection=False) или shift-ctrl-left (если expandSelection=True).

MoveCursorRight(expandSelection)

Перемещает курсор вправо. Метод эквивалентен нажатию клавиши «стрелка вправо» (если expandSelection=False) или shift-стрелка вправо (если expandSelection=True).

MoveCursorRightBlock(expandSelection)

Перемещает курсор на одну ячейку правее выбранного блока. Метод эквивалентен нажатию ctrl-right (если expandSelection=False) или shift-ctrl-right (если expandSelection=True).

MoveCursorUp(expandSelection)

Перемещает курсор вверх. Метод эквивалентен нажатию клавиши «стрелка вверх» (если expandSelection=False) или shift-стрелка вверх (если expandSelection=True).

MoveCursorUpBlock(expandSelection)

Перемещает курсор на одну ячейку выше выбранного блока. Метод эквивалентен нажатию ctrl-up (если expandSelection=False) или shift-ctrl-up (если expandSelection=True).

MovePageDown()

Перемещает курсор вниз так, что ячейки нижней строки перемещаются в верхнюю строку.

MovePageUp()

Перемещает курсор вверх так, что ячейки верхней строки перемещаются в нижнюю строку.

Мы рассказали почти все из того, что вы должны знать о сетках. В следующей главе, мы займемся следующим виджетом – деревом (tree control).

Резюме

Перевод: Володеев Сергей

Книги/WxPythonInAction/Работа с сеткой (grid control) (последним исправлял пользователь alafin 2010-05-30 09:28:37)