Hilfe bei Klassen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
agressor
User
Beiträge: 9
Registriert: Donnerstag 1. September 2011, 05:23

Morgen. Ich versuche mich grade etwas in python einzuarbeiten. Mit GUI-Programmierung habe ich nur vor vielen Jahren undter Delph etwas zu tun gehabt.

Nun zu meinem (verständniss)Problem.
Die GUI besitzt eine eigene klasse. innerhalb dieser kann ich funktionen für die einzelnen Slots definieren. ich versuche nun die elemente der GUI von außerhalb dieser Klasse zu maipulieren.
Das habe ich sowohl direkt mit der Bezeichnung des Elementes als auch durch den Aufruf einer Funktion innerhalb dieser GUI-Klasse versucht. Hatte aber keinen echten erfolg.

Code: Alles auswählen

import sys 
from PyQt4 import QtGui 
from PyQt4 import QtCore
from gmetertest import Ui_MainWindow as Dlg
from Boarddummy import Ui_MainWindow as Dlg2

class MeinDialog(QtGui.QDialog, Dlg): 
    def __init__(self): 
        QtGui.QDialog.__init__(self) 
        self.setupUi(self)
#Slots
        self.connect(self.menuBeenden, QtCore.SIGNAL("clicked()"), self.onQuit) 
        self.connect(self.B_Trennen, QtCore.SIGNAL("clicked()"), self.onTrennen) 
#        self.connect(self.S_G_YAchse, QtCore.SIGNAL("valueChanged(int)"), self.on_ySlider_change)
        self.connect(self.pushButton, QtCore.SIGNAL("clicked()"), self.Dummysenden)
        
        
    def onQuit(self): 
#         Methode zum Fensterschliessen  
        self.E_XAchse.setText("Schuess")
        self.close()
        
    def onTrennen(self):
        self.E_XAchse.setText("Test")
        value_xachsefine = self.S_F_XAchse.value()
        self.E_YAchse.setText(str(value_xachsefine))
        self.S_F_ZAchse.setValue(100)
    
    def on_ySlider_change(self):
        value = self.S_G_YAchse.value()
        valuecut = value
        if value > 200: valuecut = 200
        if value < -200: valuecut = -200
        self.S_F_YAchse.setValue(valuecut)
        self.E_YAchse.setText(str(value))
        
    def on_Call(self):
        self.E_XAchse.setText("Weg2")
        self.S_F_XAchse.setValue(100)

    def Dummysenden(self):
        valueX = self.verticalSlider.value()
        valueY = self.verticalSlider_2.value()
        valueZ = self.verticalSlider_3.value()
        tempText = self.EB_Terminal.toPlainText()
        sendString = "S: X" + str(float(valueX)/100) + " Y" + str(float(valueY)/100) + " Z" + str(float(valueZ)/100)
        tempText = sendString + " \n" + tempText
        self.EB_Terminal.setText(tempText)
        Reciver("test")
       

def Reciver(Input):
        print Input + "Global"
        test = MeinDialog()
        test.on_Call()
        
app = QtGui.QApplication(sys.argv) 
dialog = MeinDialog() 
dialog.show() 
print "test"
sys.exit(app.exec_())
inhalt der GUI soll sein über RS232 ein Controllerboard einzulesen das mit einem Accelerometer ausgestattet ist und die werte ersteinmal anzeigen und später auch grafisch darzustellen.

zum Ablauf des Porgrammes.
- pushButton wird betätigt
-> klasseninterne Funktion "Dummysenden" wird aufgerufen
-> nach erfolgreicher abarbeitung der internen Befehle wird die externe Funktion "Reciver" gerufen ind ihr Werte übergenen.
-> diese Werte werden auch übernommen und durch den Code der externen Funktion ausgeführt
-> in dieser Funktion versuche ich die Klasseninterne Funktion "on_Call" aufzurufen aber doert scheitert alles dann und ich verstehe nicht warum.

ich habe ein anderes Programm geschrieben, dass aus 2 Klassen mit mehreren internen Funktionen und mehreren Hauptebenen funktionen besteht. in diesem Programm funktionieren die funktionsaufrufe super egal in welchen richtungen. klassen intern von klasse zu klasse. Alsses halt.
So langsam wächst die Frustration.

