mercoledì 16 gennaio 2013

Le finestre di dialogo

Salve!

Le finestre di dialogo sono il modo con cui l'applicazione ci parla, comunica informazioni, dialoga con noi. Eccone un esempio semplicissimo (d0.py):

#!/usr/bin/python
# -*- coding: utf-8 -*-

# ZetCode wxPython tutorial

import wx

class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
            
        wx.FutureCall(5000, self.ShowMessage)

        self.SetSize((300, 200))
        self.SetTitle('Aspetta che arriva...')
        self.Centre()
        self.Show(True)

    def ShowMessage(self):
        wx.MessageBox('Ciao!', 'Info', 
            wx.OK + wx.ICON_INFORMATION)

def main():
    
    ex = wx.App()
    Example(None)
    ex.MainLoop()    

if __name__ == '__main__':
    main()    
Come si vede dopo 5 secondi (grazie a wx.FutureCall()) compare la finestra di dialogo con il messaggio. Per proseguire bisogna chiudere la finestra. Notare che a questa passiamo il testo del messaggio, il titolo e i flag. Questi ultimi riguardano i pulsanti e l'eventuale icona. I flag si creano con | anche se si potrebbe usare + (meno bello concettualmente).

Con wx.MessageDialog posso passare i seguenti flag
wx.OK -> visualizza il pulsante OK
wx.CANCEL -> visualizza il pulsante Annulla
wx.YES_NO -> visualizza i pulsanti Sì e No
wx.YES_DEFAULT -> rende Sì il pulsante predefinito (default)
wx.NO_DEFAULT -> rende No il pulsante predefinito (default)
wx.ICON_EXCLAMATION    -> visualizza l'icona Attenzione
wx.ICON_ERROR -> visualizza l'icona Errore
wx.ICON_HAND -> come wx.ICON_ERROR
wx.ICON_INFORMATION    -> visualizza l'icona info
wx.ICON_QUESTION -> visualizza l'icona ?

Ecco un esempio pratico (d1.py):
#!/usr/bin/python
# -*- coding: utf-8 -*-

# ZetCode wxPython tutorial

import wx

