Версия 4 от 2010-05-26 05:47:16

Убрать это сообщение

Работа с основными элементами управления

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

Инструментарий wxPython предоставляет множество различных виджетов, включая базовые элементы управления, являющиеся темой этой главы. Мы исследуем начальный набор виджетов, содержащий следующие элементы управления: статический текст, редактируемый текст, кнопки, счетчики (spinners), ползунки (slider), флажки (check box), переключатели (radio button), списки (list box), выпадающие списки (choice), комбинированные списки (combo box) и индикаторы прогресса (gauge). Для каждого виджета мы покажем короткий пример его использования, сопровождаемый описанием важных частей API wxPython.

Вывод текста

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

Как вывести статический текст?

Возможно, основная задача любого пакета для разработки интерфейса пользователя состоит в рисовании на экране простого текста. В wxPython это выполняется на базе класса wx.StaticText. Рисунок 7.1 отображает статические текстовые элементы.

В wx.StaticText Вы можете изменять выравнивание, шрифт и цвет текста. Отдельный виджет статического текста может содержать многострочный текст, однако, он не может управлять множеством шрифтов или стилей. Для поддержки множества шрифтов или стилей используйте более сложный текстовый элемент управления, например, wx.html.HTMLWindow, описываемый в главе 16. Для того, чтобы отображать множество строк внутри статического текстового поля, включите в него строку с символами новой строки и сделайте элемент достаточно большим, чтобы отображать весь текст. Единственная особенность, которая не видна на рисунке, состоит в том, что окно wx.StaticText никогда не получает и не реагирует на события мыши, и оно никогда не получает фокус ввода.

Рисунок 7.1 Примеры виджетов wx.StaticText с изменением шрифта, выравнивания и цвета

Вывод статического текста

Листинг 7.1 показывает текст программы, соответствующий рисунку 7.1

Листинг 7.1 Базовый пример использования статического текста

   1 import wx
   2 class StaticTextFrame(wx.Frame):
   3     def __init__(self):
   4          wx.Frame.__init__(self, None, -1, 'Static Text Example',
   5                   size=(400, 300))
   6          panel = wx.Panel(self, -1)
   7          wx.StaticText(panel, -1, "This is an example of static text",
   8                   (100, 10))
   9          rev = wx.StaticText(panel, -1,
  10                   "Static Text With Reversed Colors",
  11                   (100, 30))
  12          rev.SetForegroundColour('white')
  13          rev.SetBackgroundColour('black')
  14          center = wx.StaticText(panel, -1,
  15                   "align center", (100, 50),
  16                   (160, -1), wx.ALIGN_CENTER)
  17          center.SetForegroundColour('white')
  18          center.SetBackgroundColour('black')
  19          right = wx.StaticText(panel, -1,
  20                   "align right", (100, 70),
  21                   (160, -1), wx.ALIGN_RIGHT)
  22          right.SetForegroundColour('white')
  23          right.SetBackgroundColour('black')
  24          str = "You can also change the font."
  25          text = wx.StaticText(panel, -1, str, (20, 100))
  26          font = wx.Font(18, wx.DECORATIVE,
  27                  wx.ITALIC, wx.NORMAL)
  28          text.SetFont(font)
  29          wx.StaticText(panel, -1,
  30                   "Your text\ncan be split\n"
  31                   "over multiple lines\n\neven blank ones", (20,150))
  32          wx.StaticText(panel, -1,
  33                   "Multi-line text\ncan also\n"
  34                   "be right aligned\n\neven with a blank", (220,150),
  35                   style=wx.ALIGN_RIGHT)
  36 if __name__ == '__main__':
  37     app = wx.PySimpleApp()
  38     frame = StaticTextFrame()
  39     frame.Show()
  40     app.MainLoop()
  41 Конструктор для wx.StaticText идентичен базовым конструкторам wxWidget:
  42  wx.StaticText(parent, id, label, pos=wx.DefaultPosition,
  43           size=wx.DefaultSize, style=0, name="staticText")

Конструктор для wx.StaticText идентичен базовым конструкторам wxWidget:

   1 wx.StaticText(parent, id, label, pos=wx.DefaultPosition,
   2          size=wx.DefaultSize, style=0, name="staticText")

Таблица 7.1 показывает назначение его параметров - подобный набор параметров в своих конструкторах имеет большинство виджетов wxPython. За детальным описанием параметров конструктора обращайтесь к обсуждению виджетов в главе 2.

Таблица 7.1 Параметры конструктора wx.StaticText

Параметр

Назначение

parent

Виджет, вмещающий данный статический текст

id

Идентификатор wxPython. Для автоматического создания уникального идентификатора необходимо использовать значение -1.

label

Текст, который необходимо отобразить

pos