Ich bitte also um ein paar Tipps.
wie rufe ich eine funktion innerhalb DIESER Klasse auf
wie manipuliere ich die Elemente der GUI von außerhalb der GUI-Klasse

mfg
BlackJack

@agressor: Du rufst in `Reciver()` die `on_Call()`-Methode eines gerade neu erstellten, aber nicht angezeigten Dialog-Exemplars auf. Das hat natürlich keinen Einfluss auf das Dialogexemplar aus dem heraus die Funktion aufgerufen wurde. Wenn Du auf dem etwas aufrufen willst, müsstest Du es der Funktion als Argument übergeben. Ich glaube Du hast gedanklich den Schritt zwischen Klasse und Exemplar ausgelassen. Eine Klasse ist ein Objekt, welches das Verhalten von Exemplaren beschreibt, die man daraus erstellen kann. Diese Exemplare sind voneinander unabhängig. Wenn man zwei Dialoge erstellt, dann beeinflussen die sich gegenseitig nicht. Jeder hat seine eigenen Ein- und Ausgabeelemente.

Ich nehme mal an das ist nur weil es ein Test ist, aber durchnummerierte `verticalSlider`-Namen sind nicht so toll. Ein Name sollte die Bedeutung verraten und nicht nur den Typ.

Zeichenketten mit ``+`` und `str()` zusammensetzen ist ein wenig „unpythonisch”. Dafür nimmt man eher den ``%``-Operator oder die `format()`-Methode auf Zeichenketten:

Code: Alles auswählen

        sendString = 'S: X%s Y%s Z%s \n' % (
            valueX / 100.0, valueY / 100.0, valueZ / 100.0
        )
Du könntest übrigens die neue (ist mittlerweile gar nicht mehr sooo neu) Art zum Verbinden von Signalen verwenden:

Code: Alles auswählen

self.connect(self.menuBeenden, QtCore.SIGNAL("clicked()"), self.onQuit)
# <=>
self.menuBeenden.clicked.connect(self.onQuit)
agressor
User
Beiträge: 9
Registriert: Donnerstag 1. September 2011, 05:23

@BlackJack
Python "lerne" ich mit den Openbooks Phython von GalileoComputing. Für schritt für schritt lernen hatte ich noch nie nerven. Ich komme programmiertechnich von einem BASIC-Dialekt, der speziell auf Controller angepasst wurde, die wir bei mir in der Firma verwenden. (nich das ich softi wäre). Daher einige unorthodoxe "Gramatik" meines Codes.

Die durchnummerierten Veritvals sind ein dirty-hack. Dieser teil fliegt natürlich raus wenn ich dann über serielle die Daten einhole.

nun aber zum zentralen Teil meiner Frage und deiner Antwort. so ganz verstehe ich dich nich. "on_call" liegt innerhalb der Klasse, die den sichtbaren Dialog erzeugt. der eigentliche Dialog liegt (entsprechend des Buches) in einer externen datei. dieser ist zum Zeitpunkt aber schon aktiv und sichtbar.
mir fehlt, um deiner erklährung zu folgen echt 3-4 Meter Film. ich arbeite meistens über Beispiele, die ich dann manipuliere.
BlackJack

@agressor: Das OpenBook ist gerade was OOP angeht nicht gut.

Mit `MeinDialog()` erstellst Du ein Exemplar des Dialogs. Das machst Du auf Modulebene und zeigst den auch an (`show()`-Methode), aber in `Receiver()` erstellst Du noch ein Exemplar von dem Dialog und rufst auf dem, nicht angezeigten Dialog, dessen `on_Call()`-Methode auf. Das hat keinen Einfluss auf den anderen Dialog. Du musst *auf dem* Exemplar die `on_Call()`-Methode aufrufen. Und dazu musst Du das Exemplar an die `Receiver()`-Funktion übergeben und dort kein neues erstellen. Jetzt überleg mal über welchen Namen Du innerhalb von `Dummysenden()` an Attribute von dem Dialogexemplar heran kommst, dann weisst Du auch was Du zusätzlich an `Receiver()` übergeben musst.
agressor
User
Beiträge: 9
Registriert: Donnerstag 1. September 2011, 05:23

So... Das scheint jetzt nach ein bisschen probieren zu funktionieren.

