Автор — Грэг Валтерс (Greg Walters)

Думаю, что вы поигрались с Boa Constructor со времени нашей последней встречи. Сначала мы напишем простую программу, которая открывает одно окно, а после нажатия кнопки — второе окно. В прошлый раз мы открывали окно сообщений. На этот раз мы откроем отдельное окно. Это будет полезно при создании приложений с несколькими окнами. Итак, приступим…

Запустите Boa Constructor и закройте все вкладки в окне Редактора, кроме вкладок «Командная строка» и «Обзор», нажав клавиши Ctrl-W. Так мы начнём с чистого листа. Создайте новый проект, нажав кнопку «wx.App» (если не помните, как это сделать, обратитесь к предыдущей статье).

До начала работы сохраните «Frame1» под названием «FrameMain.py» и «App1» под названием «Gui2.py». Это очень важно. Выделив вкладку «GUI2» в окне Редактора, перейдите на Панель инструментов, выберите вкладку «Новые» и, щёлкнув кнопку «wx.Frame» (рядом с кнопкой «wx.App»), добавьте ещё одно окно в проект. Убедитесь, что колонка «Модули» на вкладке «Приложение» отображает оба окна. Теперь выделите второе окно и сохраните его под названием «FrameSecond.py»:

Откройте «FrameMain» в режиме Дизайнера. Добавьте новую панель «wx.Panel», измените её размеры, чтобы она закрывала всё окно. Теперь изменим некоторые свойства панели — в прошлый раз мы этого не делали. В окне Инспектора выделите вкладку «Constr», измените заголовок на «Main Frame», а имя — на «FrameMain». Чуть позже мы обсудим правила имён. Измените размер окна на 400×340, нажав на флаговую кнопку «Размер». Она отобразит выпадающий список с полями для высоты и ширины. Измените высоту на 400, а ширину на 340:

Щёлкните на вкладке «Props», затем на свойстве «Центрирование» и установите его в «wx.BOTH» Щёлкните по кнопке-галочке (post) для публикации. Запустите приложение, нажав на кнопку с жёлтой стрелкой. Наше приложение появится в центре экрана с заголовком «Main Frame». Закройте окно щелчком на крестике в его правом верхнем углу.

Снова откройте форму «FrameMain» в режиме Дизайнера. Добавьте две кнопки на форму, одну под другой, ближе к центру окна. Выделите верхнюю кнопку, назовите её «btnShowNew», измените надпись на «Show the other frame» на вкладке «Constr» окна Инспектора. С помощью комбинации клавиш Shift+Курсорные стрелки измените размеры кнопки так, чтобы текст был виден полностью, а затем с помощью комбинации клавиш Ctrl+Курсорные стрелки переместите кнопку обратно в центр формы. Выделите нижнюю кнопку, назовите её «btnExit» и измените текст на «Exit». Примените изменения, сохраните файл и запустите приложение, чтобы увидеть изменения. Закройте программу и вернитесь в окно Дизайнера. Мы собираемся добавить обработчиков событий нажатия на кнопки. Выделите верхнюю кнопку, перейдите в окно Инспектора, выделите вкладку «Evts». Нажмите на «ButtonEvent», затем два раза щёлкните по «wx.Evt_BUTTON». Теперь у вас ниже должна появиться строка с надписью «OnBtnShowNewButton». Выделите кнопку «btnExit», повторите операции, убедитесь в том, что вы видите «OnBtnExitButton». Примените и сохраните изменения. Теперь перейдите в окно Редактора и прокрутите код до конца.

Убедитесь, что у вас есть два метода, которые мы создали ранее. Окно должно выглядеть так:

Теперь настала пора разобраться со второй формой. Откройте «FrameSecond» в режиме дизайнера. Задайте название «FrameSecond» и заголовок «Second Frame». Задайте центровку «wx.BOTH». Добавьте кнопку и выровняйте её в нижней части окна. Задайте название «btnFSExit» и заголовок «Exit». Создайте событие для кнопки. Добавьте элемент управления «wx.StaticText» в верхней части окна ближе к середине. Назовите его «stHiThere», задайте надпись «Hi there…I'm the second form!», начертание «Sans», размер 14 пт и плотность «wxBOLD»(Props→Font). Теперь сбросьте положение, чтобы в форме кнопка была выровнена справа и слева. Это можно сделать, сняв галочку с атрибута «Position», и изменять положение «X» для сдвига кнопки вправо и влево, и положение «Y» для сдвига кнопки вверх и вниз до тех пор, пока результат не удовлетворит вас. Запишите изменения и сохраните их.