Позиция виджета на базе объекта wx.Point или кортеж (tuple) Python

size

Размер создаваемого виджета на базе объекта wx.Size или кортеж (tuple) Python

style

Флаг стиля

name

Имя объекта, используемое при поиске

В следующем разделе мы подробно обсудим стилевые флаги.

Работа со стилями

Все методы, вызываемые для экземпляров статического текста в листинге 7.1, принадлежат родительскому классу wx.Window; wx.StaticText не определяет каких-либо новых собственных методов. Несколько характерных для wx.StaticText стилевых флагов указаны в таблице 7.2.

Таблица 7.2 Стилевые флаги класса wx.StaticText

Стиль

Описание

wx.ALIGN_CENTER

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

wx.ALIGN_LEFT

Выравнивание текста виджета слева. Этот стиль установлен по умолчанию.

wx.ALIGN_RIGHT

Выравнивание текста виджета справа.

wx.ST_NO_AUTORESIZE

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

Элемент управления wx.StaticText перекрывает метод SetLabel() для изменения своих размеров на основании нового текста, что происходит, если не установлен стиль wx.ST_NO_AUTORESIZE.

При создании однострочного поля статического текста с центрированием или выравниванием справа, Вы должны явно устанавливать в конструкторе размер этого поля. Определение размера сдерживает wxPython от автоматического изменения размеров элемента управления. В wxPython размер по умолчанию соответствует минимальному окружающему текст прямоугольнику. Так как по умолчанию размер текстового поля никак не больше размещенного в нем текста и при отображении выравнивания пустого пространства не образуется, не имеет значения выравнено ли поле слева, справа или по центру. Для того чтобы при выполнении программы изменять текст в виджете динамически без изменения размера поля, установите стиль wx.ST_NO_AUTORESIZE. Это не даёт виджету после изменения текста привести свои размеры к минимальному прямоугольнику. Если статический текст размещается внутри динамической формы, изменение его размера может переместить на экране другие виджеты, отвлекая при этом внимание пользователя.

Другие приёмы вывода текста

Имеются и другие способы размещения статического текста на Вашем экране. Во-первых, можно использовать класс wx.lib.stattext.GenStaticText, который представляет собой видоизмененную Python- реализацию класса wx.StaticText. Он более согласован в кросс-платформенном плане, чем стандартная версия C++, и он принимает события мыши. Он также предпочтителен, когда Вам необходим подкласс при создании собственного статического текстового элемента управления.

Вы можете рисовать текст непосредственно в Вашем контексте устройства при помощи метода DrawText(text, x, y) или метода DrawRotatedText(text, x, y, angle). Последний является простейшим способом вывести текст под углом, хотя имеется также управляющий вращением подкласс GenStaticText. Контексты устройства были кратко рассмотрены в главе 6 и будут рассмотрены более подробно в главе 12.

Как обеспечить пользователя возможностью ввода текста?

Вслед за простым выводом статического текста, мы начинаем обсуждение взаимодействия пользователя при вводе текста. Класс wxPython wx.TextCtrl используется в качестве виджета для текстового ввода и допускает как однострочный, так и многострочный ввод. Он может также реализовывать парольный ввод, маскируя нажимаемые клавиши. Если платформа поддерживает, то wx.TextCtrl обеспечивает также расширенный текстовый вывод (rich text) с многочисленными текстовыми стилями. Рисунок 7.2 показывает пример wx.TextCtrl в качестве однострочного элемента управления, как с маскированием пароля, так и без него.

Рисунок 7.2 Примеры однострочных текстовых полей, простого и парольного

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

Как это сделать Листинг 7.2 содержит код, который генерирует рисунок 7.2.

Листинг 7.2 Пример однострочного wx.TextCtrl

   1 import wx
   2 class TextFrame(wx.Frame):
   3     def __init__(self):
   4         wx.Frame.__init__(self, None, -1, 'Text Entry Example',
   5                  size=(300, 100))
   6         panel = wx.Panel(self, -1)
   7         basicLabel = wx.StaticText(panel, -1, "Basic Control:")
   8         basicText = wx.TextCtrl(panel, -1, "I've entered some text!",
   9                  size=(175, -1))
  10         basicText.SetInsertionPoint(0)
  11         pwdLabel = wx.StaticText(panel, -1, "Password:")
  12         pwdText = wx.TextCtrl(panel, -1, "password", size=(175, -1),
  13                  style=wx.TE_PASSWORD)
  14         sizer = wx.FlexGridSizer(cols=2, hgap=6, vgap=6)
  15         sizer.AddMany([basicLabel, basicText, pwdLabel, pwdText])
  16         panel.SetSizer(sizer)
  17 if __name__ == '__main__':
  18     app = wx.PySimpleApp()
  19     frame = TextFrame()
  20     frame.Show()
  21     app.MainLoop()

