@onur22: Anmerkungen zum Quelltext:
`App` ist kein guter Name für eine Fensterklasse und `ex` ist kein guter Name für ein Exemplar davon. Es gibt in Qt Klassen die die Anwendung repräsentieren (`QApplication`) und deren Exemplaren man die geläufige Abkürzung `app` als Namen geben kann. Dann ist es aber sehr verwirrend wenn man einen Namen `app` hat und eine Klasse `App`, die beiden aber nichts miteinander zu tun haben, obwohl sie gleich heissen. Und was soll der Name `ex` eigentlich bedeuten?
Der Inhalt des ``if __name__ …``-Zweigs sollte in einer Funktion stehen. Sonst sind die Namen `app` und `ex` im ganzen Modul sichtbar und es besteht die Gefahr, dass man die irgendwann mal (aus versehen) irgendwo benutzt.
Der `show()`-Aufruf gehört nicht in die `__init__()` des Fensters. Ein Widget anzuzeigen gehört in den Aufgabenbereich der Stelle die das Objekt erzeugt, nicht in das Widget selbst. Der Aufruf steht auch unnötigerweise zwei mal im Code.
Eine zusätzliche `initUI()` macht keinen Sinn. Das gehört mit in die `__init__()`. Einfach die drei Zeilen – Aufruf, Leerzeile, Methodendefinition – löschen.
Die Fenstergeometrie sollte man nicht setzen. Die meisten Benutzer finden Fenster die sich nicht da öffnen wo Platz auf dem Bildschirm ist, sondern immer an der selben Stelle wo der Programmierer das toll fand, ziemlich nervig. Damit fällt die Position also schon mal weg.
Die Grösse sollte sich automatisch aus dem benötigten Platz des Inhalts ergeben. Womit wir dann beim Thema Layouts wären: Du platzierst alles pixelgenau selbst. Das macht nicht nur unnötig Arbeit, sondern sieht dann auch nur auf Deiner Kombination von Betriebsystem, Monitorauflösung, und Systemeinstellungen so aus wie bei Dir. Auf anderen Systemen, die beispielsweise eine höhere oder niedrigere Monitorauflösung haben, sind Pixel aber kleiner oder grösser.
Um diese Probleme zu umgehen und es auch einfacher zu haben wenn man etwas an der GUI verändert wodurch sich andere Widgets verschieben, verwendet man Layout-Klassen, wo man die Widgets relativ zueinander anordnet, und das Layout dann dafür sorgt das alles an seinem Platz ist, und auch genug Platz hat.
Kommentare sollten dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code tut, denn das steht da bereits als Code, sondern *warum* er das (so) tut. Sofern das nicht offensichtlich ist.
Namen schreibt man in Python klein_mit_unterstrichen. Ausnahmen Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). Und wenn externe Bibliotheken die Namenskonventionen von anderen Programmiersprachen oder Projekten übernehmen, wie PyQt die von Qt/C++, dann sieht man auch mal etwas anderes. `Pictures` und `Solution` wäre aber unter beiden Konventionen falsch geschrieben, weil es keine Klassen sind.
`Solution` müsste auch in der Mehrzahl benannt werden. Zudem sollten diese Werte nicht in parallelen Listen stehen sondern Bilder und Lösungen jeweils zu einem Objekt zusammengefasst, beispielsweise als Tupel, in *einer* Liste.
Wenn man später auf die Aufgaben auch in anderen Methoden zugreifen will, muss man sie natürlich an das Objekt binden.
In der `__init__()` sollte man wie gesagt am besten kein Bild auf dem Label setzen, sondern alles vorbereiten so dass man mit der Methode die das jeweils nächste Bild setzt, eben auch das erste Bild setzen kann. Dann muss man das nur an einer Stelle programmieren.
Die supergenerischen und dann auch noch durchnummerierten Namen für Eingabeelemente, Schaltflächen, und Slots sind schlecht. Schöne Stelle an der man das besonders gut sieht ist das Verbinden von Signalen und Slots:
Code: Alles auswählen
self.button.clicked.connect(self.on_click)
self.button2.clicked.connect(self.on_click2)
Wenn man wissen will was da passiert, muss man sowohl bei den `Button`\s nachsehen womit die beschriftet sind, als auch bei den Slots was die machen. So sieht man an der Stelle direkt am Code was da passiert:
Code: Alles auswählen
self.confirmation_button.clicked.connect(self.check_answer)
self.continue_button.clicked.connect(self.go_to_next_assignment)
Wobei man die `Button`-Objekte auch gar nicht an das Fenster binden muss.
Zwischenstand:
Code: Alles auswählen
#!/usr/bin/env python3
import sys
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import (
QApplication, QLabel, QLineEdit, QMainWindow, QPushButton, QHBoxLayout,
QMessageBox, QVBoxLayout, QWidget,
)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.assignments = iter(
[('test2.jpg', 'spam'), ('test2.png', 'parrot')]
)
self.expected_answer = None
self.setWindowTitle('Test')
central_widget = QWidget(self)
vbox = QHBoxLayout()
widget = QWidget(central_widget)
hbox = QVBoxLayout()
self.input_edit = QLineEdit(widget)
hbox.addWidget(self.input_edit)
self.result_edit = QLineEdit(widget)
hbox.addWidget(self.result_edit)
confirmation_button = QPushButton('Confirm', widget)
hbox.addWidget(confirmation_button)
continue_button = QPushButton('Continue', widget)
hbox.addWidget(continue_button)
hbox.addStretch()
widget.setLayout(hbox)
vbox.addWidget(widget)
self.image_label = QLabel(self)
vbox.addWidget(self.image_label)
central_widget.setLayout(vbox)
self.setCentralWidget(central_widget)
confirmation_button.clicked.connect(self.check_answer)
continue_button.clicked.connect(self.go_to_next_assignment)
self.go_to_next_assignment()
def check_answer(self):
self.result_edit.setText(
str(self.input_edit.text() == self.expected_answer)
)
def go_to_next_assignment(self):
try:
image_filename, self.expected_answer = next(self.assignments)
except StopIteration:
QMessageBox.information(
self,
'Done',
'Do whatever needs to be done here when there is no assignment'
' left.'
)
else:
self.input_edit.setText('')
self.result_edit.setText('')
self.image_label.setPixmap(QPixmap(image_filename))
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Als nächstes würde ich den Aufbau der GUI aus dem Code heraus nehmen stattdessen mit dem Qt Designer arbeiten. Die *.ui-Datei kann man dann im Programm mit dem `PyQt5.uic`-Modul zur Laufzeit laden. Damit erspart man sich viel unübersichtlichen Code, sowohl zu schreiben, als auch zu lesen.