@jerch: Wie immer, besten dank. Du hast es methodisch und didaktisch sehr gut erklärt. So gefällt mir das auch. Ich will ja keine fertigen Lösungen, sondern an die Hand genommen werden, und belehrt werden. Genau meinen Geschmack. Aber ich habe noch einige Fragen, Anmerkungen und möchte die Gelegenheit nutzen und dir meine Gedankengänge aufzeigen, damit dir vielleicht klar wird, inwiefern ich nicht weiterkam.
Import immer am Anfang?
In meinem Fall habe ich mit Absicht meinen Import in eine Funktion untergebracht. Immer wenn in Unterfenster kreiert wird, soll die entsprechenden Klassen importiert werden. Ich habe es mir deshalb so angewöhnt, weil ich im Vorfeld schon weiß, dass - gerade im MDI-Bereich - viele verschiedene Unterfenster zustande kommen werden. Und damit ich den Namensraum nicht unnötig vollstopfe, verlege ich sie in die entsprechenden Funktionen. Und außerdem, wenn der Anwender das eine Unterfenster nicht braucht, dann wird auch nicht importiert. Würde ich es weit am Anfang setzen, so wird das Unterfenster importiert, obwohl noch nicht einmal sicher ist, dass das Unterfenster überhaupt benutzt wird.
Unterfenster auf zwei Wege erstellen
Das es zwei Wege gibt, womit man sein Unterfenster erstellen kann, habe ich bereits vernommen. Wie du unschwer erkannt hast, habe ich mit auch für den ersten Weg, und zwar über das Erstellen der
QMdiSubWindow-Klasse entschieden. Jedoch bekam ich von eurer Seite aus diesbezüglich Kritik, was ja auch nicht schlimm ist.
Das WA_DeleteOnClose-Attribut
Ich habe spaßeshalber den erste Weg noch einmal aufgegriffen, also die QMdiSubWindow per Hand kreiert und das
WA_DeleteOnClose-Attribut anstatt auf
self.search_form zu setzen, habe ich sie auf
self.subwindow_search gesetzt, also auf QMdiSubWindow und die Anwendung gestartet. Das Verhalten bleibt weiterhin bestehen. Keine Änderung. Der Balken klemmt weiterhin im MDI-Bereich.
Code: Alles auswählen
def create_search_form(self):
from ..modules_ui.ui_pp_search import Search_Window
self.subwindow_search = QMdiSubWindow()
self.search_form = Search_Window(self.close_sub_form, self.subwindow_search, self)
self.subwindow_search.setAttribute(Qt.WA_DeleteOnClose)
self.subwindow_search.setWidget(self.search_form)
self.mdiArea.addSubWindow(self.subwindow_search)
self.search_form.showNormal()
Die nutzlose QMdiSubWindow-Klasse
In meinem Quelltext war die
QMdiSubWindow-Klasse nutzlos. Ist ja nicht so, dass ich es nicht wüsste

Ich schrieb ja selbst, dass diese gerade erstellte Klasse keinen Nutzen bringt. Nur weil BlackJack die ganze Zeit davon schrieb, aber nirgends weiter darauf einging, dachte ich mir, schenke ich ihm die
QMdiSubWindow-Klasse, vielleicht passiert ja noch ein Wunder, und ich erfahre dann mehr?
Das singende, klingende Objektbäumchen
Also, ich gehe mal einen Schritt weiter, und betrachte mein Bäumchen wie folgt:
QMainWindow --> QMdiArea --> QMdiSubWindow --> QWidget --> QPushButton.
Alles wunderbar. Jetzt haben wir das Bäumchen, und nun? Genau das denke ich. Wie komme ich vom Anblick des Bäumchen nun auf die von dir vorgestellte Funktion:
Code: Alles auswählen
def closeParent(self):
...: if isinstance(self.parent(), QMdiSubWindow):
...: self.parent().close()
Allein vom Anblick meines Objektbaumes wäre ich niemals auf die Funktion gekommen, die du mir da vorstellst. Mir fehlt also da der Übergang. Denn das Objektbaum habe ich ja bereits verstanden. Aber mein Objektbaum hätte es mir nicht verraten und gesagt "Hey, mach das so und so". Ich sehe nur fünf Ebenen, ja, aber das warst dann auch. Es ist vielleicht für euch so selbstverständlich, weil ich Profis seid, und es so gelernt habt bzw. es euch so gezeigt wurde. Aber von allein, ohne Hilfsmittel wäre ich nicht darauf gekommen. Also ist der Objektbaum per se nicht selbst erklärend. Wie gesagt, ich könnte den Objektbaum Tag und Nacht rauf und runterbeten. Deswegen dachte ich mir immer:
"Alder, was pochen sie die ganze Zeit auf dem Objektbaum? Lass den armen Objektbaum in Ruhe, er kann mir auch nicht weiterhelfen".
Aber ein Kind braucht doch seine Eltern
Damit nicht das Gefühl aufkommt, ich werfe nur so mit den parent-Argumenten um mich, möchte ich kurz meine Gedankenwelt präsentieren. Dazu schauen wir mal kurz in mein mdi-Modul:
Modul: mdi.py
Code: Alles auswählen
class Mdi_Main(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
Was sehe ich hier? Hier wird eine Klasse Mdi_Main definiert, die von der Klasse QMainWindow erbt. Letztere wird in Qt benutzt, um das Hauptfenster einer Anwendung zu implementieren. Es folgt mit __init__() der Initializer der Klasse - Konstruktor. Dieser "empfängt" einen zusätzlichen Default-Parameter parent. Das entsprechend übergebene Argument wird dabei zum Parent-Objekt der Instanz gemacht. Somit ist es ein so genanntes Top-Level-Window. Dies wird also durch das parent-Attribut den Wert „None“ ermöglicht. Soweit so gut. Schauen wir doch mal die
Search_Window()-Klasse an.
Modul: ui_pp_search.py
Code: Alles auswählen
class Search_Window(QWidget):
def __init__(self, parent):
QWidget.__init__(self, parent)
Was sehe ich hier? Das parent-Argument hat diesmal nicht den Wert None. Aber halt, rein theoretisch kann jedes Qt-Widget als Top-Level-Window benutzt werden. Will ich aber nicht. Warum? Weil ein solches Top-Level-Window sonst nicht Bestandteil eines anderen Fensters ist, also die dies QMainWindows, und des Weiteren läge die Verantwortung für das Schließen des Fensters beim Programmierer. Damit sich Qt selbst darum kümmert, habe ich beim parent-Argument einfach den 'None'-Wert weggelassen. Somit sorgt Qt selbst dafür, dass beim Schließen des Parent-Widgets (mein QMainWindows namens Mdi_Main) auch alle enthaltenen Kind-Widgets geschlossen werden. Zur Initialisierung muss anschließend immer der Initializer der Klasse aufgerufen werden.
The End
Betrachtet dies nicht als eine Belehrung oder dergleichen, sondern als eine Art, meine Gedanken lesen zu können. Natürlich hat dies auch einen Selbst-Lern-Effekt für mich

Schließlich möchte ich Python lernen, ich will alles verstehen, ich will nicht nur Lösungen vorgekaut bekommen etc. Ich möchte euch die Gelegenheit geben, dass ihr mal meine Gedankenstruktur kennenlernt. Nur so hoffe ich, dass ihr dann entsprechend ansetzen könnt, und sagen könnt "Aber genau da denkst du falsch" oder "genau da fehlt der Sprung" oder was auch immer.
So jetzt gibt es Kaffee.