Code: Alles auswählen

    def Dummysenden(self):
        valueX = self.verticalSlider.value()
        valueY = self.verticalSlider_2.value()
        valueZ = self.verticalSlider_3.value()
        sendString = "S: X" + str(float(valueX)/100) + " Y" + str(float(valueY)/100) + " Z" + str(float(valueZ)/100)
        self.EB_Terminal.insertPlainText(sendString)
        self.EB_Terminal.insertPlainText("\n")
        Reciver("Text", self.on_Call)        
       

def Reciver(Input, jumpcommand):
    print Input + "Global"
    jumpcommand()

Was mir da zum beispiel net so in den Kopf geht is, dass ich 2 Exemplare mit dem selben Namen erstellen kann. Aber nun gut. Damit kann ich erstmal weiter Arbeiten.

Dank dir nochmal. Bis zum nächsten Problem :-D
agressor
User
Beiträge: 9
Registriert: Donnerstag 1. September 2011, 05:23

Aber noch ne frage

diese methode ertlaubt natürlich einen sprung zurück in die klasse, wenn ich aus ihr heraus aufrufe. wie sieht das dann aus, wenn ich von außerhalb an diese funktion ran will. also der dialog steht und ich im normalen Programmablauf den Reciver() starten würde, sprich ich ohne das "self.on_Call" arbeiten im aufruf arbeiten müsste.
BlackJack

@agressor: Wie meinst Du das mit „zwei Exemplare mit dem selben Namen erstellen”? Objekte selbst kennen ihren Namen oder ihre Namen (Mehrzahl) nicht. An einen Namen innerhalb eines Namensraums kann man immer nur ein Objekt zur gleichen Zeit binden.

Oder meinst Du das Du zwei unabhängige Exemplare von `MeinDialog` erstellen kannst? Warum sollte das nicht gehen? Stell Dir mal vor das ginge nicht und man könnte von jeder Klasse immer nur *ein* Exemplar erstellen, was das für Folgen hätte. Einfaches Beispiel mit der Klasse `fractions.Fraction`:

Code: Alles auswählen

In [20]: a = Fraction(1, 2)

In [21]: b = Fraction(2, 3)

In [22]: a + b
Out[22]: Fraction(7, 6)
Wenn man nur *ein* Exemplar von `Fraction` erstellen könnte, wäre das nicht möglich, weil man `b` gar nicht definieren könnte. Und da alles was man in Python an einen Namen binden kann ein Objekt ist, und damit einen Typ und in der Regel eine Klasse hat [1]_, würde das bedeuten man könnte innerhalb eines Programms nur eine ganze Zahl verwenden, und nur eine einzige Zeichenkette, und nur eine Liste, und nur ein Tupel, und so weiter.

Auch bei GUIs kann es doch sogar Sinn machen von ein und dem selben Dialog mehr als ein Exemplar gleichzeitig zu erstellen und auch anzuzeigen. Beispielsweise Fenster zum erstellen einer Mail in einem Mailprogramm.

Wenn Du an eine Methode auf einem Exemplar heran kommen willst, brauchst Du entweder die Methode selbst — so wie Du das jetzt gelöst hast — oder das Exemplar. Was Du nicht möchtest, auch wenn Du das vielleicht denkst, ist `Receiver()` aufrufen und dort drin etwas benutzen was nicht eine Konstante ist oder als Argument übergeben wurde.

.. [1] Manche Typen haben keine Klasse im Sinne einer ``class``-Definition, sondern sind in C implementiert. Die haben aber trotzdem ein `__class__`-Attribut.
agressor
User
Beiträge: 9
Registriert: Donnerstag 1. September 2011, 05:23

...Ah... Erkenntnissblitz.

Ich rufe beim Programmaufruf ein Exemplar von "MeinDialog()" auf unter dem namen "Dialog".
wenn ich also dialog.on_Call rufen Würde müsste es funktionieren.
es funktionierte nicht, weil ich "MeinDialog" erneut und unter neuem Namen aufgerufen habe. wobei funktioniert nicht nicht ganz stimmte weil ich dieses Exemplar mangels eines .show() einfach nur nicht sehen konnte...

scheint sinnvoll.

nun gut... nach Ferierabend mal ausprobieren.
in oop muss man sich völlig neu eindenken.
alles wird gut
Antworten