EVA Prinzip bei Klassen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
honk0190
User
Beiträge: 9
Registriert: Dienstag 20. April 2010, 12:43

Hallo Zusammen,

ich habe ein Problem beim verarbeiten von 2 Klassen.
Ich habe ,grob gesagt, 2 Klassen, die eine baut mir eine UI (Ausgabe) und die andere ist Eingabe,Verarbeitung.

Nun erzeuge ich meine UI und initialisiere damit auch gleich meine E:V. Die UI baut sich aber erst, wenn E:V fertig sind, das möchte ich aber nicht, da die E:V in einer schleife laufen.
Hier mein Code:

Code: Alles auswählen


class MyGuiClass(QtGui.QMainWindow):
    def __init__(self, uiRef):
        QtGui.QMainWindow.__init__(self, None)
        self.uiRef = uiRef
        uiRef.setupUi(self)
        
        self.blub = DoIt()

        self.uiRef.comboBox.addItem("AV42_test")
        self.uiRef.comboBox.addItem("AV42_work")

    def changeState(self, objectName, state):
        self.uiRef.__getattribute__(objectName).setStyleSheet(self.getImage(state))


    def getImage(self, state):
        if state == '1':
            return green
        elif state == '0':
            return blue
        else:
            return black 
    def bla(self):
        i = 3
        while i > 0:
            i= i-1
            self.blub.doChange()
            time.sleep(2)
    def killer(self):
        self.blub.killAll()

class DoIt():
    def __init__(self):
        global lItems 
        lItems =  self.getItems()
        clientPath="a2.out"
        global client 
        client = subprocess.Popen(clientPath,
          shell=True,
          stdout=subprocess.PIPE,
          stdin=subprocess.PIPE)
        if not os.path.exists(clientPath):
            print "ERROR: Can't find ", clientPath
            print "Bye..."
            sys.exit()

#--------------------------Main---------------------------#
app = QtGui.QApplication(sys.argv)
uiBauer = av42_create.Ui_MainWindow()
hauptGui = MyGuiClass(uiBauer)
hauptGui.show()
hauptGui.bla()
hauptGui.killer()
app.exec_()

kann mir jemand einen Tip geben, wie ich das besser lösen kann.

Die Ui soll einfach nur laufen und alle 5 sekunden werden die Daten neu eingelesen und die UI soll sich neu Updaten.
Kann mal dabei die Zeit als Event benutzen?

Vielen Dank für jede Antwort

MfG

Honk
BlackJack

@honk0190: ``global`` ist eine schlechte Idee. Wozu Code und Daten in Klassen aufteilen wenn das ganze dann doch wieder über globale Variablen undurchsichtig verwoben wird!?

`blub`, `bla`, und `DoIt` sind nichtssagende Namen. `killer` ist ein schlechter Name für eine Methode, weil er keine Tätigkeit beschreibt.

Ist der direkte Aufruf von `__getattribute__` wirklich nötig? Warum reicht die `getattr()`-Funktion nicht?

Warum ist die Funktion `getImage()` als Methode auf der Klasse? Man kann diese ``if``/``elif``-Kaskaden auch mit einem Dictionary ausdrücken:

Code: Alles auswählen

def get_image(state):
    return {'1': GREEN, '0': BLUE}.get(state, BLACK)
Länger laufende Methoden in GUIs sind keine gute Idee. `bla()` blockiert die GUI 6 Sekunden lang. Das könnte dem Benutzer unangenehm auffallen. GUI Toolkits bieten dafür in der Regel Rückrufmechanismen zum Beispiel in Form von Timer-Objekten an. Mal so geraten: in der Qt-Dokumentation nach QTimer suchen.

Der V-Teil von EVA sollte unabhängig von der GUI sein, also keine GUI Elemente kennen müssen. Also ist eine VA-Klasse wahrscheinlich keine so gute Idee. GUI wäre eher eine EA-Klasse.
problembär

honk0190 hat geschrieben:ich habe ein Problem beim verarbeiten von 2 Klassen.
Ich habe ,grob gesagt, 2 Klassen, die eine baut mir eine UI (Ausgabe) und die andere ist Eingabe,Verarbeitung.
Nun erzeuge ich meine UI und initialisiere damit auch gleich meine E:V. Die UI baut sich aber erst, wenn E:V fertig sind, das möchte ich aber nicht, da die E:V in einer schleife laufen.
kann mir jemand einen Tip geben, wie ich das besser lösen kann.
Ja, man verwendet dazu nicht zwei, sondern drei Klassen, genannt Model, View und Controller (wie BlackJack genau weiß).

Gruß
sandra84
User
Beiträge: 17
Registriert: Mittwoch 9. Juni 2010, 06:34

eigentlich sinds 3 klassen wenn ich das so sehe.

Die Frage interessiert mich aber auch (hab python erst vor n paar tagen angefangen).
Hat jmd ein kleines Beispiel? (Aber nich vom MVC Modell das kenn ich aus Grails aber dieses autom. aktualisieren)
honk0190
User
Beiträge: 9
Registriert: Dienstag 20. April 2010, 12:43

Hallo zusammen,

