Warning: Creating default object from empty value in /membri/bancaldo/wp-content/plugins/paged-comments/paged-comments.php on line 31
bancaldo™ » wxPython

Archivio

Archivio per la categoria ‘wxPython’

python: generatore squadre Calcio 7

28 gennaio 2015 Commenti chiusi

I tuoi amici si lamentano sempre perchè fai delle squadre squilibrate?
Una volta quando eri giovane eri fortissimo e adesso sei un vecchio che vive di ricordi come me?
Ecco un’applicazione utile, scritta in python, per comporre le squadre di una partita di calcio a 7.
Questa app, tiene conto della valutazione complessiva di un calciatore e del suo stato di forma, definisce un massimo gap ammissibile tra le due squadre e compone le stesse casualmente, tenendo conto anche dei ruoli.
Tutto quello che devi fare è inserire i giocatori e valutarli da 0 a 100, sia come valore complessivo, sia come stato di forma.

core

Inserire i nomi dei propri amici (lo so ho amici importanti…)
dal menu Giocatore (Nuovo Giocatore):
aggnuovo

Poi stabilire se il gap delle due squadre è ottimale.
gap

Infine comporre le squadre selezionando gli amici che verranno al campo e premendo sul pulsante dedicato.
fatte

Ovviamente restringendo il gap, le combinazioni saranno sempre meno. In caso non si riuscisse dopo 10000 tentativi, un messaggio avviserà di allargare la forbice.

In caso di disparità dei giocatori, crearne uno JOLLY con valutazione 0 0, in modo da equilibrare le squadre nonostante la disparità.

Grossi bug non dovrebbero essercene, in caso una segnalazione sarebbe gradita.

Un po’ di codice:

# controller.py
__author__ = 'Banchellia'

import wx
from model import Model
from view import View
from random import shuffle

# pyinstaller
#import flask_sqlalchemy._compat as _

#import flask.ext.sqlalchemy as s

class Controller(object):
    def __init__(self, model):
        self.model = model
        self.giocatori = self.tutti_giocatori()
        self.view = View(parent=None, title='"calcio a 7" v.2.1 by Bancaldo',
                         controller=self)

    def salva_nuovo_giocatore(self, nome, cognome, valore, forma, ruolo):
        msg = self.model.nuovo_giocatore(nome, cognome, valore, forma, ruolo)
        return msg

    def modifica_giocatore(self, nome, cognome, valore, forma, ruolo):
        msg = self.model.modifica_valori(nome, cognome, valore, forma, ruolo)
        return msg

    def tutti_giocatori(self):
        return  ['%s %s %s %s <%s>' %(g.cognome, g.nome.capitalize(), g.valore,
                                      g.forma, g.ruolo[0])
                 for g in self.model.tutti_giocatori()]

    def trova_giocatore(self, nome, cognome):
        giocatore =  self.model.trova_giocatore(nome.upper(), cognome.upper())
        self.model.giocatore = giocatore
        self.view.edit_view.update_ui_edit_giocatore(giocatore)

    def cancella_giocatore(self, nome, cognome):
        msg = self.model.cancella_giocatore(nome, cognome)
        return msg

    def get_gap(self):
        return self.model.diff

    def set_gap(self, value):
        try:
            self.model.diff = int(value)
            return '+++ nuovo GAP settato!'
        except ValueError:
            return "ERROR: il valore del GAP deve essere un numero!"

    # Algoritmo di composizione
    # 1) controllo che siano stati selezionati i giocatori
    # 2) controllo che i giocatori siano pari e se sono dispari
    #        seleziono il giocatore jolly "ASSENTE Assente"
    # 3) creata la lista, la seziono in base ai ruoli e la mescolo
    # 4) la ricompongo mescolata ma in ordine di ruoli e divido
    #        in due con metodo zigzag [::2][1::2]

    def componi(self, iterable):
        list_selezionati = list(iterable)
        ordinati = self.dividi_per_ruolo(list_selezionati)
        verde, gialla = ordinati[::2], ordinati[1::2]
        diff = self.check_gap(verde, gialla)
        tentativi = 1
        while diff >= self.model.diff:
            print 'GAP: <%s> troppo alto' % diff
            print '[CORE] Formazioni non equilibrate: ricalcolo...'
            print '[CORE] Tentativo n. %s...' % tentativi
            ordinati = self.dividi_per_ruolo(list_selezionati)
            verde, gialla = ordinati[::2], ordinati[1::2]
            tentativi += 1
            if tentativi > 10000:
                verde, gialla = [], []
                break
            else:
                diff = self.check_gap(verde, gialla)
        if not verde and not gialla:
            self.view.alert(
                """Devi aumentare il GAP o non riesco [conferma con set GAP]""")
        else:
            print '[CORE] GAP squadre <%s>' % diff
            print '[CORE] Composizione squadre riuscita!'
            self.view.update_squadre(verde, gialla)

    def dividi_per_ruolo(self, iterable):
        pp = [g for g in iterable if g.split(' ')[4] == '<p>']
        dd = [g for g in iterable if g.split(' ')[4] == '<d>']
        cc = [g for g in iterable if g.split(' ')[4] == '<c>']
        aa = [g for g in iterable if g.split(' ')[4] == '<a>']
        for lr in (pp, dd, cc, aa):
            shuffle(lr)
        return pp + dd + cc + aa

    def check_gap(self, verde, gialla):
        val_verde = sum([int(g.split(' ')[2]) for g in verde])
        sdf_verde = sum([int(g.split(' ')[3]) for g in verde])/2
        val_gialla = sum([int(g.split(' ')[2]) for g in gialla])
        sdf_gialla = sum([int(g.split(' ')[3]) for g in gialla])/2
        diff = abs((val_verde + sdf_verde) - (val_gialla + sdf_gialla))
        return diff


if __name__ == '__main__':
    app = wx.App()
    model = Model()
    controller = Controller(model)
    app.MainLoop()


# model.py
__author__ = 'Banchellia'

import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

# pyinstaller
import flask_sqlalchemy._compat as _
import flask.ext.sqlalchemy as s

t = s
print t.__str__

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///giocatori.db'
db = SQLAlchemy(app)


class Giocatore(db.Model):
    """Class Giocatore per creazione tabella in sqlite"""
    id = db.Column(db.Integer, primary_key=True)
    nome = db.Column(db.String(30))
    cognome = db.Column(db.String(30))
    valore = db.Column(db.Integer())
    forma = db.Column(db.Integer())
    ruolo = db.Column(db.String(20))

    def __init__(self, nome, cognome, valore=60, forma=60, ruolo='difensore'):
        self.nome = nome
        self.cognome = cognome
        self.valore = valore
        self.forma = forma
        self.ruolo = ruolo

    def __repr__(self):
        return '<%s - %s>' % (self.cognome, self.nome.capitalize())