Конструктор класса wx.TextCtrl несколько сложнее, чем у его родительского класса wx.Window, к нему добавлены два аргумента:

   1    wx.TextCtrl(parent, id, value = "", pos=wx.DefaultPosition,
   2         size=wx.DefaultSize, style=0, validator=wx.DefaultValidator
   3         name=wx.TextCtrlNameStr)

Аргументы parent, id, pos, size, style и name идентичны аргументам конструктора wx.Window. Аргумент value является начальным значением отображаемого в поле текста.

Аргумент validator (верификатор) используется классом wx.Validator. Верификатор часто используется для фильтрации данных, что гарантирует ввод в элемент управления только допустимых данных. Верификаторы подробно обсуждаются в главе 9.

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

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

Таблица 7.3 Стилевые флаги однострочного класса wx.TextCtrl

Стиль

Описание

wx.TE_CENTER

Текст внутри элемента управления центрируется.

wx.TE_LEFT

Текст внутри элемента управления выравнивается слева. Это поведение по умолчанию.

wx.TE_NOHIDESEL

Если Вам трудно расшифровать эту опцию, то она читается так: "не скрывать выделение". Эта опция Windows перекрывает стандартное поведение текстового виджета Windows, то есть, если виджет не имеет фокуса, выбранный текст выделяется. При выборе данной опции текст виджета будет всегда выделен. На других системах такого эффекта не будет.

wx.TE_PASSWORD

Вводимый текст не отображается, вместо этого он маскируется звездочками.

wx.TE_PROCESS_ENTER

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

wx.TE_PROCESS_TAB

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

wx.TE_READONLY

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

wx.TE_RIGHT

Текст внутри элемента управления выравнивается справа.

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

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

■ <ctrl-x> вырезать

■ <ctrl-c> копировать

■ <ctrl-v> вставить

■ <ctrl-z> отменить

Как изменить текст без ввода со стороны пользователя?

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

Таблица 7.4 Методы обработки текста wx.TextCtrl

Метод

Описание

AppendText(text)

Добавляет текстовый аргумент в конец текстового элемента управления. Позиция ввода перемещается на конец элемента управления.

Clear()

Сбрасывает текстовое значение элемента управления в "". Вызывает генерацию события обновления текста.

EmulateKeyPress(event)

Данное событие нажатия клавиши вставляет в элемент управления связанный с этим событием символ, имитируя тем самым фактическое нажатие.

GetInsertionPoint() SetInsertionPoint(pos) SetInsertionPointEnd()

Получение или установка целочисленного индекса текущей позиции ввода, или другими словами, индекса, где размещается следующий вставляемый символ. Начало элемента управления имеет индекс 0.

GetRange(from, to)

Возвращает строку между указанными целыми позициями элемента управления.

GetSelection() GetStringSelection() SetSelection(from, to)

GetSelection() возвращает кортеж (start, end) с индексами выделенного в данный момент текста. GetStringSelection() возвращает выделенную строку текста. Метод SetSelection(from, to) устанавливает выделение по его конечным точкам.

GetValue() SetValue(value)

Метод SetValue() изменяет значение элемента управления целиком. GetValue() возвращает целиком всю его строку.

Remove(from, to)

Удаляет указанный диапазон текста.

Replace(from, to, value)

Замещает указанный диапазон новым значением. Это может изменить длину текста.

WriteText(text)

Аналогичен методу AppendText(), за исключением того, что новый текст помещается в текущую позицию ввода.

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

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

При помощи стилевого флага wx.TE_MULTILINE Вы можете создать многострочный текстовый элемент управления. Если виджет поддерживает стили, Вы можете изменить стили шрифта и цвета в тексте этого элемента управления (иногда его называют расширенным текстом - rich text). На других платформах вызовы, которые устанавливают стили, просто игнорируются. Рисунок 7.3 отображает пример многострочных текстовых элементов управления.

Листинг 7.3 содержит код, использованный для создания рисунка 7.3. Обычно, создание многострочного элемента управления управляется установкой стилевого флага wx.TE_MULTILINE. Далее в этом разделе мы обсудим использование стилей расширенного текста.

Рисунок 7.3 Примеры многострочных текстовых полей, простого и с расширенным текстом