После того как мы создали формы, мы напишем код, который «склеит» их все.

В окне Редактора щёлкните на вкладке «GUI2», а затем на вкладке «Код». Под строкой «import FrameMain» добавьте строку «import FrameSecond». Сохраните изменения и перейдите на вкладку «FrameMain». Под строкой «import wx» добавьте строку «import FrameSecond». Прокрутите код вниз до строки «def init(self, parent):». Добавьте после строки «self._init_ctrls(parent)» строку «self.Fs = FrameSecond.FrameSecond(self)». В событии «def OnBtnShowNewButton(self, event):» закомментируйте строку «event.Skip()» и добавьте следующие две строки:

self.Fs.Show()
self.Hide()

Наконец, в методе «OnBtnExitButton» закомментируйте строку «event.Skip()» и добавьте строку «self.Close()».

Что всё это делает? Сначала мы убедились, что приложение знает, что у него есть две формы. Поэтому в файле «GUI2» мы импортировали «FrameMain» и «FrameSecond». Затем мы импортировали ссылку на FrameSecond в FrameMain, чтобы позже вызвать второе окно. Мы инициализировали ссылку в методе «_init_», а в методе «OnBtnShowNewButton» приказали кнопке по щелчку на ней отобразить второе окно и спрятать главное окно. Наконец, мы привязали к нажатию на кнопку «Exit» закрытие приложения.

Теперь переключитесь на код окна «FrameSecond». Здесь изменений относительно немного. В методе «_init_» добавьте строку «self.parent = parent», которая добавляет переменную «self.parent». Наконец, в событии щелчка кнопки «FSExitButton» закомментируйте строку «event.Skip()» и добавьте следующие две строки:

self.parent.Show()
self.Hide()

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

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

Теперь можно запустить программу. Если всё сделано правильно, то после нажатия на кнопку «btnShownNew» первое окно исчезнет, а второе появится. Нажатие на кнопку «Exit» во втором окне закроет его и откроет главное окно. После нажатия на кнопку «Exit» в главном окне программа закроется.

Я обещал, что мы обсудим правила имён. Помните, мы обсуждали комментирование кода? При использовании хорошо структурированных имён для элементов управления ваш код выглядит достаточно документи-*рованным. Если раньше вы просто называли элементы «staticText1» или «button1» или как-то в этом духе, то если вы будете создавать сложные формы с большим количеством элементов управления, в особенности, текстов и кнопок, очень важно, чтобы их имена что-нибудь означали. Если код будет доступен только вам, это не столь важно, но при разработке приложений в коллективе понятные имена элементов управления будут существенным подспорьем. Можно использовать, например, такие имена:

Тип элемента управления — Префикс названия Статический текст — st_ Кнопка — btn_ Поле ввода — txt_ Флаговая кнопка — chk_ Радиокнопка — rb_ Окно — Frm_ или Frame_

По мере накопления опыта программирования вы можете придумать свои правила для префиксов. Да и у вашего работодателя тоже могут быть определенные требования.

В следующий раз мы отложим в сторону программирование интерфейсов и рассмотрим программирование баз данных. До следующего раза установите на свою систему python-apsw и python-mysqldb. Для SQLite также понадобятся sqlite и sqlitebrowser. Если вы хотите поэкспериментировать с MySql, это прекрасно. Все пакеты устанавливаются с помощью Synaptic.

Коды

GUI2 code:

#!/usr/bin/env python
#Boa:App:BoaApp

import wx

import FrameMain
import FrameSecond

modules ={u'FrameMain': [1, 'Main frame of Application', u'FrameMain.py'],
 u'FrameSecond': [0, '', u'FrameSecond.py']}

class BoaApp(wx.App):
    def OnInit(self):
        self.main = FrameMain.create(None)
        self.main.Show()
        self.SetTopWindow(self.main)
        return True

def main():
    application = BoaApp(0)
    application.MainLoop()

if __name__ == '__main__':
    main()

FrameMain code:

#Boa:Frame:FrameMain

import wx
import FrameSecond

def create(parent):
    return FrameMain(parent)