also ich hab die Änderungen übernommen und einen ctimer benutzt aber komme jetzt schon wieder nicht weiter.
Wenn ich jetzt den ctimer starte

Code: Alles auswählen

self.connect(self.ctimer, QtCore.SIGNAL("timeout()"), self.worker.doChange)
bringt er mir einen Fehler:

Traceback (most recent call last):
File "D:\work\Uebung\src\av42aktuell\av42_use.py", line 144, in doChange
ret = self.sendCommand(cmdToSend)
File "D:\work\Uebung\src\av42aktuell\av42_use.py", line 120, in sendCommand
self.client.stdin.write(cmd +"\n")
IOError: [Errno 22] Invalid argument

Wenn ich aber die funktion

Code: Alles auswählen

    def aufruf(self):
        i = 3
        while i > 0:
            i= i-1
            self.worker.doChange()
            time.sleep(2)
direkt aufrufe

Code: Alles auswählen

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    uiBauer = av42_create.Ui_MainWindow()
    hauptGui = MyGuiClass(uiBauer)
    hauptGui.show()
    hauptGui.aufruf()
    hauptGui.killapp()
    sys.exit(app.exec_())
funktioniert die Abfrage. Aber da ist dann eben wieder das Problem das die UI auf die Eingabe wartet.

Wo ist der fehler?
Hier nochmal die Klassen:

Code: Alles auswählen

class MyGuiClass(QtGui.QMainWindow):
    def __init__(self, uiRef):
        QtGui.QMainWindow.__init__(self, None)
        self.uiRef = uiRef
        uiRef.setupUi(self)
        self.ctimer = QtCore.QTimer()
        self.worker = DoIt()
        self.uiRef.comboBox.addItem("AV42_test")
        self.uiRef.comboBox.addItem("AV42_work")
        #self.connect(self.uiRef.set, QtCore.SIGNAL("clicked()"), self.aufrufTimer)
        #self.connect(self.ctimer, QtCore.SIGNAL("timeout()"), self.worker.doChange)
    def changeState(self, objectName, state):
        self.uiRef.__getattribute__(objectName).setStyleSheet(self.getImage(state))
    def getImage(self, state):
        return {'1': green, '0': blue}.get(state, black)
    def aufrufTimer(self):
        self.ctimer.start(1000)
    def aufruf(self):
        i = 3
        while i > 0:
            i= i-1
            self.worker.doChange()
            time.sleep(2)
    def killapp(self):
        self.worker.killAll()
class DoIt():
    def __init__(self):
        self.lItems =  self.getItems()
        clientPath="a2.out"
        self.client = subprocess.Popen(clientPath,
          shell=True,
          stdout=subprocess.PIPE,
          stdin=subprocess.PIPE)
        if not os.path.exists(clientPath):
            print "ERROR: Can't find ", clientPath
            print "Bye..."
            sys.exit()
    def getItems(self):
        f = open('av42_external.idx','r')
        aoffset = {}
        asystem = {}
        asignalname = {}
        asignalOffset = {}
        lAll= [aitems, bitems, citems, ditems]
        return lAll
    def getList(self, l):
        aList = []
        for x, y in l:
            aList.append(y)
        return aList 
    def sendCommand(self, cmd):
        self.client.stdin.write(cmd +"\n")
        self.client.stdin.flush()
        line =  self.client.stdout.readline().rstrip()
        self.client.stdout.flush()
        if line[:2] == "-1":
            return -1
        else:
            return line
    def doChange(self):
        x=0
        u=0
        get_signalname=self.getList(self.lItems[2])
        get_offset=self.getList(self.lItems[0])
        while (u < 10):
            u=u+1
            for i in get_offset:
                cmdToSend = "read " + i
                ret = self.sendCommand(cmdToSend)
                print i
                if (x == 58):
                    x=x-1
                hauptGui.changeState(get_signalname[x].replace("-","_"),ret)
                x=x+1
problembär

honk0190 hat geschrieben:Aber da ist dann eben wieder das Problem das die UI auf die Eingabe wartet.
Bei mir läuft das so:

1. Skript instantiiert Controller.
2. Controller initialisiert Model und View und gibt dabei jeweils sich selbst mit. Beispiel:

Code: Alles auswählen

class Model:
    def __init__(self, controller):
        self.controller = controller
        ...
In den ".__init__()"-Methoden von Model und View wird ansonsten erstmal noch nicht viel gemacht, außer ein paar Variablen auf Ausgangswerte gesetzt.
3. Programmablauf kehrt zurück zu Controller.
4. Controller startet View.showMain(). GUI wird erzeugt, der GUI-Mainloop gestartet. GUI wartet auf Benutzerinput.

Später:
5. View gibt User-Eingaben an Controller, bzw. genauer startet eine Methode in Controller, die die Verarbeitung der Benutzereingaben einleitet.
6. Controller übergibt User-Eingaben an Berechnungsfunktionen in Model.
7. Model gibt Berechnungsergebnisse an Controller.
8. Controller übergibt Berechnungsergebnisse an View zur Darstellung.
usw.

Logisch? (Hab' ich mir aber selbst zusammengetüftelt, viel Hilfe aus theoretischen Beschreibungen hab' ich dabei nicht erhalten.)

Gruß
Antworten