Листинг 7.3 Создание многострочного текстового элемента управления

   1 import wx
   2 class TextFrame(wx.Frame):
   3     def __init__(self):
   4         wx.Frame.__init__(self, None, -1, 'Text Entry Example',
   5                      size=(300, 250))
   6         panel = wx.Panel(self, -1)
   7         multiLabel = wx.StaticText(panel, -1, "Multi-line")
   8         multiText = wx.TextCtrl(panel, -1,                                         # Создание текстового поля
   9                    "Here is a looooooooooooooong line "
  10                    "of text set in the control.\n\n"
  11                    "See that it wrapped, and that "
  12                    "this line is after a blank",                          
  13         size=(200, 100), style=wx.TE_MULTILINE)
  14         multiText.SetInsertionPoint(0)                                             # Установка позиции курсора
  15         richLabel = wx.StaticText(panel, -1, "Rich Text")                          # Создание расширенного текста
  16         richText = wx.TextCtrl(panel, -1,
  17                    "If supported by the native control, "
  18                    "this is reversed, and this is a different font.",
  19                    size=(200, 100),
  20                    style=wx.TE_MULTILINE|wx.TE_RICH2)
  21                                                  
  22         richText.SetInsertionPoint(0)
  23         richText.SetStyle(44, 52, wx.TextAttr("white", "black"))                    # Установка текстовых стилей
  24         points = richText.GetFont().GetPointSize()
  25         f = wx.Font(points + 3, wx.ROMAN,
  26             wx.ITALIC, wx.BOLD, True)                                               #  Создание шрифта
  27         richText.SetStyle(68, 82, wx.TextAttr("blue",        
  28             wx.NullColour, f))                                                      # Установка стиля нового шрифта
  29         sizer = wx.FlexGridSizer(cols=2, hgap=6, vgap=6)
  30         sizer.AddMany([multiLabel, multiText, richLabel, richText])
  31         panel.SetSizer(sizer)
  32 if __name__ == '__main__':
  33     app = wx.PySimpleApp()
  34     frame = TextFrame()
  35     frame.Show()
  36     app.MainLoop()

Использование стилей расширенного текста

Кроме wx.TE_MULTILINE имеются и другие стилевые флаги, которые имеют значение в контексте многострочного или расширенного текстового элемента управления. Таблица 7.5 перечисляет эти стили окна.

Таблица 7.5 Стилевые биты многострочного wx.TextCtrl

Стиль

Описание

wx.HSCROLL

Если текстовый элемент управления многострочный и указан этот флаг, длинные строки вместо переноса будут горизонтально прокручиваться. В GTK+ эта опция игнорируется.

wx.TE_AUTO_URL

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

wx.TE_DONTWRAP

Другое имя для wx.HSCROLL.

wx.TE_LINEWRAP

Противопоставлен флагу wx.TE_WORDWRAP. Длинные строки могут быть разорваны для переноса на любом символе. Некоторые операционные системы игнорируют этот флаг.

wx.TE_MULTILINE

Текстовый элемент управления будет отображать множество строк.

wx.TE_RICH

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

wx.TE_WORDWRAP

Противопоставлен флагу wx.TE_LINEWRAP. Требующие переноса строки будут разорваны на границе слова. На многих системах эта опция игнорируется.

Помните, что стилевые флажки могут быть объединены, например, многострочное поле расширенного текста в последнем примере объявлено со стилем wx.TE_MULTILINE | wx.TE_RICH2. Использующиеся в виджете wx.TextCtrl текстовые стили являются экземплярами класса wx.TextAttr. Отдельный экземпляр wx.TextAttr включает цвет текста, цвет фона и шрифт, определяемые в конструкторе следующим образом:

   1     wx.TextAttr(colText, colBack=wx.NullColor, font=wx.NullFont)

Цвета текста и фона являются объектами wxPython типа wx.Color и могут определяться при помощи строки идентификатора цвета или кортежа со значениями цветовых составляющих (красный, зеленый, синий). Значение wx.NullColor указывает, что будет использован существующий цвет фона элемента управления. Шрифт представлен объектом wx.Font и будет рассмотрен в следующем разделе. Объект wx.NullFont указывает на то, что должен быть использован установленный по умолчанию текущий шрифт.

Класс wx.TextAttr имеет методы для получения атрибутов текста GetBackgroundColour(), GetFont(), GetTextColour(), а также логические методы существования HasBackgroundColour(), HasFont() и HasTextColour(). Если атрибут содержит значение по умолчанию, методы существования возвращают False. Метод IsDefault() возвращает True, если значение по умолчанию содержат все три атрибута. Поскольку экземпляры wx.TextAttr являются неизменяемыми, класс wx.TextAttr не имеет методов установки. Чтобы изменить стиль текста, Вы должны создать его экземпляр.

