В этой главе рассказывается о том, как:
- создавать модальные диалоговые окна и окна с сообщениями
- использовать стандартные диалоги
- создавать помощников
- показывать советы при запуске
- создавать и использовать валидаторы
В то время как фреймы используются для продолжительных взаимодействий с пользователем, диалоги обычно нужны для того, чтобы получить некоторое количество информации от пользователя и передать её на обработку дальше. Зачастую диалоговые окна открываются в модальном режиме, что не позволяет другим фреймам перехватывать события, пока диалог не закрыт. В это главе мы обсудим виды диалогов, доступных в wxPython, хотя кроме них Вы можете создать и свои собственные варианты. Среди предустановленных диалогов есть как простые, только для вывода информации, так и более сложные, например, для открытия файлов.
9.1 Работа с модальными диалогами
Модальные диалоги используются или для того, чтобы быстро вывести / получить какую-либо информацию, либо когда без новых данных от пользователя невозможно двигаться дальше. wxPython содержит несколько функций для отображения таких диалогов: диалог с сообщением, со строкой для ввода и с выбором из списка. В следующем разделе мы посмотрим, как эти диалоги выглядят и как Вы можете облегчить себе жизнь с помощью имеющихся функций.
9.1.1 Как создать модальный диалог
Модальный диалог не позволяет другим виджетам получать события от пользователя до тех пор, пока диалог не будет закрыт. Как видно из рисунка 9.1, по внешнему виду не всегда можно отличить, является ли открытое окно диалогом или фреймом.
рис 9.1
Листинг 9.1
import wx
class SubclassDialog(wx.Dialog):
def __init__(self): #инициируем диалог
wx.Dialog.__init__(self, None, -1, 'Dialog Subclass',size=(300, 100))
okButton = wx.Button(self, wx.ID_OK, "OK", pos=(15, 15))
okButton.SetDefault()
cancelButton = wx.Button(self, wx.ID_CANCEL, "Cancel",pos=(115, 15))
if __name__ == '__main__':
app = wx.PySimpleApp()
dialog = SubclassDialog()
result = dialog.ShowModal() #показываем модальный диалог
if result == wx.ID_OK:
print "OK"
else:
print "Cancel"
dialog.Destroy()
В этом листинге надо отметить несколько деталей: при инициализации кнопка добавляется непосредственно к диалогу, а не на панель. Вообще, панели гораздо реже используются в диалогах, чем во фреймах. Отчасти потому, что диалоги должны быть как можно проще, но главная причина в том, что функционал панели (стандартный фон и переключение между элементами с помощью табуляции) уже реализован в диалогах.
Для отображения диалога как модального окна используется метод ShowModal(), имеющийся от метода Show(), который используется для отображения фреймов. Ваше приложение останавливается в точке вызова ShowModal() до тех пор, пока диалоговое окно не будет закрыто. В этот момент единственным, кто может взаимодействовать с пользователем является диалог (понятно, что другие приложения продолжают работать в обычном режиме).
Программно диалог можно закрыть с помощью метода EndModal(retCode), где retCode — числовое значение, которое возвращается методом ShowModal(). Обычно оно используется для того, чтобы сообщить приложению каким образом было закрыто диалоговое окно и на основании этого принять соответствующее решение. При этом важно помнить, что прекращение отображения диалога ещё не значит его уничтожения — даже после этого он продолжает существовать, благодаря чему после его закрытия Вы всё ещё можете получить данные, введённые пользователем. Пример этого мы увидим в следующем разделе.
Возможно, Вы заметили, что в листинге не было определено ни одного обработчика, что должно было заставить Вас задуматься: «Почему же тогда диалог реагирует на нажатие кнопок?» Никакого секрета тут нет — это поведение уже определено в wx.Dialog. Есть два предопределённых ID, которые имеют особое значение для диалогов:
- когда нажимается wx.Button с ID равным wx.ID_OK, диалог закрывается и в точку вызова ShowModal() возвращается значение wx.ID_OK
- аналогично действует нажатие на кнопку со значением wx.ID_CANCEL, возвращающая соответствующее значение
после чего приложению остаётся лишь корректно обработать значения кнопок.
Листинг 9.1 показывает стандартный способ работы с модальными диалогами. После активации диалога значение, которое он возвращает, используется в качестве условия в выражении if. В нашем случае мы всего лишь выводим на экран выбор пользователя. Однако обычно в случае результата wx.ID_OK предпринимаются более сложные действия, основанные на выборе пользователя, такие как открытие файла или выбор цвета.
Обычно Вы должны явным образом уничтожить диалог когда Вы заканчиваете его использовать, так как после этого он может быть утилизован сборщиком мусора Python. Если же Вы хотите повторно использовать диалог без того, чтобы тратить время на его создание (например, если это какой-то сложный экземпляр), то Вы можете сохранить на него ссылку и отобразить его позже, вызвав метод ShowModal(). Но при этом важно помнить, что перед завершением программы диалог всё равно придется уничтожить, так как иначе MainLoop() будет рассматривать его как окно верхнего уровня и не сможет корректно завершить работу.
9.1.2 Как вывести пользователю сообщение?
Три наиболее простых диалога для взаимодействия с пользователем — это wx.MessageDialog, выводящий сообщение, wx.TextEntryDialog, предлагающий пользователю ввести короткий текст и wx.SingleChoiceDialog, позволяющий пользователю выбрать варианты из предоставленного списка. В следующих трёх секциях мы обсудим эти три диалога.
Диалог сообщения, как следует из названия, отображает короткое сообщение и закрывается по нажатию кнопки. Обычно он используется для вывода предупреждений или получения ответа на вопрос да / нет. На рисунке 9.2 отображён такой диалог.
рис 9.2
Использование такого диалога не вызовет у Вас затруднений: в листинге 9.2 представлено два способа создания такого диалога.
Листинг 9.2
import wx
if __name__ == "__main__":
app = wx.PySimpleApp()
# с использованием классов
dlg = wx.MessageDialog(None, "Is this explanation OK?",
'A Message Box',wx.YES_NO | wx.ICON_QUESTION)
retCode = dlg.ShowModal()
if (retCode == wx.ID_YES):
print "yes"
else:
print "no"
dlg.Destroy()
# с использованием функции
retCode = wx.MessageBox("Is this way easier?", "Via Function",
wx.YES_NO | wx.ICON_QUESTION)
Мы создаём два диалоговых окна, одно за другим. В первый раз мы создаём экземпляр класса wx.MessageDialog, после чего вызываем его метод ShowModal().
Используем класс wx.MessageDialog
Используем класс wx.MessageDialog
Используя конструктор класса wx.MessageDialog Вы можете задать сообщение в диалоге и выбрать для него необходимые кнопки:
wx.MessageDialog(parent,message,caption=»MessageBox»,style=wx.OK|wx.CANCEL,pos=wx.DefaultPosition)
message — текст, который будет отображаться в диалоге; если Вы хотите разделить его на несколько строк — используйте 'n'. caption отображается в заголовке диалога. pos позволяет Вам определить место на экране, где будет отображён диалог, однако Windows этот аргумент игнорирует.
Флаги стиля можно разделить на две группы. Первая содержит кнопки, которые будут отображаться в диалоге:
| Стиль | Описание |
|---|---|
| wx.CANCEL | Добавляет кнопку «отменить» с идентификатором wx.ID_CANCEL |
| wx.NO_DEFAULT | Если установлен флаг wx.YES_NO, то кнопкой по умолчанию будет «нет» |
| wx.OK | Добавляет кнопку «да» с идентификатором wx.ID_OK |
| wx.YES_DEFAULT | Если установлен флаг wx.YES_NO, то кнопкой по умолчанию будет «да». Такая настройка применяется по умолчанию |
| wx.YES_NO | Добавляет кнопки «да» и «нет» со значениями wx.ID_OK и wx.ID_NO соответственно |
Вторая группа флагов отвечает за знак, который будет отображён рядом с текстом:
| Стиль | Описание |
|---|---|
| wx.ICON_ERROR | Знак ошибки |
| wx.ICON_EXCLAMATION | Восклицательный знак |
| wx.ICON_HAND | То же, что и wx.ICON_ERROR |
| wx.ICON_INFORMATION | Знак информационного сообщения (буква i) |
| wx.ICON_QUESTION | Вопросительный знак |
И наконец, Вы можете использовать флаг стиля wx.STAY_ON_TOP, чтобы отобразить сообщение поверх всех окон в системе.
Как можно видеть из листинга, для того, чтобы отобразить диалог, вызывается метод ShowModal(). В зависимости от отображаемых кнопок Вы получите в ответ wx.ID_OK, wx.ID_CANCEL, wx.ID_YES или wx.ID_NO. Как обычно, результат используется для управления дальнейшей работой программы.
Использование функции wx.MessageBox()
В листинге 9.2 показан и более короткий способ отображения информационного окна: специальная функция wx.MessageBox() сама создаёт диалог, вызывает его метод ShowModall() и возвращает одно из четырёх значений: wx.ID_OK, wx.ID_CANCEL, wx.ID_YES или wx.ID_NO. Сам вызов функции проще конструктора wx.MessageDialog: wx.MessageBox(message,caption=»Message»,style=wx.OK)
В этом примере message,caption и style имеют те же значения, что и в конструкторе класса и Вы можете использовать те же самые флаги стиля. Как Вы увидите дальше в этой главе, многие из предустановленных диалогов имеют схожие функции для их быстрого вызова. Пока Вы планируете использовать диалог всего один раз, можете спокойно выбирать любой из этих двух способов. Но если Вы хотите сохранить диалог в памяти для дальнейшего использования — лучше создать собственный экземпляр. Однако для таких простых диалогов, как наш, экономии времени Вы, конечно, не достигните.
В этом примере message,caption и style имеют те же значения, что и в конструкторе класса и Вы можете использовать те же самые флаги стиля. Как Вы увидите дальше в этой главе, многие из предустановленных диалогов имеют схожие функции для их быстрого вызова. Пока Вы планируете использовать диалог всего один раз, можете спокойно выбирать любой из этих двух способов. Но если Вы хотите сохранить диалог в памяти для дальнейшего использования — лучше создать собственный экземпляр. Однако для таких простых диалогов, как наш, экономии времени Вы, конечно, не достигните.
Для того, чтобы отобразить более объемны
й текст (например, лицензию) Вы можете использовать доступный только для Python класс wx.lib.dialogs.ScrolledMessageDialog, использующий такой конструктор:
wx.lib.dialogs.ScrolledMessageDialog(parent, msg, caption, pos=wx.wxDefaultPosition, size=(500,300))
Этот класс не использует встроенные диалоги, а конструирует свой из доступных виджетов. Он отображает только кнопку «ОК» и не принимает флагов стиля.
й текст (например, лицензию) Вы можете использовать доступный только для Python класс wx.lib.dialogs.ScrolledMessageDialog, использующий такой конструктор:
wx.lib.dialogs.ScrolledMessageDialog(parent, msg, caption, pos=wx.wxDefaultPosition, size=(500,300))
Этот класс не использует встроенные диалоги, а конструирует свой из доступных виджетов. Он отображает только кнопку «ОК» и не принимает флагов стиля.
9.1.3 Как получить короткий текст от пользователя?
Второй простой тип диалога — wx.TextEntryDialog, используемый для получения ввода от пользователя небольшого объема информации. Обычно Вы встречаетесь с ним, когда от Вас требуют имя пользователя или пароль при запуске программы. На рисунке 9.3 отображён типичный представитель этого класса.
рис 9.3
Код, вызвавший его к жизни, приведён в листинге 9.3
Листинг9.3
import wx
if __name__ == "__main__":
app = wx.PySimpleApp()
dialog = wx.TextEntryDialog(None,
"What kind of text would you like to enter?",
"Text Entry", "Default Value", style=wx.OK|wx.CANCEL)
if dialog.ShowModal() == wx.ID_OK:
print "You entered: %s" % dialog.GetValue()
dialog.Destroy()
Как и в предыдущем разделе, мы создаём экземпляр класса диалога, в данном случае wx.TextEntryDialog, однако конструктор этого класса чуть более сложный, чем предыдущий:wx.TextEntryDialog(parent, message, caption=»Please enter text», defaultValue=»», style=wx.OK | wx.CANCEL | wx.CENTRE, pos=wx.DefaultPosition) message — текст приглашения к вводу, caption — текст, отображаемый в заголовке окна. defaultValue, если задано, отображает значение, появляющееся в поле для ввода при отображении диалога. Флаги стиля могут содержать wx.OK и wx.CANCEL для отображения соответствующих кнопок.
В данном диалоге можно использовать и некоторые флаги стиля виджета wx.TextCtrl. Наиболее полезные из них: wx.TE_PASSWORD для замены символов звёздочками, wx.TE_MULTILINE, позволяющий вводить несколько строк текста, и wx.TE_LEFT, wx.TE_CENTRE с wx.TE_RIGHT, определяющие выравнивание вводимого текста.
Последняя строка из этого листинга иллюстрирует ещё одно отличие от информационного диалога: введённая пользователем информация сохраняется в экземпляре диалога и может быть использована после его закрытия. В нашем примере мы получаем её с помощью метода GetValue(). Не стоит забывать, что если пользователь нажал на «отмену», это значит, что он не хочет использовать введённое значение, поэтому имеет смысл проводить проверку, какая кнопка была нажата. Кроме того, Вы можете ввести значение программно с помощью метода SetValue().
Кроме того, у нас есть ещё три удобных функции для этих целей:
- wx.GetTextFromUser()
- wx.GetPasswordFromUser()
- wx.GetNumberFromUser()
Наиболее похожим образом на наш пример действует функция wx.GetTextFromUser():
wx.GetTextFromUser(message, caption=»Input text», default_value=»», parent=None)
Все значения в этом примере идентичны конструктору класса. Если пользователь нажимает «ок», то функция возвращает введёный текст, иначе Вы получите пустую строку.
Для получения пароля надо использовать функцию wx.GetPasswordFromUser():
wx.GetPasswordFromUser(message, caption=»Input text», default_value=»», parent=None)
И тут с аргументами у Вас не должно возникнуть проблем. Вводимый текст, как понятно, заменяется звёздочками. Возвращаемые значения аналогичны предыдущей фу
wx.GetTextFromUser(message, caption=»Input text», default_value=»», parent=None)
Все значения в этом примере идентичны конструктору класса. Если пользователь нажимает «ок», то функция возвращает введёный текст, иначе Вы получите пустую строку.
Для получения пароля надо использовать функцию wx.GetPasswordFromUser():
wx.GetPasswordFromUser(message, caption=»Input text», default_value=»», parent=None)
И тут с аргументами у Вас не должно возникнуть проблем. Вводимый текст, как понятно, заменяется звёздочками. Возвращаемые значения аналогичны предыдущей фу


