Programant en Python - part 6

Espero que hageu estat jugant amb Boa Constructor des de l'última trobada. Continuarem ara amb una mica més de programació d'interfícies gràfiques. Primer farem un programa MOLT simple que mostrarà un marc, i et permetrà clicar un botó que desplegarà un altre marc. L'últim cop vam fer una caixa d'informació. Aquest cop serà un marc completament separat. Això pot ser útil per a fer una aplicació amb múltiples marcs o finestres. Així que... ...som-hi!

Inicieu Boa Constructor i tanqueu totes les pestanyes de la finestra de l'editor, excepte el Shell i l'explorador usant la combinació de tecles Ctrl-W. Això assegura que comencem completament de nou. Ara creeu un nou projecte clicant al botó wx.App (vegeu l'article anterior si us cal).

ABANS de fer RES més, guardeu el Frame1 com a "FrameMain.py" i llavors guardeu App1 com a "Gui2.py". Això és important. Amb la pestanya GUI2 seleccionada a la finestra de l'Editor, torneu a la barra d'eines, a New Tab, i afegiu un altre marc al nostre projecte clicant a wx.Frame (al costat del botó wx.App). Assegureu-vos que la pestanya d'aplicació mostra ambdós marcs a la columna del mateix mòdul. Ara torneu al nou marc i guardeu-lo com a "FrameSecond.py":

{INSERT screenshot_001.png HERE}

A continuació, obriu FrameMain al dissenyador. Afegiu wx.Panel al marc. Canvieu-li la mida per fer que el panell cobreixi el marc. A continuació canviarem algunes propietats, cosa que no vam fer l'últim cop. Al marc Inspector, assegureu-vos que la pestanya Constr està seleccionada i el títol sigui "Main Frame" i el nom "FrameMain". Parlem de convencions pels noms més endavant. Configureu la mida a 400x340 clicant a la caixa Size. Això mostra alçada i amplada. L'alçada hauria de ser 400 i l'amplada 340:

{INSERT screenshot_002.png HERE}

Ara cliqueu a la pestanya Props. Cliqueu a la propietat Centered i poseu-la a wx.BOTH. Cliqueu la icona de post i guardeu el treball. Ara executeu l'aplicació clicant al botó de la fletxa groga. La nostra aplicació apareix al centre de la pantalla amb el títol "Main Frame". Ara tanqueu-la clicant a la "X" de la cantonada superior dreta.

Torneu a portar FrameMain al dissenyador. Afegiu-hi dos wx.Buttons, un sobre l'altre, i a prop del centre. Seleccioneu el botó de sobre, i anomeneu-lo "btnShowNew", i canvieu l'etiqueta a "Show the other frame" a la pestanya Constr del marc Inspector. Useu la combinació Shift+Fletxa per a modificar la mida del botó per tal que tot el text sigui visible, i després useu la combinació Ctrl+Fletxa per a moure'l de nou al centre. Seleccioneu el de sota, anomeneu-lo "btnExit", i anomeneu l'etiqueta "Exit". Post, guardar, i executeu per a veure els canvis. Sortiu de l'aplicació i torneu al dissenyador. Ara afegirem els esdeveniments dels clics dels botons. Seleccioneu el botó superior, i al marc de l'inspector, seleccioneu la pestanya Evts. Cliqueu a ButtonEvent, i després feu doble clic a wx.Evt_BUTTON. Tingueu en compte que hauria d'haver-hi "OnBtnShowNewButton" a sota. A continuació, seleccioneu el botó btnExit. Feu el mateix, assegurant-vos que mostra "OnBtnExitButton". Post i guardeu. A continuació aneu a l'editor i baixeu fins al final.

Make sure you have the two event methods that we just created. Here's what the frame should look like so far:

{INSERT screenshot_003.png HERE}

Now it's time to deal with our other frame. Open FrameSecond in the designer. Set the name to “FrameSecond”, and the title to “Second Frame”. Set centering to wx.BOTH. Add a wx.Button, and center it towards the lower part of the frame. Set the name to “btnFSExit”, and change the title to “Exit”. Set up a button event for it. Next add a wx.StaticText control in the upper portion of the frame close to the middle. Name it “stHiThere”, set the label to “Hi there...I'm the second form!”, and set the font to Sans, 14 point and weight to wxBOLD. Now reset the position to be centered in the form right and left. You can do this by unchecking the Position attribute and use the X position for right and left, and Y for up and down until you are happy. Post and save:

{INSERT screenshot_004.png HERE}

Now that we have designed our forms, we are going to create the “glue” that will tie all this together.

In the Editor frame, click on the GUI2 tab, then, below that, click on the Source tab. Under the line that says “import FrameMain”, add “import FrameSecond”. Save your changes. Next, select the “FrameMain” tab. Under the line that says “import wx”, add a line that says “import FrameSecond”. Next scroll down, and find the line that says “def init(self, parent):”. Add a line after the “self._init_ctrls(parent)” line that says “self.Fs = FrameSecond.FrameSecond(self)”. Now under the “def OnBtnShowNewButton(self, event):” event, comment out “event.Skip()” and add the following two lines:

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

Finally, under “OnBtnExitButton” method, comment out “event.Skip()”, and add a line that says “self.Close()”

What does all this do? OK. The first thing we did was to make sure that the application knew we were going to have two forms in our app. That's why we imported both FrameMain and FrameSecond in the GUI2 file. Next we imported a reference for FrameSecond into FrameMain so we can call it later. We initialized it in the “_init_” method. And in the “OnBtnShowNewButton” event we told it that when the button was clicked, we want to first show the second frame, and to hide the main frame. Finally we have the statement to close the application when the Exit button is clicked.

Now, switch to the code for FrameSecond. The changes here are relatively small. Under the “_init_” method, add a line that says “self.parent = parent” which adds a variable self.parent. Finally, under the click event for FSExitButton, comment out the “event.Skip()” line, and add the following two lines:

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

Remember we hid the main frame when we showed the second frame, so we have to re-show it. Finally we hide the second frame. Save your changes.

Here is all the code for you to verify everything:

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)

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()

Now you can run your application. If everything went right, you will be able to click on btnShownNew, and see the first frame disappear and second frame appear. Clicking on the Exit button on the second frame will cause that frame to disappear and the main frame to re-appear. Clicking on the Exit button on the main frame will close the application.

I promised you we'd discuss naming conventions. Remember way back, we discussed commenting your code? Well, by using well-formed names for gui controls, your code is fairly self-documenting. If you just left control names as staticText1 or button1 or whatever, when you are creating a complex frame with many controls, especially if there are a lot of text boxes or buttons, then naming them something that is meaningful is very important. It might not be too important if you are the only one who will ever see the code, but to someone coming behind you later on, the good control names will help them out considerably. Therefore, use something like the following:

Control type - Name prefix Static text - st_ Button - btn_ Text Box - txt_ Check Box - chk_ Radio Button - rb_ Frame - Frm_ or Frame_

You can come up with your own ideas for naming conventions as you grow as a programmer, and in some instances your employer might have conventions already in place.

Next time, we will leave GUI programming aside for a bit and concentrate on database programming. Meanwhile, get python-apsw and python-mysqldb loaded on your system. You will also need sqlite and sqlitebrowser for SQLite. If you want to experiment with MySql as well, that's a good idea. All are available via Synaptic.

UbuntuMagazine/TranslateFullCircle/Catalan/edicio32/Programant en Python - part 6 (last edited 2009-12-30 23:25:02 by 251)