Для того, чтобы использовать текстовый стиль, вызовите метод SetDefaultStyle(style) или SetStyle(start, end, style). Первый метод устанавливает текущий стиль элемента управления. После этого любой вставляемый в элемент управления текст, как путём набора, так и при помощи методов AppendText() или WriteText(), будет отображен в данном стиле. Если какой-либо из атрибутов стиля имеет значение по умолчанию, текущая величина этого стиля сохраняется. Однако если значение по умолчанию имеют все атрибуты стиля, восстанавливается стиль по умолчанию. Метод SetStyle() аналогичен, но воздействует на текст непосредственно между позициями start и end. Атрибуты по умолчанию в аргументе стиля определяются путем проверки в элементе управления текущего стиля по умолчанию. Листинг 7.3 использует следующую строчку кода для назначения определенных цветов нескольким символам текста:

   1     richText.SetStyle(44, 52, wx.TextAttr("white", "black"))

Цвет фона становится белым, а цвет текста для этих символов становится черным.

Таблица 7.6 перечисляет методы wx.TextCtrl, которые полезны при работе с многострочными элементами управления и расширенным текстом.

Таблица 7.6 Методы wx.TextCtrl для многострочного и стилизованного текста

Метод

Описание

GetDefaultStyle() SetDefaultStyle(style)

Смотрите начало этого раздела с описанием встроенных стилей.

GetLineLength(lineNo)

Возвращает целую длину указанной строки.

GetLineText(lineNo)

Возвращает текст указанной строки.

GetNumberOfLines()

Возвращает число строк в элементе управления. Для однострочных возвращает 1.

IsMultiLine() IsSingleLine()

Булевые методы для определения состояния элемента управления.

PositionToXY(pos)

Для заданной целой позиции внутри текста возвращает кортеж (столбец, строка) индексов позиции. Столбец и строка индексируются, начиная с 0.

SetStyle(start, end, style)

Изменяет стиль указанного диапазона текста.

ShowPosition(pos)

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

XYToPosition(x, y)

Противоположный методу PositionToXY — для указанных столбца и строки возвращает целую позицию.

Работа со стилями становится более гибкой, если в своей системе Вы можете использовать произвольные шрифты. Далее мы покажем Вам, как создавать и использовать экземпляры шрифтов.

Как создать шрифт?

Шрифты определены как экземпляры класса wx.Font. Вы имеете доступ к любому шрифту, который установлен и доступен в Вашей системе. Для того чтобы создать экземпляр шрифта, используйте следующий конструктор:

   1 wx.Font(pointSize, family, style, weight, underline=False,
   2     faceName="", encoding=wx.FONTENCODING_DEFAULT)

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

Таблица 7.7 Образцы существующих семейств шрифтов

Шрифт

Описание

wx.DECORATIVE

Формальный старо-английский стиль шрифта

wx.DEFAULT

Системный шрифт по умолчанию

wx.MODERN

Моноширинный шрифт (с фиксированным шагом)

wx.ROMAN

Шрифт с засечками, обычно приблизительно похож на Times New Roman

wx.SCRIPT

Прописной или рукописный шрифт

wx.SWISS

Шрифт sans-serif , обычно приблизительно соответствует Helvetica или Arial.

Параметр style указывает характер наклона шрифта: wx.NORMAL, wx.SLANT или wx.ITALIC. Аналогично, параметр weight (вес) указывает толщину шрифта: wx.NORMAL, wx.LIGHT или wx.BOLD. Константы ведут себя здесь, как это следует из их имени. Параметр underline (подчеркивание) работает только в системах Windows, и если он установлен в True, шрифт необходимо подчеркивать. Используйте аргумент faceName, чтобы указать системное имя отображаемого Вами шрифта.

Параметр encoding позволяет Вам выбрать тот или иной вариант кодирования, который соотносит внутренние символы и шрифт дисплейных символов. Данное кодирование не является кодированием Unicode, это просто другое применяемое в wxPython 8-битовое кодирование. В большинстве случаев Вам достаточно использовать кодирование по умолчанию.

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

   1 wx.FontEnumerator:
   2    e = wx.FontEnumerator()
   3    e.EnumerateFacenames()
   4    fontList = e.GetFacenames()

Для ограничения списка по ширине, измените первую строку на:

   1 e = wx.FontEnumerator(fixedWidth=True).

Можно ли стилизировать текст, если платформа не поддерживает расширенный текст (rich text)?

Да. В wxPython имеется кросс-платформенный виджет стилизованного текста, называющийся wx.stc.StyledTextCtrl, который является надстройкой к компоненту расширенного текста Scintilla. Поскольку Scintilla не является частью wxWidgets и представляет собой включенный в wxPython отдельный независимый компонент, он не имеет такого же API, как и у рассмотренных нами классов.

Детальное обсуждение wx.stc.StyledCtrl выходит за рамки нашей книги, тем не менее, Вы можете найти соответствующую документацию по адресу:

http://wiki.wxpython.org/index.cgi/wxStyledTextCtrl

Что если мой текстовый элемент управления не подходит для моей строки?

