Hallo Community!
Auch ich versuche mich gerade an der Programmierung einer
Maschinensteuerung inkl. Visualisierung mit Python bzw. PyQt.
Da dies im Rahmen einer Studienarbeit geschieht, würde ich gerne
möglichst sauberen Code schreiben. Leider finde ich im Internet nur
wenige umfangreiche Beispiele. (falls ihr also ein gutes Beispiel,
ähnlich wie: https://gist.github.com/PhilReinhold/05b475549e4c37e2f95a,
was schlussendlich so: http://i.imgur.com/uuS3YPM.jpg aussieht, kennt,
immer her damit :) )
Als Nicht-Informatiker habe ich leider (noch?) kein gutes Gespür für die
Strukturierung meines Codes entwickelt.
Konkret geht es bei meiner Frage um die Erzeugung von Klassen und deren
Instanzen und wie ich dies sinnvoll gestalte.
Vorweg eine ganz banale Frage: Macht es Sinn, eine Klasse zu erstellen,
wenn es von dieser nur eine Instanz gibt?
Gerne würde ich mehrere Tabs haben, wozu ich vorerst im mainwindow ein
Tabwidget erstelle. Nun ähneln sich die unterschiedlichen Tabs teilweise
(beispielsweise im Layout), unterscheiden sich aber entsprechend auch
(beispielsweise für die Beschriftung der Buttons und Labels).
Meine Frage ist es jetzt:
Wird nun für jeden eigenen Tab eine eigene Klasse erstellt (A) oder
sollte eine einzelne Klasse für alle Tabs erstellt werden (B)?
Hier mal Codeschnipsel der beiden Möglichkeiten:
A) Jeder Tab eine Klasse
1
class MainWindow(QtGui.QMainWindow):
2
3
def __init__(self):
4
super(MainWindow,self).__init__()
5
self.createComponents()
6
self.setupTabs()
7
self.createLayout()
8
9
def createComponents(self):
10
self.tabwidget = QtGui.QTabWidget()
11
12
def setupTabs(self):
13
self.tab1 = TabInhalt1(self)
14
self.tab2 = TabInhalt2(self)
15
self.tab3 = TabInhalt3(self)
16
17
def createLayout(self):
18
layoutZentral = QtGui.QVBoxLayout()
19
layoutZentral.addWidget(self.tabwidget)
20
widgetZentral = QtGui.QWidget()
21
widgetZentral.setLayout(layoutZentral)
22
self.setCentralWidget(widgetZentral)
23
24
class TabInhalt1(self):
25
def __init__(self):
26
super(TabInhalt1,self).__init__()
27
(Hier alles rein, was in Tab 1 gehört)
28
mainwindow.tabwidget.addTab(self)
29
30
class TabInhalt2(self):
31
def __init__(self):
32
super(TabInhalt2,self).__init__()
33
(Hier alles rein, was in Tab 2 gehört)
34
mainwindow.tabwidget.addTab(self)
35
36
class TabInhalt3(self):
37
def __init__(self):
38
super(TabInhalt2,self).__init__()
39
(Hier alles rein, was in Tab 3 gehört)
40
mainwindow.tabwidget.addTab(self)
B) Eine Klasse für alle Tabs(so habe ich es zurzeit gemacht)
1
class MainWindow(QtGui.QMainWindow):
2
3
def __init__(self):
4
super(MainWindow,self).__init__()
5
self.createComponents()
6
self.setupTabs()
7
self.createLayout()
8
9
def createComponents(self):
10
self.tabwidget = QtGui.QTabWidget()
11
12
def setupTabs(self):
13
self.tab1 = TabInhalt(self,'Seite_1')
14
self.tab2 = TabInhalt(self,'Seite_2')
15
self.tab3 = TabInhalt(self,'Seite_3')
16
17
def createLayout(self):
18
layoutZentral = QtGui.QVBoxLayout()
19
layoutZentral.addWidget(self.tabwidget)
20
widgetZentral = QtGui.QWidget()
21
widgetZentral.setLayout(layoutZentral)
22
self.setCentralWidget(widgetZentral)
23
24
class TabInhalt(QtGui.QWidget):
25
def __init__(self,mainwindow,tabname):
26
self.tabname = tabname
27
super(TabInhalt,self).__init__()
28
self.populate_tab(self.tabname)
29
mainwindow.tabwidget.addTab(self, self.tabname)
30
31
def populate_tab(self, tabname):
32
33
#An dieser Stelle vorerst die "gemeinsamen" Elemente erstellen, dann folgt Fallunterscheidung um welchen Tab es sich handelt
34
35
36
37
#Tab 1
38
if (self.tabname=='Seite_1'):
39
self.labelHalloWelt = QtGui.QLabel("Hallo Welt")
40
self.labelHalloMom = QtGui.QLabel("Hallo Mom")
41
self.labelHalloDad = QtGui.QLabel("Hallo Dad")
42
43
layout = QtGui.QVBoxLayout()
44
layout.addWidget(self.labelHalloWelt)
45
layout.addWidget(self.labelHalloMom)
46
layout.addWidget(self.labelHalloDad)
47
48
self.setLayout(layout)
49
50
#Tab 2
51
elif (self.tabname =='Seite_2'):
52
return #(Hier habe ich mal den Code für die Leserlichkeit abgekürzt)
53
54
#Tab 3
55
elif (self.tabname =='Seite_3'):
56
return #(Hier habe ich mal den Code für die Leserlichkeit abgekürzt)
Ich hoffe, dass ich es irgendwie verständlich machen konnte, wo mein
Problem liegt. Würde mich über eine Rückmeldung freuen! Falls ihr
irgendwelche Guidelines zur Strukturierung von PyQt-Code kennt, freue
ich mich natürlich auch darüber.
Grüße und Danke!
Hendrik
Deine Objekte sind ja Stellvertreter für Gegenstände in der realen Welt.
Einfacher Grundsatz: wenn du für jeden Gegenstand ein Objekt anlegst,
wird es am übersichtlichsten. So ein Tab als realen Gegenstand
bezeichnen, ist vielleicht etwas schräg. Anfangs wurde 1:1 ein realer
Schreibtisch mit Ablagen und Papierkorb nach gebaut. Dann hat es sich
immer weiter von einem realen Schreibtisch entfernt.
Das Problem liegt eher in den Details. Im laufe der Zeit bekommst du
immer mehr Abhängigkeiten, verlierst den Überblick, an welchen Stellen
eine Änderung neue Fehler verursacht.
Die eigentliche Frage ist: wie lässt sich vermeiden, dass Tab1 auf die
Interna von Tab2 zugreifen muss? In der Praxis ist die entscheidende
Frage: welche Lösung kommt mit weniger Public-Methoden aus.
Hallo Hendrik,
Hendrik W. schrieb:> Auch ich versuche mich gerade an der Programmierung einer> Maschinensteuerung inkl. Visualisierung mit Python bzw. PyQt.> [...]> Vorweg eine ganz banale Frage: Macht es Sinn, eine Klasse zu erstellen,> wenn es von dieser nur eine Instanz gibt?
Ja.
> Gerne würde ich mehrere Tabs haben, wozu ich vorerst im mainwindow ein> Tabwidget erstelle. Nun ähneln sich die unterschiedlichen Tabs teilweise> (beispielsweise im Layout), unterscheiden sich aber entsprechend auch> (beispielsweise für die Beschriftung der Buttons und Labels).>> Meine Frage ist es jetzt:> Wird nun für jeden eigenen Tab eine eigene Klasse erstellt (A) oder> sollte eine einzelne Klasse für alle Tabs erstellt werden (B)?
Ich persönlich würde zu (C) tendieren: eine BaseTab-Klasse für alle
Tabs, die von QWidget erbt, und dann für jeden Tab eine eigene Klasse,
die von Deiner BaseTab-Klasse erbt.
1
class BaseTab(QtGui.QWidget): ...
2
class TabEins(BaseTab): ...
3
class TabZwei(BaseTab): ...
4
5
class MainWin(QtGui.QMainWindow):
6
...
7
def createComponents(self):
8
self.tabwidget = QtGui.QTabWidget()
9
self.tabwidget.addTab(TabEins(), "TabEins")
10
self.tabwidget.addTab(TabZwei(), "TabZwei")
Vorteil: Du kannst die Tabs über eine gemeinsame Schnittstelle
ansprechen, die Du in BaseTab implementierst, um Deine Tabs damit über
Ereignisse wie beispielsweise das Eintreffen neuer Daten zu informieren.
> Ich hoffe, dass ich es irgendwie verständlich machen konnte, wo mein> Problem liegt. Würde mich über eine Rückmeldung freuen! Falls ihr> irgendwelche Guidelines zur Strukturierung von PyQt-Code kennt, freue> ich mich natürlich auch darüber.
Naja, hier geht es weniger um Python- oder Qt-Code, sondern um das
Design der Architektur von objektorientierter Software, insofern wirst
Du fündig, wenn Du nach "OO Design" und "Design Patterns" suchst.
Speziell für Python kenne ich da leider nicht sehr viel, aber die
Erfahrungen und Erkenntnisse aus anderen Programmiersprachen wie Java
oder C++ lassen sich meist leicht auf Python übertragen.
HTH,
Karl
Hallo Karl!
Erstmal vielen Dank für deine Hilfe, zu diesem Ansatz mit einer
Basisklasse wurde mir auch im Pythonforum geraten. (Hier mal mein
Beitrag, hoffe mal verlinken von anderen Foren ist in Ordnung:
http://www.python-forum.de/viewtopic.php?f=24&t=36815)
Mir kam es am Anfang halt etwas komisch vor, eine Klasse für nur eine
Instanz zu erstellen. Meine Vermutung war, dass man Klassen erstellt, um
sich gewisse Gemeinsamkeiten der Instanzen (Attribute und Methoden) zu
Nutze zu machen.
Vielen Dank nochmal!
Hendrik