Architettura dell'applicazione PyQt

3

Sto provando a dare una struttura sonora a un'applicazione PyQt che implementa un gioco di carte. Finora ho le seguenti classi:

  • Ui_Game: questo descrive l'interfaccia utente ed è responsabile di reagendo agli eventi emessi dalle istanze di CardWidget

  • MainController: questo è responsabile della gestione del tutto applicazione: configurazione e tutti gli stati successivi dell'applicazione (come iniziare una nuova mano, visualizzare la notifica di stato cambia sull'interfaccia utente o termina il gioco)

  • GameEngine: questo è un insieme di classi che implementano l'intero gioco logica

Ora, il modo in cui l'ho codificato concretamente in Python è il seguente:

class CardWidget(QtGui.QLabel):
    def __init__(self, filename, *args, **kwargs):
        QtGui.QLabel.__init__(self, *args, **kwargs)
        self.setPixmap(QtGui.QPixmap(':/res/res/' + filename))

    def mouseReleaseEvent(self, ev):
        self.emit(QtCore.SIGNAL('card_clicked'), self)

class Ui_Game(QtGui.QWidget):
    def __init__(self, window, *args, **kwargs):
        QtGui.QWidget.__init__(self, *args, **kwargs)
        self.setupUi(window)
        self.controller = None

    def place_card(self, card):
        cards_on_table = self.played_cards.count() + 1
        print cards_on_table

        if cards_on_table <= 2:
            self.played_cards.addWidget(card)
            if cards_on_table == 2:
                self.controller.play_hand()

class MainController(object):
    def __init__(self):
        self.app = QtGui.QApplication(sys.argv)
        self.window = QtGui.QMainWindow()
        self.ui = Ui_Game(self.window)
        self.ui.controller = self
        self.game_setup()

C'è un modo migliore oltre a iniettare il controller nella classe Ui_Game in Ui_Game.controller? O sono totalmente fuori strada?

    
posta Lorenzo 21.10.2012 - 15:09
fonte

1 risposta

8

Direi che dovresti fare il contrario, un buon progetto sarebbe che la tua applicazione sia in grado di eseguire qualunque sia il suo contesto. Ecco perché per ogni applicazione che codifico, creo uno strumento CLI che implementa la logica e quindi implemento una GUI. Dove mi sto dirigendo?

Stai creando un oggetto MainController che contiene il mondo, quindi modifica l'oggetto Ui_Game per restituire un riferimento a se stesso. Non è elegante, e dato il tuo contesto non è il modo migliore.

Se vuoi davvero andare in questo modo dovresti invece fare quanto segue:

class Ui_Game(QtGui.QWidget):
    def __init__(self, controller, *args, **kwargs):
        QtGui.QWidget.__init__(self, *args, **kwargs)
        self.setupUi(controller.window)
        self.controller = controller

[...]

Ui_Game(self)

Questo è per l'eleganza.

Ma per il tuo contesto, ti consiglierei di separare completamente la logica di gioco dalla logica dell'interfaccia utente, e quindi avere qualche funzione iniziale o principale che inizializzi tutti gli oggetti e li unisca insieme. Inoltre, si crea un widget che sembra popolarsi all'interno della finestra, mentre il widget non deve sapere dove verrà utilizzato. Quindi qui qualcosa di simile a quello che farei:

class GameGUI:
    def __init__(self, game):
        # so you can give all your UI elements a game to play with
        self.game = game 
        # start and populate the Ui_Game stuff
        self.app = QtGui.QApplication(sys.argv)

    def main_loop(self):
        # wait for the UI to cease
        return self.app._exec()

def start():
    # here you can argparse your CLI arguments, so you can choose
    # your interface (readline, ncurses, Qt, web, whatever...?)
    # and setup your application (logfile, port to bind to, look 
    # of the GUI...)
    game = MyGame()
    game.setup()
    return GameGUI(game).main_loop()

import sys
if __name__ == "__main__":
    sys.exit(start())

Quindi, ora il flusso è più limpido:

  • si avvia nella funzione start (), che preparerà l'ambiente per il corretto funzionamento dell'applicazione
    • controlla eventuali argomenti,
    • inizializza il gioco,
    • dai alla GUI,
    • crea la GUI (tramite GameGUI che creerà le finestre e i widget)
    • avvia la GUI (tramite main_loop ())

Ricorda sempre che l'OOP è tutto incentrato sul disaccoppiamento.

HTH

    
risposta data 05.11.2012 - 10:15
fonte

Leggi altre domande sui tag