Применяя многострочный виджет wx.TextCtrl, Вы должны иметь элементарное представление относительно способа, которым текстовый элемент управления хранит строку текста. Многострочный текст в wx.TextCtrl хранится, используя в качестве разделителя строк символ \n. Даже если некоторые системы в качестве разделителя строк используют другие символьные комбинации, такой способ реально независим от типа используемой операционной системы. Когда Вы извлекаете строку методом GetValue(), системный разделитель строк восстанавливается и Вам не нужно беспокоиться об обратном ручном преобразовании. Преимущество данного способа состоит в том, что текст внутри элемента управления не зависит от каких-либо особенностей операционной системы.

Недостаток состоит в том, что длина строки и индексы внутри и за пределами текстового элемента управления могут отличаться. Например, если вы имеете дело с системой Windows, где в качестве разделителя строки применяется \r\n, длина строки, возвращенной методом GetValue(), будет длиннее, чем сообщаемый методом GetLastPosition() конец строки в элементе управлении.

Добавляя следующие две строки в листинг 7.3,

   1 print "getValue", len(multiText.GetValue())
   2 print "lastPos", multiText.GetLastPosition()

мы получим следующий результат в системе Unix:

   1 getValue 119
   2 lastPos 119

и следующий результат в системе Windows:

   1 getValue 121
   2 lastPos 119

Смысл в том, что для обратной ссылки на оригинальную строку Вы не должны использовать позиционные индексы многострочного текстового элемента управления, они должны использоваться только как аргументы в других методах wx.TextCtrl. Для подстроки текста внутри элемента управления используйте методы GetRange() или GetSelectedText(). К тому же, не пересекайте индексы при перестановке (реверсировании); не используйте индексы оригинальной строки для обратной ссылки в текстовый элемент управления.

Ниже приведен пример неправильного способа получения 10 символов, следующих за позицией ввода:

   1 aLongString = """Any old
   2     multi line string
   3     will do here.
   4     Just as long as
   5     it is multiline"""
   6 text = wx.TextCtrl(panel, -1, aLongString, style=wx.TE_MULTILINE)
   7 x = text.GetInsertionPoint()
   8 selection = aLongString[x : x + 10] ### ЭТО НЕПРАВИЛЬНО

Последняя строка должна быть снабжена комментарием для систем Windows или Mac, поскольку она использует x (позиция точки ввода текстового поля) в качестве индекса оригинальной строки. Для того чтобы вернуть правильные символы в системах Windows или Mac, последняя строка должна быть записана следующим образом:

   1     selection = text.GetRange(x, x + 10)

Как реагировать на события обработки текста?

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

   1 frame.Bind(wx.EVT_TEXT, frame.OnText, text)

Таблица 7.8 описывает командные события.

Таблица 7.8 События виджетов wx.TextCtrl

Событие

Описание

EVT_TEXT

Генерируется при изменении текста элемента управления. Это событие генерируется как в ответ на ввод пользователя, так и при программном изменении текста методом SetValue().

EVT_TEXT_ENTER

Генерируется при установленном стиле wx.TE_PROCESS_ENTER, в случае нажатия пользователем в элементе управления клавиши Enter.

EVT_TEXT_URL

Это событие вырабатывается на системах Windows при установленных стилях wx.TE_RICH или wx.TE_RICH2, а также установленном стиле wx.TE_AUTO_URL в случае, когда происходит событие мыши над URL в тексте элемента управления.

EVT_TEXT_MAXLEN

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

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

Работа с кнопками

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

Как создать кнопку?

В части 1 мы уже рассматривали несколько примеров кнопок, поэтому здесь мы только кратко изложим их основы. Рисунок 7.4 показывает простую кнопку.

Рисунок 7.4 Пример простой кнопки

Принцип использования кнопки очень прост. Листинг 7.4 содержит код этого простого примера кнопки.

Листинг 7.4 Создание и отображение простой кнопки

   1 import wx
   2 class ButtonFrame(wx.Frame):
   3     def __init__(self):
   4          wx.Frame.__init__(self, None, -1, 'Button Example',
   5                   size=(300, 100))
   6          panel = wx.Panel(self, -1)
   7          self.button = wx.Button(panel, -1, "Clicked", pos=(50, 20))
   8          self.Bind(wx.EVT_BUTTON, self.OnClick, self.button)
   9          self.button.SetDefault()
  10     def OnClick(self, event):
  11          self.button.SetLabel("Clicked")
  12 if __name__ == '__main__':
  13     app = wx.PySimpleApp()
  14     frame = ButtonFrame()
  15     frame.Show()
  16     app.MainLoop()

Конструктор wx.Button подобен конструкторам, которые мы уже видели ранее:

   1    wx.Button(parent, id, label, pos, size=wxDefaultSize, style=0,
   2             validator, name="button")