class Model(object):
    """classe Model per pattern MVC."""
    def __init__(self):
        self._diff = 25
        self._giocatore = None
        if not self._database_exist():
            self._create_database()
            print "[CORE] Database creato con successo!"
        else:
            print "[CORE] rilevato database."

    @property
    def diff(self):
        return self._diff

    @diff.setter
    def diff(self, value):
        self._diff = value

    @property  # attributo a cui associo l'oggetto calciatore trovato
    def giocatore(self):
        return self._giocatore

    @giocatore.setter  # attributo a cui associo l'oggetto calciatore trovato
    def giocatore(self, obj):
        self._giocatore = obj

    def _database_exist(self):
        """Ritorna True se il database e' gia' esistente"""
        return 'giocatori.db' in os.listdir(os.getcwd())

    def _delete_database(self):
        """Cancella il database e tutti i dati contenuti in esso"""
        ans = raw_input("[CORE] Sto per eliminare il database, sicuro? (Y/N): ")
        if ans.upper() == 'Y':
            db.session.close()
            os.remove('giocatori.db')
        else:
            print "[CORE] Operazione annullata!"

    def _create_database(self):
        """Crea il database se non esiste"""
        db.create_all()

    def nuovo_giocatore(self, nome, cognome, valore, forma, ruolo):
        """Inserisce in database un nuovo giocatore:
           nuovo_giocatore(nome, cognome).
           Ritorna in entrambi i casi un messaggio da visualizzare in UI"""
        if not self.giocatore_esistente(nome, cognome):
            giocatore = Giocatore(nome=nome.strip().upper(),
				  cognome=cognome.strip.upper(),
                                  valore=int(valore.strip()),
                                  forma=int(forma.strip()),
                                  ruolo=ruolo.lower())
            db.session.add(giocatore)
            db.session.commit()
            return '+++ Giocatore <%s> inserito correttamente' % cognome.upper()
        else:
            return 'Giocatore <%s> esistente' % cognome

    def giocatore_esistente(self, nome, cognome):
        """Ritorna True se il giocatore di nome e cognome esiste"""
        return Giocatore.query.filter_by(
            nome=nome.strip().upper(), 
            cognome=cognome.strip().upper()).first() is not None

    def trova_giocatore(self, nome, cognome):
        """Ritorna un oggetto Giocatore di nome=nome.
           Se l'oggetto non e' a database, il metodo non ritorna nulla:
           trova_giocatore(nome, cognome)"""
        return Giocatore.query.filter_by(
            nome=nome.strip().upper(),
            cognome=cognome.strip().upper()).first()

    def tutti_giocatori(self):
        """Ritorna una tupla con tutti i Giocatori presenti a database"""
        return db.session.query(Giocatore).all()

    def modifica_valori(self, *args):
        """Aggiorna gli attributi dell'oggetto giocatore.
           Ritorna un messaggio da visualizzare sulla UI"""
        nome, cognome, valore, forma, ruolo = args
        self.giocatore.nome = nome.strip().upper()
        self.giocatore.cognome = cognome.strip().upper()
        self.giocatore.valore = int(valore.strip())
        self.giocatore.forma = int(forma.strip())
        self.giocatore.ruolo = ruolo.lower()
        db.session.commit()
        return '+++ Giocatore <%s> modificato!' % self.giocatore.cognome

    def cancella_giocatore(self, nome, cognome):
        """Cerca il giocatore di nome e cognome e lo cancella dal database.
           Ritorna un messaggio da visualizzare sulla UI"""
        giocatore = self.trova_giocatore(nome, cognome)
        db.session.delete(giocatore)
        db.session.commit()
        return '+++ Giocatore <%s> eliminato!' % cognome


if __name__ == '__main__':
    m = Model()
# view.py
__author__ = 'Banchellia'

import wx
from wx import html as wxhtml


class View(wx.Frame):
    def __init__(self, parent, title, controller=None):
        super(View, self).__init__(parent=parent, title=title)
        self.controller = controller
        self.giocatori = controller.tutti_giocatori()
        # Menu
        menubar = wx.MenuBar()
        self.SetMenuBar(menubar)

        # Menu Giocatore
        menu_giocatore = wx.Menu()
        menubar.Append(menu_giocatore, "Giocatore")
        self.menu_nuovo = menu_giocatore.Append(-1, "Nuovo Giocatore",
                        "Crea nuovo giocatore")
        self.menu_modifica = menu_giocatore.Append(-1, "Modifica Giocatore",
                        "Modifica dati giocatore")
        self.menu_elimina = menu_giocatore.Append(-1, "Elimina Giocatore",
                        "Elimina giocatore")

        # Menu Info
        menu_help = wx.Menu()
        menubar.Append(menu_help, "?")
        self.menu_about = menu_help.Append(-1, "about...",
                        "info software")
        self.menu_helpsw = menu_help.Append(-1, "help",
                        "software help")

        # Layout
        self.panel = Panel(parent=self, giocatori=self.giocatori)
        self.update_gap()
        self.SetSize((700, 700))
        self.Centre()
        self.Show()

        # Bind
        self.Bind(wx.EVT_MENU, self.nuovo_giocatore, self.menu_nuovo)
        self.Bind(wx.EVT_MENU, self.modifica_giocatore, self.menu_modifica)
        self.Bind(wx.EVT_MENU, self.elimina_giocatore, self.menu_elimina)
        self.Bind(wx.EVT_MENU, self.about, self.menu_about)
        self.Bind(wx.EVT_MENU, self.helpsw, self.menu_helpsw)
        self.Bind(wx.EVT_BUTTON, self.componi, self.panel.btn_componi)
        self.Bind(wx.EVT_BUTTON, self.esci, self.panel.btn_quit)
        self.Bind(wx.EVT_BUTTON, self.set_gap, self.panel.btn_set)

    # Callbacks
    def nuovo_giocatore(self, event):
        """Apre la subUI nuovo giocatore disattivando il frame principale"""
        self.Disable()
        self.new_view = ViewNuovoGiocatore(parent=self, title='Nuovo Giocatore')

    def modifica_giocatore(self, event):
        """Apre la subUI edit giocatore disattivando il frame principale"""
        self.Disable()
        self.edit_view = ViewEditGiocatore(parent=self, title='Edit Giocatore')

    def elimina_giocatore(self, event):
        """Apre la subUI elimina giocatore disattivando il frame principale"""
        self.Disable()
        ViewEliminaGiocatore(parent=self, title='Elimina Giocatore')

    def set_gap(self, event):
        """Modifica il gap tra le due squadre"""
        gap = self.panel.gap.GetValue()
        msg = self.controller.set_gap(gap)
        InfoMessage(self, msg).get_choice()
        self.update_gap()

    def update_gap(self):
        """Aggiorna il textctrl del gap"""
        gap = self.controller.get_gap()
        self.panel.gap.SetValue(str(gap))

    def componi(self, event):
        """Richiama l'algoritmo di composizione del controller"""
        self.panel.verde.Clear()
        self.panel.gialla.Clear()
        selezionati = self.panel.clb_giocatori.GetCheckedStrings()
        if len(selezionati) % 2 == 1:
            InfoMessage(self, 'Giocatori dispari').get_choice()
        elif len(selezionati) == 0:
            InfoMessage(self, 'Seleziona i giocatori!').get_choice()
        else:
            self.controller.componi(selezionati)

    def update_squadre(self, verde, gialla):
        """Compone con le due squadre, le listbox relative"""
        InfoMessage(self, """Composizione riuscita!\n""").get_choice()
        self.panel.verde.Clear()
        self.panel.gialla.Clear()
        self.panel.verde.AppendItems(verde)
        self.panel.gialla.AppendItems(gialla)

    def esci(self, event):
        self.Destroy()

    def helpsw(self, event):
        self.Disable()
        HelpFrame(parent=self, title='Help "Calcio a 7"')

    def about(self, event):
        self.Disable()
        AboutFrame(parent=self, title='About "Calcio a 7"')

    def alert(self, msg):
        InfoMessage(self, msg).get_choice()

class Panel(wx.Panel):
    def __init__(self, parent, giocatori):
        super(Panel, self).__init__(parent=parent)
        self.gap = wx.TextCtrl(self)
        self.clb_giocatori = wx.CheckListBox(self, choices=sorted(giocatori),
                                             size=(250, 500))
        self.verde = wx.ListBox(parent=self, size=(180, 200), choices=[],
                                style=wx.LB_SINGLE)
        self.gialla = wx.ListBox(parent=self, size=(180, 200), choices=[],
                                style=wx.LB_SINGLE)
        self.btn_set = wx.Button(self, label='set GAP')
        self.btn_componi = wx.Button(self, label='Componi')
        self.btn_quit = wx.Button(self, label='Quit')

        sizer = wx.FlexGridSizer(rows=4, cols=3, hgap=5, vgap=5)

        sizer.Add(wx.StaticText(self, label="giocatori disponibili"),
                  1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
        sizer.Add(wx.StaticText(self, label="squadra VERDE"),
                  1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
        sizer.Add(wx.StaticText(self, label="squadra GIALLA"),
                  1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)

        sizer.Add(self.clb_giocatori, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
        sizer.Add(self.verde, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
        sizer.Add(self.gialla, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)

        sizer.Add(wx.StaticText(self, label="max gap squadre"),
                  1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
        sizer.Add(self.gap, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
        sizer.Add(self.btn_set, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
        sizer.Add(self.btn_componi,
                          1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
        sizer.Add(self.btn_quit,
                          1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5)
        self.SetSizer(sizer)


class ViewNuovoGiocatore(wx.Frame):
    '''GUI per creazione nuovo giocatore'''
    def __init__(self, parent, title):
        super(ViewNuovoGiocatore, self).__init__(parent=parent, title=title)
        self.parent = parent
        self.controller = self.parent.controller
        # Layout
        self.panel = PanelNuovoGiocatore(parent=self)
        self.SetSize((400, 300))
        self.Centre()
        self.Show()
        # Bind
        self.Bind(wx.EVT_BUTTON, self.salva_giocatore, self.panel.btn_save)
        self.Bind(wx.EVT_BUTTON, self.on_quit, self.panel.btn_cancel)

    def salva_giocatore(self, event):
        nome = self.panel.nome.GetValue()
        cognome = self.panel.cognome.GetValue()
        valore = self.panel.valore.GetValue()
        forma = self.panel.forma.GetValue()
        ruolo = self.panel.ruolo.GetStringSelection()
        if nome and cognome and valore and forma and ruolo:
            msg = self.controller.salva_nuovo_giocatore(
                nome, cognome, valore, forma, ruolo)
        else:
            msg = 'Inserisci tutti i valori'
        self.update_ui_nuovo_giocatore(msg)

    def on_quit(self, event):
        # Aggiorno ComboBox Top Frame
        giocatori = self.controller.tutti_giocatori()
        self.parent.panel.clb_giocatori.Clear()
        self.parent.panel.clb_giocatori.AppendItems(sorted(giocatori))
        self.parent.Enable()
        self.Destroy()

    def update_ui_nuovo_giocatore(self, msg):
        InfoMessage(parent=self, message=msg).get_choice()
        self.panel.nome.SetValue('')
        self.panel.cognome.SetValue('')
        self.panel.valore.SetValue('60')
        self.panel.forma.SetValue('60')
        self.panel.ruolo.SetLabel('scegli ruolo...')


class PanelNuovoGiocatore(wx.Panel):
    def __init__(self, parent):
        super(PanelNuovoGiocatore, self).__init__(parent=parent)
        self.nome = wx.TextCtrl(self)
        self.cognome = wx.TextCtrl(self)
        self.valore = wx.TextCtrl(self, value='60')
        self.forma = wx.TextCtrl(self, value="60")
        ruoli = ('portiere', 'difensore', 'ccampista', 'attaccante')
        self.ruolo = wx.ComboBox(self, -1, "scegli ruolo...", choices=ruoli,
                                 style=wx.CB_DROPDOWN)

        panel_sizer = wx.FlexGridSizer(rows=6, cols=2, hgap=5, vgap=5)
        panel_sizer.Add(wx.StaticText(self, label="* nome:"),
                  0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.nome, 0, wx.EXPAND | wx.ALL)
        panel_sizer.Add(wx.StaticText(self, label="** cognome:"),
                  0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.cognome, 0, wx.EXPAND | wx.ALL)
        panel_sizer.Add(wx.StaticText(self, label="valore (0/100):"),
                  0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.valore, 0, wx.EXPAND | wx.ALL)
        panel_sizer.Add(wx.StaticText(self, label="Stato di forma (0/100):"),
                  0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.forma, 0, wx.EXPAND | wx.ALL)
        panel_sizer.Add(wx.StaticText(self, label="ruolo:"),
                  0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.ruolo, 0, wx.EXPAND | wx.ALL)

        panel_sizer.AddGrowableCol(1)
        # button sizer
        button_sizer = wx.StdDialogButtonSizer()
        self.btn_save = wx.Button(self, wx.ID_SAVE)
        self.btn_save.SetDefault()
        self.btn_cancel = wx.Button(self, wx.ID_CANCEL)
        button_sizer.AddButton(self.btn_save)
        button_sizer.AddButton(self.btn_cancel)
        button_sizer.Realize()

        panel_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER|wx.ALL, 2)
        self.SetSizer(panel_sizer)


class ViewEditGiocatore(wx.Frame):
    '''GUI per modifica giocatore Esistente'''
    def __init__(self, parent, title):
        self.parent = parent
        super(ViewEditGiocatore, self).__init__(parent=self.parent, title=title)
        self.controller = self.parent.controller
        giocatori = self.controller.tutti_giocatori()
        # Layout
        self.panel = PanelEditGiocatore(parent=self, giocatori=giocatori)
        self.SetSize((400, 300))
        self.Centre()
        self.Show()
        # Bind
        self.Bind(wx.EVT_BUTTON, self.modifica_giocatore, self.panel.btn_save)
        self.Bind(wx.EVT_BUTTON, self.on_quit, self.panel.btn_cancel)
        self.Bind(wx.EVT_COMBOBOX, self.on_giocatore, self.panel.giocatori)

    def modifica_giocatore(self, event):
        nome = self.panel.nome.GetValue()
        cognome = self.panel.cognome.GetValue()
        valore = self.panel.valore.GetValue()
        forma = self.panel.forma.GetValue()
        ruolo = self.panel.ruolo.GetValue()
        if nome and cognome and valore and forma and ruolo:
            msg = self.controller.modifica_giocatore(nome, cognome, valore,
                                                     forma, ruolo)
            self.update_ui_edit_giocatore()

        else:
            msg = 'Inserisci tutti i valori o seleziona giocatore!'
        InfoMessage(self, msg).get_choice()

    def on_quit(self, event):
        giocatori = self.controller.tutti_giocatori()
        self.parent.panel.clb_giocatori.Clear()
        self.parent.panel.clb_giocatori.AppendItems(sorted(giocatori))
        self.parent.Enable()
        self.Destroy()

    def on_giocatore(self, event):
        cognome, nome = self.panel.giocatori.GetStringSelection().split(' ')[:2]
        self.controller.trova_giocatore(nome, cognome)

    def update_ui_edit_giocatore(self, giocatore=None):
        if giocatore:
            self.panel.nome.SetValue(giocatore.nome)
            self.panel.cognome.SetValue(giocatore.cognome)
            self.panel.valore.SetValue(str(giocatore.valore))
            self.panel.forma.SetValue(str(giocatore.forma))
            self.panel.ruolo.SetValue(giocatore.ruolo)
        else:
            self.panel.nome.SetValue('')
            self.panel.cognome.SetValue('')
            self.panel.valore.SetValue('')
            self.panel.forma.SetValue('')
            self.panel.ruolo.SetLabel('scegli ruolo...')

        self.panel.giocatori.Clear()
        self.panel.giocatori.AppendItems(sorted(
            self.controller.tutti_giocatori()))
        self.panel.giocatori.SetLabel('scegli...')


class PanelEditGiocatore(wx.Panel):
    def __init__(self, parent, giocatori):
        super(PanelEditGiocatore, self).__init__(parent=parent)
        self.giocatori = wx.ComboBox(self, -1, "scegli...",
                                     choices=sorted(giocatori),
                                     style=wx.CB_DROPDOWN)
        self.nome = wx.TextCtrl(self)
        self.cognome = wx.TextCtrl(self)
        self.valore = wx.TextCtrl(self)
        self.forma = wx.TextCtrl(self)
        ruoli = ('portiere', 'difensore', 'ccampista', 'attaccante')
        self.ruolo = wx.ComboBox(self, -1, "scegli ruolo...", choices=ruoli,
                                 style=wx.CB_DROPDOWN)

        panel_sizer = wx.FlexGridSizer(rows=8, cols=2, hgap=5, vgap=5)
        panel_sizer.Add(wx.StaticText(self, label="giocatori esistenti:"),
                        0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.giocatori, 0, wx.EXPAND | wx.ALL)
        panel_sizer.Add(wx.StaticText(self, label="nome:"),
                        0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.nome, 0, wx.EXPAND | wx.ALL)
        panel_sizer.Add(wx.StaticText(self, label="cognome:"),
                        0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.cognome, 0, wx.EXPAND | wx.ALL)
        panel_sizer.Add(wx.StaticText(self, label="valore (0/100):"),
                        0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.valore, 0, wx.EXPAND | wx.ALL)
        panel_sizer.Add(wx.StaticText(self, label="Stato di forma (0/100):"),
                        0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.forma, 0, wx.EXPAND | wx.ALL)
        panel_sizer.Add(wx.StaticText(self, label="ruolo:"),
                        0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.ruolo, 0, wx.EXPAND | wx.ALL)
        panel_sizer.AddGrowableCol(1)
        # button sizer
        button_sizer = wx.StdDialogButtonSizer()
        self.btn_save = wx.Button(self, wx.ID_SAVE)
        self.btn_save.SetDefault()
        self.btn_cancel = wx.Button(self, wx.ID_CANCEL)
        button_sizer.AddButton(self.btn_save)
        button_sizer.AddButton(self.btn_cancel)
        button_sizer.Realize()

        panel_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER|wx.ALL, 2)
        self.SetSizer(panel_sizer)

class ViewEliminaGiocatore(wx.Frame):
    """GUI per cancellazione giocatore Esistente"""
    def __init__(self, parent, title):
        self.parent = parent
        super(ViewEliminaGiocatore, self).__init__(
            parent=self.parent, title=title)
        self.controller = self.parent.controller
        giocatori = self.controller.tutti_giocatori()
        # Layout
        self.panel = PanelEliminaGiocatore(parent=self, giocatori=giocatori)
        self.SetSize((400, 150))
        self.Centre()
        self.Show()
        # Bind
        self.Bind(wx.EVT_BUTTON, self.elimina_giocatore, self.panel.btn_del)
        self.Bind(wx.EVT_BUTTON, self.on_quit, self.panel.btn_cancel)
        self.Bind(wx.EVT_COMBOBOX, self.on_giocatore, self.panel.giocatori)

    def elimina_giocatore(self, event):
        cognome, nome = self.panel.giocatori.GetStringSelection().split(' ')[:2]
        msg = 'Sicuro di voler eliminare %s?' % cognome
        if ChoiceMessage(self, msg).is_yes():
            msg = self.controller.cancella_giocatore(nome, cognome)
            InfoMessage(self, msg).get_choice()
            self.update_giocatori()

    def on_quit(self, event):
        giocatori = self.controller.tutti_giocatori()
        self.parent.panel.clb_giocatori.Clear()
        self.parent.panel.clb_giocatori.AppendItems(sorted(giocatori))
        self.parent.Enable()
        self.Destroy()

    def on_giocatore(self, event):
        self.panel.btn_del.Enable()

    def update_giocatori(self):
        self.panel.giocatori.Clear()
        self.panel.giocatori.AppendItems(
            sorted(self.controller.tutti_giocatori()))


class PanelEliminaGiocatore(wx.Panel):
    def __init__(self, parent, giocatori):
        super(PanelEliminaGiocatore, self).__init__(parent=parent)
        self.giocatori = wx.ComboBox(self, -1, "scegli...",
                            choices=sorted(giocatori), style=wx.CB_DROPDOWN)

        panel_sizer = wx.FlexGridSizer(rows=2, cols=2, hgap=5, vgap=5)
        panel_sizer.Add(wx.StaticText(self, label="giocatori esistenti:"),
                  0, wx.ALIGN_CENTER_VERTICAL, 10)
        panel_sizer.Add(self.giocatori, 0, wx.EXPAND | wx.ALL)
        panel_sizer.AddGrowableCol(1)
        # button sizer
        self.btn_del = wx.Button(self, wx.ID_DELETE)
        self.btn_del.Disable()
        self.btn_cancel = wx.Button(self, wx.ID_CANCEL)
        panel_sizer.Add(self.btn_del, 0, wx.EXPAND|wx.ALL, 2)
        panel_sizer.Add(self.btn_cancel, 0, wx.EXPAND|wx.ALL, 2)
        self.SetSizer(panel_sizer)


class InfoMessage(wx.MessageDialog):
    '''Simple message Dialog'''
    def __init__(self, parent, message):
        wx.MessageDialog.__init__(self, parent, message, 'core info', wx.OK |
                                  wx.ICON_EXCLAMATION)

    def get_choice(self):
        '''get the state of the user choice'''
        if self.ShowModal() == wx.ID_OK:
            self.Destroy()

class ChoiceMessage(wx.MessageDialog):
    '''Simple choice message Dialog'''
    def __init__(self, parent, message):
        wx.MessageDialog.__init__(self, parent, message, 'Core question',
                                  wx.YES_NO | wx.ICON_QUESTION)

    def is_yes(self):
        '''get True if YES is clicked'''
        if self.ShowModal() == wx.ID_YES:
            return True
        else:
            self.Destroy()

class AboutFrame(wx.Frame):
    """Frame for Abuot text"""
    def __init__(self, parent, title):
        super(AboutFrame, self).__init__(parent=parent, title=title)
        self.parent = parent
        self.text = """
        <html>
        <center><h1>Calcio a 7</h1> versione 2.1<br>
        by Bancaldo</td></center><br><br>
        <b>Calcio a 7</b> e' un semplice software per la creazione<br>
        di squadre il piu' possibile equilibrate<br>
        <br>
        <b>pacchetti utilizzati:</b><br>
        - wxPython</b> for Graphics<br>
        - Flask-SQLAlchemy</b> for database and Object Ralation Mapping<br>
        <br>
        <b>link utili:</b><br>
        web-site: www.bancaldo.wordpress.com<br>
        web-site: www.bancaldo.altervista.org<br>
        <br>
        <b>last revision:</b> Gen 22, 2015</p><br>
        <b>author:</b> bancaldo
        </html>
        """
        self.SetSize((400, 600))
        html = wxhtml.HtmlWindow(self)
        html.SetPage(self.text)
        self.btn_quit = wx.Button(self, -1, 'quit', (25, 150), (150, -1))
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(html, 1, wx.EXPAND|wx.ALL, 5)
        sizer.Add(self.btn_quit, 0, wx.ALIGN_CENTER|wx.ALL, 5)
        self.SetSizer(sizer)
        self.Centre()
        self.Show()

        # Bind
        self.Bind(wx.EVT_BUTTON, self.on_quit, self.btn_quit)

    # callback
    def on_quit(self, event):
        self.parent.Enable()
        self.Destroy()


class HelpFrame(wx.Frame):
    """Frame for Abuot text"""
    def __init__(self, parent, title):
        super(HelpFrame, self).__init__(parent=parent, title=title)
        self.parent = parent
        self.text = """
        <html>
        <center><b>Calcio a 7</b> help.</center><br><br>

        <b>1)</b> Al primo avvio viene creato il database 'giocatori.db'
        nella stessa directory.<br><br>

        <center><b>Gestione giocatori</b></center><br><br>

        <b>1)</b> inserire i giocatori nel database da <em>Nuovo Giocatore</em>
            del menu <em>Giocatore</em><br>
        ---- <b>1.a)</b> impostare i valori: nome, cognome, valore,
                         forma e ruolo.<br>
        ---------- <u>valore</u> e' l'indice di bravura del giocatore e va
                   da 0 a 100<br>
        ---------- <u>forma</u> e' lo stato di forma del giocatore, va
                   da 0 a 100.<br>
        ---- <b>1.b)</b> salvare il giocatore con l'apposito pulsante.<br><br>

        <b>2)</b> Modificare i valori di un giocatore da
              <em>Modifica Giocatore</em> del menu <em>Giocatore</em><br><br>

        <b>3)</b> Eliminare un giocatore da <em>Elimina Giocatore</em> del
             menu <em>Giocatore</em><br><br>

        <center><b>Composizione Squadre</b></center><br><br>

        <b>1)</b> selezionare i giocatori cliccando sui box a sx dei nomi<br>
        ---- <b>1.a)</b> Se sono dispari creare un giocatore JOLLY e
                         selezionarlo per avere la parita'.<br><br>

        <b>2)</b> Settare il massimo GAP ammesso tra le due squadre <br><br>

        <b>3)</b> Premere su componi per ottenere le squadre.<br>
        ---- <b>3.a)</b> Se non ci sono combinazioni, aumentare il GAP e
                         premere <b>Set new GAP</b>.<br>
        ---- <b>3.b)</b> Per ottenere invece squadre piu' equilibrate
                         diminuire il GAP</p>.<br><br>
        </html>
        """
        self.SetSize((700, 600))
        html = wxhtml.HtmlWindow(self)
        html.SetPage(self.text)
        self.btn_quit = wx.Button(self, -1, 'quit', (25, 150), (150, -1))
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(html, 1, wx.EXPAND|wx.ALL, 5)
        sizer.Add(self.btn_quit, 0, wx.ALIGN_CENTER|wx.ALL, 5)
        self.SetSizer(sizer)
        self.Centre()
        self.Show()

        # Bind
        self.Bind(wx.EVT_BUTTON, self.on_quit, self.btn_quit)

    # callback
    def on_quit(self, event):
        self.parent.Enable()
        self.Destroy()
Categorie:python, wxPython Tag:

Python: MVC con Observer per principianti

23 ottobre 2014 Commenti chiusi

Dopo l’assaggio in questo articolo, passiamo a questa versione di pattern MVC un po’ più elaborata.
Comprende anche il concetto di observer.
Per rendere il tutto il più chiaro possibile, utilizzeremo un programma molto semplice, ovvero un incrementatore di numero.

Come già visto, il pattern MVC si fonda su tre elementi principali:

– Il model che, nelle “retrovie” si occupa dei dati dell’applicazione e delle operazioni che si effettuano su di essi.

– La View, che si occupa di editare e visualizzare i dati.

– Il Controller che si occupa di gestire il flusso di dati, dal Model alla View e viceversa. Fa da collante tra i primi due oggetti.

Come dicevamo, all’Interno del Model, sarà implementato un Observer Pattern, che verrà spiegato di seguito.

Cominciamo con il definire il Model

class ModelInterface(object):
    """Definisce una interfaccia per il Model che
       gestisce l'incremento di un numero"""
    def __init__(self):
        super(ModelInterface, self).__init__()
        self.num = 0
        self.observers = [] # Inizializzo una lista di observers

    def incrementa(self):
        """Metodo interfaccia da implementare nelle sottoclassi"""
        raise NotImplementedError

    def set_value(self, num):
        self.num = num
        self.notifica_observer() # Ogni volta che viene modificato il numero

    def get_value(self):
        return self.num

    def notifica_observer(self):
        """Notifica chiamata ad ogni modifica di numero"""
        for observer in self.observers:
            observer()
            print "Click pulsante: numero incrementato a %s" \
                % self.get_value()

    def registra_observer(self, callback):
        """registro la callback dell'observer"""
        print "Registro la callback <%s>" % callback.__name__
        self.observers.append(callback)


class ModelIncrementa(ModelInterface):
    def incrementa(self):
        num = self.get_value() + 1
        self.set_value(num)

La prima classe, è l’interfaccia che verrà estesa con la successiva sottoclasse.
In questo specifico caso, l’interfaccia è il metodo incrementa, esteso da ModelIncrementa.
La View, avrà a che fare con tale metodo…
Nel Model, come si nota, sono previsti anche i due metodi relativi all’observer.
Il primo è collegato all’evento click sul pulsante, come vedremo dopo.
Il secondo è responsabile della registrazione della callback-observer.

Come si nota, Model non ha nessun riferimento alla View o al Controller, è all’oscuro di tutto.

Ora vediamo la View:

import wx


class View(wx.Frame):
    def __init__(self, parent, controller, model, title):
        super(View, self).__init__(parent=parent, title=title)

        self.panel = Panel(self, controller, model)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.panel, 1, wx.EXPAND)
        self.SetSizer(sizer)
        self.SetInitialSize((150, 150))

    def button_activated(self, state=True):
        self.panel.button.Enable(state)
        self.panel.button.SetBackgroundColour('Yellow')


class Panel(wx.Panel):
    def __init__(self, parent, controller, model):
        super(Panel, self).__init__(parent)
        #Attributi
        self.model = model
        self.controller = controller
        start_number = self.model.get_value()
        self.text = wx.TextCtrl(self, value='%s' % start_number)
        self.button = wx.Button(self, label='Incrementa')
        self.button.SetBackgroundColour('White')
        # Registro l'Observer
        self.model.registra_observer(self.on_model_update)
        # Handler evento click
        self.Bind(wx.EVT_BUTTON, self.on_click)
        # Creo il Layout
        self.__crea_layout()

    def __crea_layout(self):
        v_sizer = wx.BoxSizer(wx.VERTICAL)
        v_sizer.Add(self.text, 0, wx.ALIGN_CENTER|wx.ALL, 5)
        v_sizer.Add(self.button, 0, wx.ALIGN_CENTER)
        self.SetSizer(v_sizer)

    def on_model_update(self):
        """Metodo Observer"""
        numero = self.model.get_value()
        self.text.SetValue(str(numero))
        self.button.Enable(True)
        self.button.SetBackgroundColour('White')

    def on_click(self, event):
        self.controller.incrementa()

Qui come si nota, in fase di inizializzazione si crea un Panel, nel quale si instanziano il model esteso ed il controller esteso (tramite i metodi interfaccia).

        self.model = model
        self.controller = controller

Poi si inizializza il numero di partenza per visualizzarlo nel widget apposito:

start_number = self.model.get_value()

quello che sarà “start_number”, lo decido nel Model. La View non ha nessun potere su questo.

In seguito registriamo l’observer:

        self.model.registra_observer(self.on_model_update)
	...
    def on_model_update(self):
        """Metodo Observer"""
        numero = self.model.get_value()
        self.text.SetValue(str(numero))
        self.button.Enable(True)
        self.button.SetBackgroundColour('White')

In pratica: in fase di inizializzazione della View, registro l’observer, che nel model viene inserito nella lista degli observers:

# model.py
    def registra_observer(self, callback):
        """registro la callback dell'observer"""
        print "Registro la callback <%s>" % callback.__name__
        self.observers.append(callback)

Vediamo il Controller per concludere il ragionamento:

import wx
from view import View
from model import ModelIncrementa
import time


class ControllerInterface(object):
    """Definisce una interfaccia per il Controller che
       gestisce l'incremento di un numero"""
    def __init__(self, model):
        super(ControllerInterface, self).__init__()
        self.model = model
        self.view = View(parent=None, controller=self, model=self.model,
                         title='Incrementa')

        self.view.Show()

    def incrementa(self):
        raise NotImplementedError


class ControllerIncrementa(ControllerInterface):
    def incrementa(self):
        self.view.button_activated(False)
        self.model.incrementa()
        time.sleep(1)


class Core(wx.App):
    def OnInit(self):
        self.model = ModelIncrementa()
        self.controller = ControllerIncrementa(self.model)
        return True



if __name__ == '__main__':
    app = Core(False)
    app.MainLoop()

Torniamo alla View…

Creiamo la callback legata all’evento click del bottone:

        self.Bind(wx.EVT_BUTTON, self.on_click)

    def on_click(self, event):
        self.controller.incrementa()

Qui la View chiede al Controller cosa fare, anche qui c’è una netta separazione dei compiti.
Quando il bottone viene premuto, viene chiamato il metodo incrementa dell’interfaccia-controller per sapere cosa fare.

#controller.py
    def incrementa(self):
        self.view.button_activated(False)
        self.model.incrementa()
        time.sleep(1)

questo metodo agisce sulla View disattivando il bottone, poi
chiama il metodo incrementa dell’interfaccia model estesa…

class ModelIncrementa(ModelInterface):
    def incrementa(self):
        num = self.get_value() + 1
        self.set_value(num)

che preleva il numero dal ModelInterface e lo incrementa di 1…

        num = self.get_value() + 1

…e lo sostituisce al precedente…

        self.set_value(num)

…chiamando il metodo set_value di ModelInterface, che succede?

#model.py ModelInterface
    def set_value(self, num):
        self.num = num
        self.notifica_observer()

il numero viene sostituito dal valore incrementato e l’observer se ne accorge…

        self.notifica_observer()

ed esegue la callback registrata precedentemente;

    def notifica_observer(self):
        """Notifica chiamata ad ogni modifica di numero"""
        for observer in self.observers:
            observer() # on_model_update() di Panel

prelevando il numero…

numero = self.model.get_value()

visualizzandolo sulla textcontrol…

        self.text.SetValue(str(numero))

riattivando e ricolorando il bottono come all’inizio.

        self.button.Enable(True)
        self.button.SetBackgroundColour('White')

Ribadiamo i punti fondamentali del pattern MVC:

Il Model NON sa nulla del Controller e della View, ne è completamente estraneo.

La View, dal canto suo, non sa nulla di come il Model ed il Controller interagiscano tra loro e non sa come essi siano strutturati, poichè interagisce con loro, solo tramite le interfacce che li estendono, nel nostro caso i metodo incrementa() di ModelInterface esteso da ModelIncrementa e ControllerInterface esteso da ControllerIncrementa.
Quando premiamo il bottone, la View chiede al Controller cosa fare e per sapere quando un dato del Model viene modificato, registra una callback-observer, sul model stesso, per sapere quando la callback legata al pulsante, viene chiamata.

Il Controller come già detto, funge da collante tra i due oggetti precedenti.
Implementa il comportamento della View, in funzione dei cambiamenti di stato del Model.

Questa netta separazione dei compiti torna utile nel caso di riutilizzo del codice.
Potremmo ad esempio, invece di incrementare, decrementare il numero, senza dover mettere mano alla View, che non implementa nessuna operazione sui dati che visualizza.
Inoltre, potremmo effettuare semplici Unittest sul Model senza impazzire scorporando parti di codice innestati nella View o nel Controller.

Categorie:python, wxPython Tag:

python: calendario fantalega

1 settembre 2014 Commenti chiusi

Ecco una applicazione per creare un calendario con n squadre Pari.
Non tiene conto della giornata di riposo in caso di squadre dispari!
Testandola, dovrebbe tenere conto anche del “casa”, “fuoricasa”.

codice view:

# -*- coding: utf-8 -*-#
'''VIEW Module for FantaCalendario:
Graphic library: wx
Bindings are defined under CONTROLLER Module.
''' 
import wx, os

class FrameCal(wx.Frame):
    '''Main frame for FantaPython application'''
    def __init__(self, *args, **kwargs):
        self.nsq = kwargs.pop('nsq')
        wx.Frame.__init__(self, *args, **kwargs)
        self.panel = wx.Panel(self)
        self.panel.SetBackgroundColour('Pink')
        sq_cont = 1
        xpos, ypos = 100, 20
        while sq_cont &lt;= self.nsq:
            wx.StaticText(self.panel, wx.ID_NEW, 'squadra%s' % sq_cont,
                          pos = ((xpos - 85), ypos), size = (70, 25))
            wx.TextCtrl(self.panel, wx.ID_NEW,
                        pos = (xpos, ypos), size = (140, 25))
            ypos += 25
            sq_cont += 1
        
        self.btn_create = wx.Button(self.panel, wx.ID_NEW, 'Crea Calendario',
                                    size = (240, 25), pos = (0, (ypos)))
        self.SetSizeWH(250, (ypos + 65))
        self.Centre()
        self.Show()

class InfoMessage(wx.MessageDialog):
    '''Simple message Dialog'''
    def __init__(self, parent, message):
        wx.MessageDialog.__init__(self, parent, message, 'core info', wx.OK |
                                  wx.ICON_EXCLAMATION)
    def get_choice(self):
        '''get the state of the user choice'''
        if self.ShowModal() == wx.ID_OK:
            self.Destroy()

class ChoiceMessage(wx.MessageDialog):
    '''Simple choice message Dialog'''
    def __init__(self, parent, message):
        wx.MessageDialog.__init__(self, parent, message, 'Core question',
                                  wx.YES_NO | wx.ICON_QUESTION)
    def get_yes(self):
        '''get True if YES is clicked'''
        if self.ShowModal() == wx.ID_YES:
            return True
        else:
            self.Destroy()

class EntryDialog(wx.TextEntryDialog):            
    '''Simple Text Entry Dialog'''
    def __init__(self, parent, msg, value):
        wx.TextEntryDialog.__init__(self, parent, msg, 'Core request',
                                    defaultValue = value, style = wx.OK)
    def get_choice(self):
        '''get the state of the user choice'''
        if self.ShowModal() == wx.ID_OK:
            response = self.GetValue()
            self.Destroy()
            return response

class FileSaver(wx.FileDialog):
    '''Class for file Saver'''
    def __init__(self):
        self.f_save = None
        wildcard = &quot;File Calendario (*.txt)|*.txt|&quot; \
            &quot;Tutti i files (*.*)|*.*&quot;
        wx.FileDialog.__init__(self, None, &quot;salva il file&quot;, os.getcwd(),
                               &quot;&quot;, wildcard, wx.SAVE)
        if self.ShowModal() == wx.ID_OK:  
            print &quot;...salvo il file in: %s&quot; % (self.GetPath())
            self.output = self.GetPath()
            self.f_save = open(self.output, 'w')
        else:
            print &quot;operazione salvataggio annullata&quot;
            self.f_save = None
            self.Destroy()
        self.Destroy()

def main():
    '''app starter'''
    app = wx.PySimpleApp()
    n_sq = 8 # number of teams
    FrameCal(None, wx.ID_NEW, &quot;Calendario 1.1&quot;, nsq = n_sq)
    app.MainLoop()

if __name__ == '__main__':
    main()

codice controller:

'''FantaCalendario v 2.0
   Controller Module for FantaCalendario Application:
   All the binding method to frame widget are defined here'''

import wx

from View import (FrameCal, EntryDialog, InfoMessage, FileSaver)
from copy import copy


class Team(object):
    '''A team class'''
    def __init__(self, name, status=True):
        self.name = name
        self.casa = status
        
    def set_casa(self):
        &quot;&quot;&quot;set the status 'casa' to True&quot;&quot;&quot;
        self.casa = True

    def set_fuori(self):
        &quot;&quot;&quot;set the status 'fuori' to True&quot;&quot;&quot;
        self.casa = False


class Controller(object):
    '''Controller class for MVC-like pattern'''
    def __init__(self):
        n_sq = int(EntryDialog(None, &quot;Quante Squadre partecipano?&quot;,
                                     '8').get_choice())
        self.gui = FrameCal(None, wx.ID_NEW, &quot;Calendario 2.0&quot;, nsq=n_sq)
        self.gui.Bind(wx.EVT_BUTTON, self.on_create)

    def on_create(self, evt):
        '''create every &quot;team_x vs team_y&quot; combinations possible'''
        panel = evt.GetEventObject().GetParent()
        teams = []
        err = 0
        for widget in panel.GetChildren():
            if isinstance(widget, wx.TextCtrl):
                if widget.GetValue() != '':
                    teams.append(Team(widget.GetValue()))
                else:
                    err += 1
        if err &gt; 0:
            msg = &quot;mancano uno o piu' nomi squadra&quot;
            InfoMessage(panel.GetParent(), msg).get_choice()
        else:
            print teams
            crea_calendario(teams)
            self.gui.Close()


def crea_calendario(lista):
    '''crea gli accoppiamenti da una lista'''
    matrix = []
    cont = 0
    while cont &lt; len(lista):
        matrix.append([None] * len(lista))
        cont += 1
    matrix[0] = lista  # intestazione

    # Riga Intestazione invertita meno l'ultima squadra
    row2 = copy(lista)
    row2.pop()
    row2.reverse()
    matrix[1][0:(len(lista) - 1)] = row2[0:(len(lista) - 1)]

    # Composizione tabella prima FASE
    i = 1
    while i &lt; len(lista):
        k = 1
        for item in matrix[i]:
            try:
                matrix[i + 1][k] = item
                matrix[i + 1][0] = matrix[i + 1][(len(lista) - 1)]
                matrix[i + 1][(len(lista) - 1)] = None
                k += 1
            except IndexError:
                break
        i += 1

    # Composizione tabella seconda FASE
    row_m = 1
    while row_m &lt; len(lista):
        for item_a in matrix[0]:
            for item_b in matrix[row_m]:
                if matrix[0].index(item_a) == matrix[row_m].index(item_b):
                    if item_a == item_b:
                        matrix[row_m][matrix[row_m].index(item_b)] = lista[-1]
                        matrix[row_m][(len(lista) - 1)] = item_b
        row_m += 1

    # Stampa giornata
    cont = 1
    fbs = FileSaver()
    outputfile = fbs.f_save
    while cont &lt; len(lista):
        outputfile.write(&quot;\nGiornata n. &quot; + str(cont) + &quot;\n&quot;)
        andata = []
        for sq_a in matrix[0]:
            for sq_b in matrix[cont]:
                if matrix[0].index(sq_a) == matrix[cont].index(sq_b):
                    if sq_b not in andata or sq_a not in andata:
                        if sq_a.casa == True:
                            andata.append(sq_a)
                            andata.append(sq_b)
                            outputfile.write(sq_a.name + &quot;-&quot; + sq_b.name + &quot;\n&quot;)
                            sq_a.set_fuori()
                            sq_b.set_casa()
                        else:
                            andata.append(sq_b)
                            andata.append(sq_a)
                            outputfile.write(sq_b.name + &quot;-&quot; + sq_a.name + &quot;\n&quot;)
                            sq_a.set_casa()
                            sq_b.set_fuori()
        cont += 1
    outputfile.close()


def main():
    '''starter'''
    app = wx.PySimpleApp()
    Controller()
    app.MainLoop()

if __name__ == '__main__':
    main()

il funzionamento è semplicissimo:
si avvia, si sceglie il numero di squadre:
cal_1
si mettono i nomi delle squadre:
cal_2
si preme il pulsante crea e si sceglie un nome per la destinazione in txt, che poi potrà essere importata ad esempio in excel.

Giornata n. 1
A-C
B-D

Giornata n. 2
D-A
C-B

Giornata n. 3
A-B
D-C

link binario (exe)

Categorie:FantaLega, python, wxPython Tag:

ProgressBar riutilizzabile alleggerita

9 settembre 2011 Commenti chiusi

in riferimento alla vecchia versione, ho snellito il codice, sempre utilizzando un ProgressDialog:

'''
ProgressDialog sample for progress bar generating.
wx.ProgressDialog(title, message, maximum, parent, style)

style type:
wx.PD_APP_MODAL - the progress dialog will block all user events
wx.PD_AUTO_HIDE - The progress dialog will automatically hide itself
                  when it reaches its maximum value.
wx.PD_CAN_ABORT - Puts a Cancel button on box for stop the process.
wx.PD_ELAPSED_TIME - Displays the elapsed time
wx.PD_ESTIMATED_TIME - Displays an estimate of the total time to complete
                       the process.
wx.PD_REMAINING_TIME - Displays the amount of time remaining in a process,
                       estimated time - elapsed time.
'''

import wx

class ProgressBar(wx.ProgressDialog):
    '''Progress Bar class'''
    def __init__(self, *args, **kwargs):
        self.count = 0
        wx.ProgressDialog.__init__(self, *args, **kwargs)
        self.pmax = kwargs['maximum']
    def update_bar(self):
        '''update the progress bar'''
        while self.count < self.pmax:
            self.count += 1
            wx.MilliSleep(1)
            self.Update(self.count)
    
def main():
    '''app starter'''
    app = wx.PySimpleApp()
    app.MainLoop()
    max_item = 50 # range or total numer of lines in a file or....
    pbar = ProgressBar(title = "progress...", message = "Time remaining",
                       maximum = max_item, parent = None, 
                       style = wx.PD_AUTO_HIDE | wx.PD_ELAPSED_TIME |
                       wx.PD_REMAINING_TIME)   
    pbar.update_bar()
    pbar.Destroy()
    
if __name__ == "__main__":
    main()

max_item è ovviamente il parametro che indica la lunghezza massima della progress bar. Se per esempio stessimo parsando un file di testo, max_item sarebbe il numero di righe del file…

Categorie:python, wxpython, wxPython Tag: