2016-07-25 9 views
1

Ziel: Erstellen Sie ein Werbebuchungsobjekt, das ein Textfeld für eine Label-, Wert- und Werteinheiten in PySide enthält.OOP-Techniken mit Python-GUI (PySide) -Elementen

Hintergrund: Ich erstelle eine Systemsteuerung für ein Gerät, das von einem Raspberry Pi mit Python PySide (QtPython) ausgeführt wird, um die GUI zu behandeln. Ich verwende das Rasterlayout und habe ein gemeinsames Motiv, das ich in einer Klasse zu kapseln versuche, um mich nicht zu wiederholen. Ich brauche Hilfe beim Aufbau dieser Klasse.

Normalerweise sieht mein Code wie folgt aus:

class Form(QDialog): 
    def __init__(self, parent=None): 
     super(Form, self).__init__(parent) 

     self.pressure_label = QLabel('Pressure:') 
     self.pressure_value = QLabel() 
     self.pressure_units = QLabel('psi') 

     self.temperature_label = QLabel('Temperature:') 
     self.temperature_value = QLabel() 
     self.temperature_units = QLabel('oC') 
     ... 

     grid = QGridLayout() 

     grid.addWidget(pressure_label, 0, 0) 
     grid.addWidget(pressure_value, 0, 1) 
     grid.addWidget(pressure_units, 0, 1) 

     grid.addWidget(temperature_label, 1, 0) 
     grid.addWidget(temperature_value, 1, 1) 
     grid.addWidget(temperature_units, 1, 1) 
     ... 

     self.setLayout(grid) 

    def update(self): 
     self.temperature_value.setText(t_sensor.read()) 
     self.pressure_value.setText(p_sensor.read()) 

Was ich versucht habe:

Mit GUI-Elemente, ich bin nicht wirklich sicher, wo ich meine Klassen setzen, oder was für Eltern Objekt, das sie erben müssen. Ich habe versucht, ein Objekt auf die folgende Weise zu erstellen, aber es ist nur ein Framework und wird offensichtlich nicht kompilieren.

class LineItem(object): 
    def __init__(self, label_text, unit_text, grid, row): 
     self.value = None 
     self.units = None 

     self.label_field = QLabel(label_text) 
     self.value_field = QLabel() 
     self.units_field = QLabel(unit_text) 

     grid.addWidget(self.label_field, row, 0) 
     grid.addWidget(self.value_field, row, 1) 
     grid.addWidget(self.units_field, row, 2) 

    @property 
    def value(self): 
     return self.value 

    @value.setter 
    def value(self, val): 
     self.value = val 
     self.value_field.setText(val) 

    @property 
    def units(self): 
     return self.value 

    @value.setter 
    def units(self, val): 
     self.units = val 
     self.units_field.setText(val) 

class Form(QDialog): 
    def __init__(self, parent=None): 
     grid = QGridLayout() 

     row_number = itertools.count() 
     tb_encoder_1 = LineItem('Distance:', 'm', grid, next(row_number)) 
     tb_encoder_2 = LineItem('Distance:', 'm', grid, next(row_number)) 

     self.setLayout(grid) 

Was ich brauche:

Was ich hoffe, dieses Label, Wert, Struktureinheiten in eine Klasse zu tun ist, kapselt, so dass ich mich nicht so viel zu wiederholen.

Wohin geht eine Klasse wie diese? Was erbt es? Wie gebe ich ihm Zugriff auf das Objekt grid (braucht es überhaupt Zugriff)?

Worauf ich mich konzentriere, ist zu verstehen, wie Klassen und Kapselung in PySide-Formen und -Widgets übersetzt werden. Die meisten Tutorials, die ich bisher gesehen habe, gehen diesen Weg nicht, sie setzen einfach die gesamte Logik und das Erstellen in eine große Form(QDialog) Klasse.

+0

Sie haben mehrere Möglichkeiten es zu tun, wissen Sie über Qt's Model/View Programmierung? http://doc.qt.io/qt-5/model-view-programming.html; sonst wäre bei einem MVC deine erste Klasse ein Modell, deine zweite die Ansicht, und du könntest Signale verwenden, um Autowechsel in GUI-Komponenten auszulösen, die an deinem Controller vorbeikommen. – PyNico

+0

Danke, dass du mich auf diese Ressource gelenkt hast ein Überlesen. –

+0

Aber unter Verwendung von Qt könnte LineItem nur ein Widget sein. Sie können Ihr eigenes Widget erstellen. Dazu sollte Ihr benutzerdefiniertes Widget beispielsweise von QWidget erben. Überschreibe, was du brauchst, schreibe deine GUI und die Steuerungslogik, dann kannst du sie wie einen Button oder ein beliebiges Qt-Widget verwenden – PyNico

Antwort

1

Sie benötigen nur eine QWidget Unterklasse, die als Container für die anderen Widgets dient. Seine Struktur wird einer normalen Form sehr ähnlich sein - der Hauptunterschied besteht darin, dass es als Kind-Widget eines anderen Formulars und nicht als Fenster der obersten Ebene angezeigt wird.

class LineItem(QWidget): 
    def __init__(self, label_text, unit_text, parent=None): 
     super(LineItem, self).__init__(parent) 

     self.label_field = QLabel(label_text) 
     self.value_field = QLabel() 
     self.units_field = QLabel(unit_text) 

     layout = QVBoxLayout() 
     layout.setContentsMargins(0, 0, 0, 0) 

     layout.addWidget(self.label_field) 
     layout.addWidget(self.value_field) 
     layout.addWidget(self.units_field) 

     self.setLayout(layout) 

class Form(QDialog): 
    def __init__(self, parent=None): 
     super(Form, self).__init__(parent) 

     self.pressure_line = LineItem('Pressure:', 'psi', self) 
     self.temperature_line = LineItem('Temperature:', 'oC', self) 

     layout = QHBoxLayout() 

     layout.addWidget(self.pressure_line) 
     layout.addWidget(self.temperature_line) 

     self.setLayout(layout) 
+0

Okay, danke, dass du das geklärt hast. Ich war besonders verwirrt darüber, wie der Befehl 'layout' im Umgang mit verschiedenen Klassen verwendet wird. Für mich ähnelt das vage einem wxPython-Panel. Ich brauche nur etwas Zeit, um es in meine Anwendung zu integrieren und zu beweisen, dass es funktioniert, bevor ich es akzeptiere. –

+0

Funktioniert (mit einigen Änderungen)! Die Zeile 'super (Form, self) .__ init __ (parent)' muss dem 'Form (QDialog)' Initiator hinzugefügt werden, die 'layout.setContentsMargin()' ist 'layout.setContentsMargins()', und es gibt a ein paar Tippfehler, die verhindern, dass es ausgeführt wird. Kann ich bearbeiten? –

+0

@MichaelMolter. Danke - ich denke, ich habe jetzt alles repariert. – ekhumoro