Характерный для wx.Button аргумент label представляет собой отображаемый на кнопке текст. Он может быть изменен при выполнении программы методом SetLabel(), а получен методом GetLabel(). Два других полезных метода - который возвращает предложенный системой встроенный GetDefaultSize(), размер кнопки (полезен для согласования фреймов по ширине), и SetDefault(), который указывает, что данная кнопка диалога или фрейма будет кнопкой по умолчанию. Кнопка по умолчанию часто выглядит иначе чем другие кнопки и когда диалог имеет фокус, обычно активируется нажатием клавиши Enter.

Класс wx.Button имеет один кросс-платформенный флаг стиля wx.BU_EXACTFIT. Если он указан, кнопка не использует в качестве минимального размера системный размер по умолчанию, а вместо этого уменьшает свой размер к минимально допустимому размеру для вписывания надписи. Если виджетом поддерживается, то Вы можете изменять выравнивание надписи внутри кнопки при помощи флагов wx.BU_LEFT, wx.BU_RIGHT, wx.BU_TOP и wx.BU_BOTTOM. Каждый флаг выравнивает надпись точно по той стороне, которая как Вы понимаете, указана в имени флага. В части 1 мы увидели, что wx.Button инициирует при нажатии одно командное событие типа EVT_BUTTON.

Как создать кнопку с битовым изображением?

Иногда необходимо изобразить на кнопке вместо надписи некоторую картинку, например, как на рисунке 7.5.

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

Рисунок 7.5 Демонстрация кнопок с изображением. Левая кнопка имеет эффект 3D.

   1 import wx
   2 class BitmapButtonFrame(wx.Frame):
   3     def __init__(self):
   4         wx.Frame.__init__(self, None, -1, 'Bitmap Button Example',
   5                 size=(200, 150))
   6         panel = wx.Panel(self, -1)
   7         bmp = wx.Image("bitmap.bmp",
   8             wx.BITMAP_TYPE_BMP).ConvertToBitmap()
   9         self.button = wx.BitmapButton(panel, -1, bmp, pos=(10, 20))
  10         self.Bind(wx.EVT_BUTTON, self.OnClick, self.button)
  11         self.button.SetDefault()
  12         self.button2 = wx.BitmapButton(panel, -1, bmp, pos=(100, 20),
  13             style=0)
  14         self.Bind(wx.EVT_BUTTON, self.OnClick, self.button2)
  15     def OnClick(self, event):
  16         self.Destroy()
  17 if __name__ == '__main__':
  18     app = wx.PySimpleApp()
  19     frame = BitmapButtonFrame()
  20     frame.Show()
  21     app.MainLoop()

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

Кнопки с битовыми изображениями имеют две интересных возможности. Во-первых, это установленный по умолчанию стилевой флаг wx.BU_AUTODRAW. Если этот флаг установлен, битовое изображение кнопки будет окружено 3D-границей, что сделает её похожей на текстовую кнопку (левая кнопку на рисунке 7.5), и кнопка будет на несколько пикселей больше, чем оригинальное битовое изображение. Если этот флаг выключен, битовое изображение будет нарисовано просто как кнопка без границы. У правой кнопки на рисунке 7.5 style=0, что снимает установку по умолчанию, и у неё нет объемного эффекта 3D.

Просто передайте wxPython битовое изображение для основного экрана, и wxPython автоматически создаст стандартные производные битовых изображений для нажатой кнопки, кнопки имеющей фокус и блокированной кнопки. Если стандартное поведение Вас не устраивает, Вы можете явно указать wxPython необходимые битовые изображения следующими методами: SetBitmapDisabled(), SetBitmapFocus(), SetBitmapLabel() и SetBitmapSelected(). Каждый из этих методов получает объект wx.Bitmap, и вместе с тем имеются соответсвующие функции чтения назначенных битовых изображений.

Используя стандартную C++ библиотеку wxWidgets, Вы не можете комбинировать битовое изображение и текст. У Вас имеется единственная возможность создать битовое изображение, содержащее текст. Тем не менее, как мы увидим при обсуждении типовой кнопки, в wxPython имеется дополнительная возможность, которая разрешает эту проблему.

Как создать кнопку-переключатель?

Вы можете создать кнопку-переключатель при помощи класса wx.ToggleButton. Кнопка-переключатель выглядит точно также, как и текстовая кнопка, но ведет себя подобно флажку (checkbox), поскольку она даёт визуальное восприятие выбранного или невыбранного состояния. Другими словами, когда Вы нажимаете кнопку-переключатель, она показывает свое состояние, оставаясь на вид нажатой, пока Вы снова её не щелкнете.

Имеется всего два различия между wx.ToggleButton и его родительским классом wx.Button:

Кнопки-переключатели могут представлять полезную и привлекательную альтернативу переключателям-флажкам (checkbox), особенно в инструментальных панелях. Помните, что используя готовые объекты wxWidgets, у Вас нет возможноти объединить кнопку-переключатель и кнопку с битовым изображением, но wxPython имеет обеспечивающий это поведение класс типовой кнопки, который мы опишем в следующем разделе.

Что такое типовая (generic) кнопка и почему её необходимо использовать?

Типовая кнопка является кнопочным виджетом, который полностью воспроизведен на Python, игнорируя использование стандартного системного виджета. Общим для кнопок с битовым изображением и кнопок-переключателей выступает родительский класс GenButton из модуля wx.lib.buttons.

Для использования типовых кнопок имеется несколько причин:

Рисунок 7.6 показывает типовую кнопку в работе.

Листинг 7.6 содержит код для рисунка 7.6. Второй оператор импорта – import wx.lib.buttons as buttons – делает доступными классы общих кнопок.

Рисунок 7.6 Типовые кнопки. Верхняя строка содержит для сравнения обычные кнопки. Показаны различные сочетания цветов, кнопка с битовым изображением, кнопка-переключатель с битовым изображением и кнопка с текстом и битовым изображением

Листинг 7.6 Создание и использование типовых кнопок wxPython

   1 import wx
   2 import wx.lib.buttons as buttons
   3 class GenericButtonFrame(wx.Frame):
   4     def __init__(self):
   5         wx.Frame.__init__(self, None, -1, 'Generic Button Example',
   6                 size=(500, 350))
   7         panel = wx.Panel(self, -1)
   8         sizer = wx.FlexGridSizer(1, 3, 20, 20)
   9         b = wx.Button(panel, -1, "A wx.Button")
  10         b.SetDefault()
  11         sizer.Add(b)
  12         b = wx.Button(panel, -1, "non-default wx.Button")
  13         sizer.Add(b)
  14         sizer.Add((10,10))
  15                                                       
  16         b = buttons.GenButton(panel, -1, 'Generic Button')            # Базовая типовая кнопка
  17         sizer.Add(b)
  18         b = buttons.GenButton(panel, -1, 'disabled Generic')          # Блокированная типовая кнопка
  19         b.Enable(False)                    
  20         sizer.Add(b)                       
  21         b = buttons.GenButton(panel, -1, 'bigger')                    # Кнопка с заданным пользователем размером и цветом
  22         b.SetFont(wx.Font(20, wx.SWISS, wx.NORMAL, wx.BOLD, False))
  23         b.SetBezelWidth(5)
  24         b.SetBackgroundColour("Navy")
  25         b.SetForegroundColour("white")
  26         b.SetToolTipString("This is a BIG button...")
  27         sizer.Add(b)
  28                                                   
  29         bmp = wx.Image("bitmap.bmp",              
  30             wx.BITMAP_TYPE_BMP).ConvertToBitmap()
  31         b = buttons.GenBitmapButton(panel, -1, bmp)                   # Типовая кнопка с битовым изображением
  32         sizer.Add(b)
  33         b = buttons.GenBitmapToggleButton(panel, -1, bmp)
  34         sizer.Add(b)      Типовая кнопка-переключатель с битовым изображением
  35         b = buttons.GenBitmapTextButton(panel, -1, bmp,
  36             "Bitmapped Text", size=(175, 75))                         # Кнопка с битовым изображением и текстом
  37         b.SetUseFocusIndicator(False)                  
  38         sizer.Add(b)
  39         b = buttons.GenToggleButton(panel, -1, "Toggle Button")       # Типовая кнопка-переключатель
  40         sizer.Add(b)                              
  41         panel.SetSizer(sizer)
  42 if __name__ == '__main__':
  43     app = wx.PySimpleApp()
  44     frame = GenericButtonFrame()
  45     frame.Show()
  46     app.MainLoop()

Использование типовой кнопки в листинге 7.6 очень похоже на стандартную кнопку. Типовые кнопки как и стандартные кнопки генерируют те же события EVT_BUTTON и EVT_TOGGLEBUTTON. Для изменения толшины 3D кромки типовая кнопка имеет методы GetBevelWidth() и SetBevelWidth(). Они использованы для большой кнопки рисунка 7.6.

Класс типовой кнопки с битовым изображением GenBitmapButton работает подобно обычной версии wxPython. GenBitmapTextButton принимает в конструкторе сначала битовое изображение, а затем текст. Типовые кнопки предоставляют три класса переключателей: GenToggleButton, GenBitmapToggleButton и GenBitmapTextToggleButton. Все эти три класса аналогичны версиям без переключателей, а управление состоянием переключателя производится при помощи методов GetToggle() и SetToggle().

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

Перевод: Савицкий Юрий