class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
            
        panel = wx.Panel(self)

        hbox = wx.BoxSizer()
        sizer = wx.GridSizer(2, 2, 2, 2)

        btn1 = wx.Button(panel, label='Info')
        btn2 = wx.Button(panel, label='Error')
        btn3 = wx.Button(panel, label='Question')
        btn4 = wx.Button(panel, label='Alert')

        sizer.AddMany([btn1, btn2, btn3, btn4])

        hbox.Add(sizer, 0, wx.ALL, 15)
        panel.SetSizer(hbox)

        btn1.Bind(wx.EVT_BUTTON, self.ShowMessage1)
        btn2.Bind(wx.EVT_BUTTON, self.ShowMessage2)
        btn3.Bind(wx.EVT_BUTTON, self.ShowMessage3)
        btn4.Bind(wx.EVT_BUTTON, self.ShowMessage4)

        self.SetSize((300, 200))
        self.SetTitle('Messages')
        self.Centre()
        self.Show(True)

    def ShowMessage1(self, event):
        dial = wx.MessageDialog(None, 'Download completed', 'Info', wx.OK)
        dial.ShowModal()

    def ShowMessage2(self, event):
        dial = wx.MessageDialog(None, 'Error loading file', 'Error', 
            wx.OK | wx.ICON_ERROR)
        dial.ShowModal()

    def ShowMessage3(self, event):
        dial = wx.MessageDialog(None, 'Are you sure to quit?', 'Question', 
            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
        dial.ShowModal()

    def ShowMessage4(self, event):
        dial = wx.MessageDialog(None, 'Unallowed operation', 'Exclamation', 
            wx.OK | wx.ICON_EXCLAMATION)
        dial.ShowModal()

def main():
    ex = wx.App()
    Example(None)
    ex.MainLoop()    

if __name__ == '__main__':
    main()
Sempre copiando da ZetCode

http://www.zetcode.com/wxpython/dialogs/

ecco la finestra di About, quella che in italiano viene di solito indicata come Informazioni (about.py). Dovete mettere nella stessa cartella dello script questa immagine chiamandola hunter.png.
#!/usr/bin/python
# -*- coding: utf-8 -*-

#ZetCode wxPython tutorial

import wx

class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
        menubar = wx.MenuBar()
        help = wx.Menu()
        help.Append(100, '&About')
        self.Bind(wx.EVT_MENU, self.OnAboutBox, id=100)
        menubar.Append(help, '&Help')
        self.SetMenuBar(menubar)

        self.SetSize((300, 200))
        self.SetTitle('About dialog box')
        self.Centre()
        self.Show(True)

    def OnAboutBox(self, e):
        
        description = """File Hunter is an advanced file manager for 
the Unix operating system. Features include powerful built-in editor, 
advanced search capabilities, powerful batch renaming, file comparison, 
extensive archive handling and more.
"""

        licence = """File Hunter is free software; you can redistribute 
it and/or modify it under the terms of the GNU General Public License as 
published by the Free Software Foundation; either version 2 of the License, 
or (at your option) any later version.

File Hunter is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
See the GNU General Public License for more details. You should have 
received a copy of the GNU General Public License along with File Hunter; 
if not, write to the Free Software Foundation, Inc., 59 Temple Place, 
Suite 330, Boston, MA  02111-1307  USA"""

        info = wx.AboutDialogInfo()

        info.SetIcon(wx.Icon('hunter.png', wx.BITMAP_TYPE_PNG))
        info.SetName('File Hunter')
        info.SetVersion('1.0')
        info.SetDescription(description)
        info.SetCopyright('(C) 2007 - 2011 Jan Bodnar')
        info.SetWebSite('http://www.zetcode.com')
        info.SetLicence(licence)
        info.AddDeveloper('Jan Bodnar')
        info.AddDocWriter('Jan Bodnar')
        info.AddArtist('The Tango crew')
        info.AddTranslator('Jan Bodnar')

        wx.AboutBox(info)

def main():
    ex = wx.App()
    Example(None)
    ex.MainLoop()    

if __name__ == '__main__':
    main()
Uh! fa un sacco di cose, scopritele esaminando il codice, se serve aiuto chiedete. Secondo me le finestre dovrebbero essere tenute semplici, senza troppe opzioni che "spaventano" l'utente (specie se niubbo, che è quello che avrebbe bisogno di sentirsi a suo agio).

È possibile creare finestre di dialogo personalizzate, come questa che propone di cambiare il numero di colori per un'immagine (color.py). Serve l'immagine color.png.
#!/usr/bin/python
# -*- coding: utf-8 -*-

#ZetCode wxPython tutorial

import wx

class ChangeDepthDialog(wx.Dialog):
    
    def __init__(self, *args, **kw):
        super(ChangeDepthDialog, self).__init__(*args, **kw) 
            
        self.InitUI()
        self.SetSize((250, 200))
        self.SetTitle("Change Color Depth")
     
    def InitUI(self):
        pnl = wx.Panel(self)
        vbox = wx.BoxSizer(wx.VERTICAL)

        sb = wx.StaticBox(pnl, label='Colors')
        sbs = wx.StaticBoxSizer(sb, orient=wx.VERTICAL)        
        sbs.Add(wx.RadioButton(pnl, label='256 Colors', 
            style=wx.RB_GROUP))
        sbs.Add(wx.RadioButton(pnl, label='16 Colors'))
        sbs.Add(wx.RadioButton(pnl, label='2 Colors'))
        
        hbox1 = wx.BoxSizer(wx.HORIZONTAL)        
        hbox1.Add(wx.RadioButton(pnl, label='Custom'))
        hbox1.Add(wx.TextCtrl(pnl), flag=wx.LEFT, border=5)
        sbs.Add(hbox1)
        
        pnl.SetSizer(sbs)
       
        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        okButton = wx.Button(self, label='Ok')
        closeButton = wx.Button(self, label='Close')
        hbox2.Add(okButton)
        hbox2.Add(closeButton, flag=wx.LEFT, border=5)

        vbox.Add(pnl, proportion=1, 
            flag=wx.ALL|wx.EXPAND, border=5)
        vbox.Add(hbox2, 
            flag=wx.ALIGN_CENTER|wx.TOP|wx.BOTTOM, border=10)

        self.SetSizer(vbox)
        
        okButton.Bind(wx.EVT_BUTTON, self.OnClose)
        closeButton.Bind(wx.EVT_BUTTON, self.OnClose)
        
    def OnClose(self, e):
        self.Destroy()
        
        
class Example(wx.Frame):
    
    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw) 
            
        self.InitUI()
        
    def InitUI(self):    
        ID_DEPTH = wx.NewId()

        tb = self.CreateToolBar()
        tb.AddLabelTool(id=ID_DEPTH, label='', 
            bitmap=wx.Bitmap('color.png'))
        
        tb.Realize()

        self.Bind(wx.EVT_TOOL, self.OnChangeDepth, 
            id=ID_DEPTH)

        self.SetSize((300, 200))
        self.SetTitle('Custom dialog')
        self.Centre()
        self.Show(True)
        
    def OnChangeDepth(self, e):
        
        chgdep = ChangeDepthDialog(None, 
            title='Change Color Depth')
        chgdep.ShowModal()
        chgdep.Destroy()        

def main():
    ex = wx.App()
    Example(None)
    ex.MainLoop()    

if __name__ == '__main__':
    main()
OK, secondo me manca ancora una cosa: come facciamo a sapere qual è la risposta nel caso ci siano più scelte? Riprendiamo il secondo esempio, riduciamolo all'essenziale e vediamo (res.py):
#!/usr/bin/python
# -*- coding: utf-8 -*-

# ZetCode wxPython tutorial

import wx

class Example(wx.Frame):
    
    def __init__(self, *args, **kwargs):
        super(Example, self).__init__(*args, **kwargs) 
            
        panel = wx.Panel(self)

        hbox = wx.BoxSizer()
        sizer = wx.GridSizer(2, 2, 2, 2)

        btn3 = wx.Button(panel, label='Question')

        sizer.AddMany([btn3])

        hbox.Add(sizer, 0, wx.ALL, 15)
        panel.SetSizer(hbox)

        btn3.Bind(wx.EVT_BUTTON, self.ShowMessage3)

        self.SetSize((300, 200))
        self.SetTitle('Messages')
        self.Centre()
        self.Show(True)

    def ShowMessage3(self, event):
        dial = wx.MessageDialog(None, 'Are you sure to quit?', 'Question', 
            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
        scelta = dial.ShowModal()
        print scelta, wx.ID_YES, scelta == wx.ID_YES
        
def main():
    ex = wx.App()
    Example(None)
    ex.MainLoop()    

if __name__ == '__main__':
    main()
Ho scelto rispettivamente Sì, No e chiuso la finestra senza scegliere.
I valori dei messaggi li trovate qui

Anche se rispetto alla versione per il C++ vanno modificati: wxID_OK per noi diventa wx.ID_OK, come nel codice.

Mi sa che il caro Juhan si è ripreso dall'influenza!! Non si spiega diversamente. :)

L'indice di "Mission Python" qui.

Alla prossima!

1 commento: