EINFÜHRUNG |
Die Reservation von Sitzplätzen in Flugzeugen und Konzertsälen erfolgt heute fast ausnahmslos über Online-Reservationssysteme. Die Informationen werden dabei mit Online-Datenbanken verwaltet. Für die Entwicklung sind Datenbank-Spezialisten mit guten Programmierkenntnissen verantwortlich. |
RESERVATIONSSYSTEM TEIL 1: BENUTZERINTERFACE |
Das Reservationssystem präsentiert sich dem Benutzer mit einer attraktiven Benutzeroberfläche. Diese kann mit einem eigenständigen Programm oder als Webseite erzeugt werden. Bei Sitzplatz-Reservationssystemen für Konzertsäle und Flugzeuge wird üblicherweise der Grundriss des Raumes bzw. des Flugzeuges dargestellt, auf dem die Sitze eingezeichnet sind. Bereits reservierte Sitze werden mit einer besonderen Farbe gekennzeichnet, beispielsweise freie grün und bereits reservierte rot. Der Benutzer wählt eine Sitzplatzoption durch einen Mausklick auf einen freien Sitz. Dieser wechselt dabei seine Farbe, er wird beispielsweise gelb. Diese Wahl wird noch nicht zum Datenbankserver übertragen, da der Benutzer oft mehrere zusammengehörende Sitze gleichzeitig reservieren möchte. Erst beim Klicken auf einen Confirm-Button, wird der Reservationsprozess durchgeführt. Für die Implementierung des graphischen Benutzerinterfaces ist die Gamelibrary JGameGrid hervorragend geeignet, da sich die Sitze meist gitterartig anordnen lassen. Für die Speicherung des aktuellen Zustands (frei, option, reserviert) können die Sprite-Identifier (0, 1, 2) verwendet werden.
Mit diesem kurzen Programm hast du bereits ein voll funktionsfähiges Benutzerinterface realisiert. Es fehlt natürlich noch die Anbindung an die Datenbank [mehr... Wenn du etwas nicht verstehst, so kannst du dich an den Beispielen im Kapitel Games & OOP orientieren] . from gamegrid import * def toLoc(seat): i = ((seat - 1) % 6) + 1 k = ((seat - 1) // 6) + 2 return Location(i, k) def toSeatNb(loc): if loc.x < 1 or loc.x > 6 or loc.y < 2 or loc.y > 6: return None i = loc.x - 1 k = loc.y - 2 seatNb = k * 6 + i + 1 return seatNb class MyButton(GGButton, GGButtonListener): def __init__(self, imagePath): GGButton.__init__(self, imagePath) self.addButtonListener(self) def buttonClicked(self, button): if button == confirmBtn: confirm() if button == renewBtn: renew() def buttonPressed(self, button): pass def buttonReleased(self, button): pass def renew(): setStatusText("View refreshed") def confirm(): for seatNb in range(1, 31): if seats[seatNb - 1].getIdVisible() == 1: seats[seatNb - 1].show(2) refresh() setStatusText("Reservation successful") def pressCallback(e): loc = toLocation(e.getX(), e.getY()) seatNb = toSeatNb(loc) if seatNb == None: return seatActor = seats[seatNb - 1] if seatActor.getIdVisible() == 0: # free seatActor.show(1) # option refresh() elif seatActor.getIdVisible() == 1: # option seatActor.show(0) # free refresh() makeGameGrid(8, 8, 40, None, "sprites/stage.gif", False, mousePressed = pressCallback) addStatusBar(30) setTitle("Seat Reservation") setStatusText("Please select free seats and press 'Confirm'") confirmBtn = MyButton("sprites/btn_confirm.gif") renewBtn = MyButton("sprites/btn_renew.gif") addActor(confirmBtn, Location(1, 7)) addActor(renewBtn, Location(6, 7)) seats = [] for seatNb in range(1, 31): seatLoc = toLoc(seatNb) seatActor = Actor("sprites/seat.gif", 3) seats.append(seatActor) addActor(seatActor, seatLoc) addActor(TextActor(str(seatNb)), seatLoc) show()
|
MEMO |
Die Umrechnung von Sitznummern auf Locations und umgekehrt wird in zwei Transformationsfunktionen erledigt. Solche Mappingfunktionen werden oft mit to.. eingeleitet. |
RESERVATIONSSYSTEM TEIL 2: ANBINDUNG AN DIE DATENBANK |
Online-Datenbanken sind Mehrbenutzer-Systeme. Weil mehrere Clients die Daten gleichzeitig manipulieren, können je nach Situation heikle Zugriffskonflikte auftreten. Es liegt in der Natur solcher Probleme, dass sie nur sporadisch auftreten und darum schwierig zu meistern sind. Das folgende Szenario beschreibt einen typischen Konfliktfall: A und B können mit einem Mausklick die gewählten Sitze als Option auswählen. Die optierten Sitze werden gelb gefärbt. Diese Optionen werden aber der Datenbank nicht übermittelt, da der Benutzer sie noch verändern oder mit weiteren Optionen ergänzen will. Erst nach einiger Zeit, die bei A und B unterschiedlich lange dauert, klickt der schneller entschlossene Benutzer A den Confirm-Button, um die Option definitiv zu machen. Die Datenbank setzt die Sitze in den Zustand reserviert (booked = 'Y'). Von dieser Veränderung der Datenbank merkt allerdings der Kunde B nichts, da die Datenbank von sich aus keine Rückmeldungen an B macht und A natürlich auch nicht im direkten Kontakt mit B ist. [mehr... In einer Client-Server-Umgebung kann der Server von sich aus keine Mitteilungen an den Client versenden]. Nach einer gewissen Zeit entscheidet sich auch Kunde B und drückt den Confirm-Button.
Achtung: Die Ausführung dieses Programms setzt voraus, dass du den Datenbankserver gestartet, die Tabelle reservation erzeugt und die Tabelle mit Initialisierungsdaten gefüllt hast (siehe vorhergehendes Kapitel). from dbapi import * from gamegrid import * serverURL = "derbyserver:localhost" #serverURL = "derbyserver:10.1.1.123" dbname = "casino" username = "admin" password = "solar" tbl = "reservation" def toLoc(seat): i = ((seat - 1) % 6) + 1 k = ((seat - 1) // 6) + 2 return Location(i, k) def toSeatNb(loc): if loc.x < 1 or loc.x > 6 or loc.y < 2 or loc.y > 6: return None i = loc.x - 1 k = loc.y - 2 seatNb = k * 6 + i + 1 return seatNb def pressCallback(e): loc = toLocation(e.getX(), e.getY()) seatNb = toSeatNb(loc) if seatNb == None: return seatActor = seats[seatNb - 1] if seatActor.getIdVisible() == 0: # free seatActor.show(1) # option refresh() elif seatActor.getIdVisible() == 1: # option seatActor.show(0) # free refresh() class MyButton(GGButton, GGButtonListener): def __init__(self, imagePath): GGButton.__init__(self, imagePath) self.addButtonListener(self) def buttonClicked(self, button): if button == confirmBtn: confirm() if button == renewBtn: renew() def buttonPressed(self, button): pass def buttonReleased(self, button): pass def renew(): with connect(serverURL, dbname, username, password) as con: cursor = con.cursor() sql = "SELECT * FROM " + tbl cursor.execute(sql) con.commit() result = cursor.fetchall() for record in result: seatNb = record[0] isBooked = (record[1] != 'N') if isBooked: seats[seatNb - 1].show(2) else: seats[seatNb - 1].show(0) refresh() setStatusText("View refreshed") def confirm(): # check if seats is still available with connect(serverURL, dbname, username, password) as con: cursor = con.cursor() for seatNb in range(1, 31): if seats[seatNb - 1].getIdVisible() == 1: sql = "SELECT * FROM " + tbl + " WHERE seat=" + str(seatNb) cursor.execute(sql) result = cursor.fetchall() for record in result: if record[1] == 'Y': setStatusText("One of the seats are already taken.") return isReserved = False for seatNb in range(1, 31): if seats[seatNb - 1].getIdVisible() == 1: sql = "UPDATE " + tbl + " SET booked='Y' WHERE seat=" + \ str(seatNb) cursor.execute(sql) isReserved = True con.commit() renew() if isReserved: setStatusText("Reservation successful") else: setStatusText("Nothing to do") makeGameGrid(8, 8, 40, None, "sprites/stage.gif", False, mousePressed = pressCallback) addStatusBar(30) setTitle("Seat Reservation - Loading...") confirmBtn = MyButton("sprites/btn_confirm.gif") renewBtn = MyButton("sprites/btn_renew.gif") addActor(confirmBtn, Location(1, 7)) addActor(renewBtn, Location(6, 7)) seats = [] for seatNb in range(1, 31): seatLoc = toLoc(seatNb) seatActor = Actor("sprites/seat.gif", 3) seats.append(seatActor) addActor(seatActor, seatLoc) addActor(TextActor(str(seatNb)), seatLoc) show() renew() setTitle("Seat Reservation - Ready") setStatusText("Select free seats and press 'Confirm'") while not isDisposed(): delay(100)
|
MEMO |
Du kannst das Reservationssystem mit mehreren Benutzerfenster testen, indem du auf deinem Computer die TigerJython IDE mehrmals startest und das gleiche Programm ausführst. Sind alle Plätze reserviert, so kannst du die Tabelle (wie im vorangehenden Kapitel gezeigt) löschen und wieder neu erstellen. |
AUFGABEN |
|