[wxID_FRAMEMAIN, wxID_FRAMEMAINBTNEXIT, wxID_FRAMEMAINBTNSHOWNEW, 
 wxID_FRAMEMAINPANEL1, 
] = [wx.NewId() for _init_ctrls in range(4)]

class FrameMain(wx.Frame):
    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Frame.__init__(self, id=wxID_FRAMEMAIN, name=u'FrameMain',
              parent=prnt, pos=wx.Point(846, 177), size=wx.Size(400, 340),
              style=wx.DEFAULT_FRAME_STYLE, title=u'Main Frame')
        self.SetClientSize(wx.Size(400, 340))
        self.Center(wx.BOTH)

        self.panel1 = wx.Panel(id=wxID_FRAMEMAINPANEL1, name='panel1',
              parent=self, pos=wx.Point(0, 0), size=wx.Size(400, 340),
              style=wx.TAB_TRAVERSAL)

        self.btnShowNew = wx.Button(id=wxID_FRAMEMAINBTNSHOWNEW,
              label=u'Show the other frame', name=u'btnShowNew',
              parent=self.panel1, pos=wx.Point(120, 103), size=wx.Size(168, 29),
              style=0)
        self.btnShowNew.SetBackgroundColour(wx.Colour(25, 175, 23))
        self.btnShowNew.Bind(wx.EVT_BUTTON, self.OnBtnShowNewButton,
              id=wxID_FRAMEMAINBTNSHOWNEW)
FrameMain Code (cont.):
        self.btnExit = wx.Button(id=wxID_FRAMEMAINBTNEXIT, label=u'Exit',
              name=u'btnExit', parent=self.panel1, pos=wx.Point(162, 191),
              size=wx.Size(85, 29), style=0)
        self.btnExit.SetBackgroundColour(wx.Colour(225, 218, 91))
        self.btnExit.Bind(wx.EVT_BUTTON, self.OnBtnExitButton,
              id=wxID_FRAMEMAINBTNEXIT)

    def __init__(self, parent):
        self._init_ctrls(parent)
        self.Fs = FrameSecond.FrameSecond(self)

    def OnBtnShowNewButton(self, event):
        #event.Skip()
        self.Fs.Show()
        self.Hide()

    def OnBtnExitButton(self, event):
        #event.Skip()
        self.Close()

FrameSecond code:

#Boa:Frame:FrameSecond

import wx

def create(parent):
    return FrameSecond(parent)

[wxID_FRAMESECOND, wxID_FRAMESECONDBTNFSEXIT, wxID_FRAMESECONDPANEL1, 
 wxID_FRAMESECONDSTATICTEXT1, 
] = [wx.NewId() for _init_ctrls in range(4)]

class FrameSecond(wx.Frame):
    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Frame.__init__(self, id=wxID_FRAMESECOND, name=u'FrameSecond',
              parent=prnt, pos=wx.Point(849, 457), size=wx.Size(419, 236),
              style=wx.DEFAULT_FRAME_STYLE, title=u'Second Frame')
        self.SetClientSize(wx.Size(419, 236))
        self.Center(wx.BOTH)
        self.SetBackgroundStyle(wx.BG_STYLE_COLOUR)

        self.panel1 = wx.Panel(id=wxID_FRAMESECONDPANEL1, name='panel1',
              parent=self, pos=wx.Point(0, 0), size=wx.Size(419, 236),
              style=wx.TAB_TRAVERSAL)

        self.btnFSExit = wx.Button(id=wxID_FRAMESECONDBTNFSEXIT, label=u'Exit',
              name=u'btnFSExit', parent=self.panel1, pos=wx.Point(174, 180),
              size=wx.Size(85, 29), style=0)
        self.btnFSExit.Bind(wx.EVT_BUTTON, self.OnBtnFSExitButton,
              id=wxID_FRAMESECONDBTNFSEXIT)

        self.staticText1 = wx.StaticText(id=wxID_FRAMESECONDSTATICTEXT1,
              label=u"Hi there...I'm the second form!", name='staticText1',
              parent=self.panel1, pos=wx.Point(45, 49), size=wx.Size(336, 23),
              style=0)
        self.staticText1.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD,
              False, u'Sans'))

    def __init__(self, parent):
        self._init_ctrls(parent)
        self.parent = parent

    def OnBtnFSExitButton(self, event):
        #event.Skip()
        self.parent.Show()
        self.Hide()