Fenster mit QHBoxLayout schließen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

BlackJack hat geschrieben:@Sophus: Wenn ich das Starte und auf Film hinzufügen gehe, dann passiert nichts, und in der Konsole wird mir das hier ausgegeben:

Code: Alles auswählen

$ python Xarphus.py 
Die Ordner existieren bereits.
Das Programm wird von einem anderen Modul importiert.
Traceback (most recent call last):
  File "/home/bj/tmp/forum/Xarphus/Xarphus/MDIForm.py", line 100, in CreateNewMovie
    self.MDIChild = start_window(self)
NameError: global name 'start_window' is not defined
Also genau das Problem das ich auch beim verkürzten Programm hatte.
Einen Moment, ich schaue mal nach.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

In der MDIForm.py Datei folgendes ändern:

Code: Alles auswählen

    def CreateNewMovie(self):                   # Neues Fenster für Film hinzufügen öffnen
        self.MDIChild = MyForm(self)  #<---- ansttt start_window kommt hier MyForm hin.
        self.mdiArea.addSubWindow(self.MDIChild)
        self.MDIChild.show()
        print "Dialog lädt"
EmaNymton
User
Beiträge: 174
Registriert: Sonntag 30. Mai 2010, 14:07

Hab dir mal ein Beispiel gebastelt, damit du siehst, das Internationalisierung kein Hexenwerk ist und schon sehr bequem umgesetzt werden kann:
https://github.com/Cermit/snippets/tree ... 8n_example

Vorgehen:
Du erzeugst deinen Quelltext (hier main.py). Alle Strings, die übersetzt werden sollen, setzt du in self.tr().
Du legst ein pro-File (hier project.pro) an, in dem die Dateien aufgeführt werden, in denen Strings zur Übersetzung vorgesehen sind.
Du benutzt das CLI-Tool

Code: Alles auswählen

pylupdate5 project.pro
bzw

Code: Alles auswählen

pylupdate4 project.pro
(je nach verwendeter PyQt-Version) um die ts-Files zu erzeugen (sind nichts anderes als xml-Files).
Du benutzt den Qt Linguist, um die Übersetzungen anzugeben und gibst zum Schluss dort mit "Freigeben" die Datei frei. Dann wird ein qm-File erzeugt, das vom QTranslator zur Laufzeit des Programms eingelesen werden kann.

Es sind halt im wesentlichen drei Zeilen mehr:

Code: Alles auswählen

[...]
translator = QtCore.QTranslator()
translator.load('de.qm')
app.installTranslator(translator)
[...]
die du benötigst. Das kannst du natürlich jetzt noch beliebig erweitern, d.h. beim Programmstart aus deinen Settings die Sprachwahl auslesen und dementsprechend das richtige qm-File auswählen. Das ist aber bei weitem einfacher als das, was du vorhast und ich sehe hierbei auch keinen wirklichen Lerneffekt.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

EmaNymton hat geschrieben:Hab dir mal ein Beispiel gebastelt, damit du siehst, das Internationalisierung kein Hexenwerk ist und schon sehr bequem umgesetzt werden kann:
https://github.com/Cermit/snippets/tree ... 8n_example

Vorgehen:
Du erzeugst deinen Quelltext (hier main.py). Alle Strings, die übersetzt werden sollen, setzt du in self.tr().
Du legst ein pro-File (hier project.pro) an, in dem die Dateien aufgeführt werden, in denen Strings zur Übersetzung vorgesehen sind.
Du benutzt das CLI-Tool

Code: Alles auswählen

pylupdate5 project.pro
bzw

Code: Alles auswählen

pylupdate4 project.pro
(je nach verwendeter PyQt-Version) um die ts-Files zu erzeugen (sind nichts anderes als xml-Files).
Du benutzt den Qt Linguist, um die Übersetzungen anzugeben und gibst zum Schluss dort mit "Freigeben" die Datei frei. Dann wird ein qm-File erzeugt, das vom QTranslator zur Laufzeit des Programms eingelesen werden kann.

Es sind halt im wesentlichen drei Zeilen mehr:

Code: Alles auswählen

[...]
translator = QtCore.QTranslator()
translator.load('de.qm')
app.installTranslator(translator)
[...]
die du benötigst. Das kannst du natürlich jetzt noch beliebig erweitern, d.h. beim Programmstart aus deinen Settings die Sprachwahl auslesen und dementsprechend das richtige qm-File auswählen. Das ist aber bei weitem einfacher als das, was du vorhast und ich sehe hierbei auch keinen wirklichen Lerneffekt.
Hallo EmaNymton,

besten Dank für deine kleine Demonstration. Aber eine Frage: Wie kann ich dein kleines Beispiel herunterladen? Muss ich mich erst auf der Seite anmelden? Und dann hätte ich eines anzumerken. Wenn ich mir das alles so durchlese, was ich machen muss, dann schlage ich mir die Hände über meinem Kopf zusammen. Da sind ja ganze 4-5 Schritte die ich machen muss, bis ich am Ende erstmal eine *.qm Datei habe. In meinem Vorgang habe ich Sprachmodule, muss nicht erst 5 Schritte durchlaufen, bis ich am Ende eine *.qm Datei habe. Ich würde mir gern dein Code ansehen, aber überzeugt von den ganzen umständlichen Schritten bin ich immer noch nicht. Da habe ich in meinem Vorgang nur einen einzigen Schritt.
BlackJack

@Sophus: Das mit den Qt-Linguist unterscheidet sich von deinem Ansatz. Das ist nämlich für den Programmierer und für den Übersetzer einfacher. Aber mach's ruhig kompliziert wenn Du unbedingt willst.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

BlackJack hat geschrieben:@Sophus: Das mit den Qt-Linguist unterscheidet sich von deinem Ansatz. Das ist nämlich für den Programmierer und für den Übersetzer einfacher. Aber mach's ruhig kompliziert wenn Du unbedingt willst.
Hallo BlackJack, konntest du mein kleines Projekt zum Laufen bringen und kannst du mir bezüglich meines Ausgangsproblem helfen?
BlackJack

@Sophus: Da hatte ich doch schon etwas zu geschrieben: `QDialog` ist ein „top-level only”-Widget. Das kann man nur als eigenes Fenster verwenden und nicht als Widget in andere Widgets einbauen.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

BlackJack hat geschrieben:@Sophus: Da hatte ich doch schon etwas zu geschrieben: `QDialog` ist ein „top-level only”-Widget. Das kann man nur als eigenes Fenster verwenden und nicht als Widget in andere Widgets einbauen.
Ach so, das heißt konkret für mich, dass ich aus QDialog nun QWidget machen muss, richtig? Aber selbst dann schließt sich das Programm leider nicht, sondern die Widgets auf der Form verschwinden.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Selbst 'destroy()' will auch nicht ganz funktionieren. Wie gesagt, ich habe aus QDialog nun QWidget gemacht, in der Hoffnung, dass man mit einem QWidget in einem MdiArea-Widget arbeiten kann. Aber irgendwie scheint es nicht ganz zu funktionieren. Woran könnte es denn liegen?
BlackJack

@Sophus: Kommando zurück. Anscheinend funktioniert es auch mit `QDialog`-Exemplaren. Allerdings muss man schon das richtige Objekt schliessen. Nämlich das `QMdiSubWindow`-Exemplar das zu dem `QMdiArea`-Exemplar hinzugefügt wird. Wenn man nur das Widget zerstört welches *in* diesem `QMdiSubWindow`-Exemplar angezeigt wird, dann wird halt auch nur der Inhalt von dem Fenster zerstört.

Wobei: Kommando zurück wieder zurück: Auch wenn `QDialog` funktioniert, würde ich das nur verwenden wenn man tatsächlich irgend etwas von diesem speziellen Widget verwendet. Wenn ein `QWidget`-Exemplar reicht, muss man es ja nicht unnötig kompliziert machen.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

BlackJack hat geschrieben:@Sophus: Kommando zurück. Anscheinend funktioniert es auch mit `QDialog`-Exemplaren. Allerdings muss man schon das richtige Objekt schliessen. Nämlich das `QMdiSubWindow`-Exemplar das zu dem `QMdiArea`-Exemplar hinzugefügt wird. Wenn man nur das Widget zerstört welches *in* diesem `QMdiSubWindow`-Exemplar angezeigt wird, dann wird halt auch nur der Inhalt von dem Fenster zerstört.

Wobei: Kommando zurück wieder zurück: Auch wenn `QDialog` funktioniert, würde ich das nur verwenden wenn man tatsächlich irgend etwas von diesem speziellen Widget verwendet. Wenn ein `QWidget`-Exemplar reicht, muss man es ja nicht unnötig kompliziert machen.
Hey BlackJack, das Problem, was ich hier habe, ist, dass ich keinen Unterschied zwischen QWidget und QDialog verstehe. Da ich VB6ler bin, gibt es dort nur Formen, und die Formen kann man behandeln wie man will. Und ich habe die Formen auch in ein MDIFormular (Analog: QMdiArea) untergebracht, indem die Formen als Child behandelt wurden.

Aber nun zum Problem:
Du sagtest, ich solle das Objekt 'QMdiSubWindow' schließen, richtig? Jedoch habe ich dieses Objekt ja gar nicht. Schauen wir mal meine Funktion an:

Code: Alles auswählen

    def CreateNewMovie(self):                   # Neues Fenster für Film hinzufügen öffnen
        self.MDIChild = MyForm(self)
        self.mdiArea.addSubWindow(self.MDIChild)
        self.MDIChild.show()
        print "Dialog lädt"
Hier wird MDIChild als SubWindow in das Widget mdiArea hinzugefügt. Was genau muss ich in meinem Beispiel schließen?
BlackJack

@Sophus: `MDIChild` wird nicht als Subwindow hinzugefügt, sondern dem Subwindow als Inhalt. Schau Dir mal die Dokumentation zu `QMdiArea.addSubWindow()` an. Danach solltest Du zwei Wege kennen um an das `QMdiSubWindow`-Exemplar heran zu kommen.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Also mit 'self.mdiArea.removeSubWindow(self.MDIChild)' komme ich offensichtlich auch nicht weit.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Nach langem rumgetüffel bin ich auf eine vermeintliche Lösung gestoßen, aber ich hätte gern eure Meinung.

TestDialog.py Was tat ich? Ich habe die Klasse "MyForm" unter anderem von QMdiSubWindow abgeleitet, schließlich sollten alle Child-Fenster bei QMdiArea von QMdiSubWindow abgeleitet werden. Vorher war sie nur vom QDialog und zeitweise auch nur vom QWidget abgeleitet. Klappte ja nicht.

Code: Alles auswählen

import sys
from PyQt4.QtGui import QWidget, QApplication, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox, QTextEdit, QMdiSubWindow 
from PyQt4.QtCore import Qt

class MyForm(QMdiSubWindow, QDialog):
    def __init__(self, parent=None):
        QMdiSubWindow, QDialog.__init__(self, parent)
     [...]
MDIForm.py Hier schließe ich das Fenster mit der Methode 'removeSubWindow()', aber mit 'close()' klappt es auch wunderbar. Kann ich also getrost bei 'close()' bleiben oder sollte ich da auf etwas achten?

Code: Alles auswählen

[...]
    def CloseQWidget(self):
        self.MDIChild = MyForm(self)
        self.mdiArea.removeSubWindow(self.MDIChild)
        #self.close()
[...]
BlackJack

@Sophus: Das ist kompletter Unsinn. Wieder Programmieren durch raten statt zu verstehen was man da tut. Und bei beiden gezeigten Programmstellen hätte ich gewettet damit fällt man auf die Nase. Wenn das tatsächlich funktioniert, fällt das wohl unter die Kategorie „feak accident”. Oder Du trollst hier gerade ganz gewaltig.

Edit: Und es funkioniert auch tatsächlich *nicht*. Das Layout in dem MDI-Fenster ist kaputt und auf der Konsole erscheint auch eine entsprechende Warnung von Qt:

Code: Alles auswählen

QLayout: Attempting to add QLayout "" to MyForm "", which already has a layout
QWidget::setLayout: Attempting to set QLayout "" on MyForm "", which already has a layout
Wie die Schaltfläche vom `MyForm`-Objekt mit der gezeigten `CloseQWidget()`-Methode verbunden wird, will ich wahrscheinlich gar nicht wissen. Unsinnig ist sie allemal, sowohl der aktive Code als auch die auskommentierte Zeile.
Sirius3
User
Beiträge: 18229
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: was glaubst Du, bewirkt die Zeile

Code: Alles auswählen

QMdiSubWindow, QDialog.__init__(self, parent)
Wahrscheinlich: auf wundersame Weise wird das Verhalten von QMdiSubWindow und QDialog miteinander vermischt, so dass ein QMdiSubDialog entsteht, der alles genau so macht, wie ich mir das wünsche.
In Wirklichkeit macht Python ein Tuple aus dem Objekt QMdiSubWindow und dem Rückgabewert von QDialog.__init__ und verwirft es gleich wieder.
Hättest Du einmal in die Dokumentation geschaut:

Code: Alles auswählen

QMdiSubWindow addSubWindow(self, QWidget widget, Qt.WindowFlags flags=0)
wäre klar, woher das QMdiSubWindow kommt und dass Du ein QWidget statt eines QDialogs brauchst.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Bei mir kommt keine Warnung. Hier die verpackte Datei, damit ihr mein komplettes Projekt ansehen könnt': Xarphus.

Werter BlackJack, du kannst ein paar Gänge runterschalten. Mir zu unterstellen ich trolle oder gar mich von der Seite anzufahren empfinde ich mehr als dreist und unhöflich. Das ich als Anfänger nicht gleich alles auf Anhieb verstehe und richtig mache, sollte einem jeden klar sein. Sollte dein Geduldsfaden sehr kurz sein, hoffe ich wirklich, dass du kein Ausbilder bist. Und bevor du wieder denkst, dass ich trolle, kommen wir wieder zurück. Ja, ich habe die Qt Dokumentation gelesen, aber ich muss gestehen, dass ich mich immer noch irgendwie schwer tue an die Seite heranzukommen. Es liegt weniger daran, dass die Seite auf englisch ist, sondern wie die Seite aufgebaut ist. Es stehen so viele Informationen, dass der Scrollbalken im Browser richtig klein wird. Aber irgendwie habe ich das richtige Lesen noch nicht erfasst. Und anstatt mich hier als Troll abzustempeln könnte man mir zeigen, wie man auf der Seite richtig liest, wie man vorzugehen hat, wie man Informationen herausnimmt etc.
Zuletzt geändert von Sophus am Samstag 21. Juni 2014, 15:21, insgesamt 2-mal geändert.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Sirius3 hat geschrieben: Wahrscheinlich: auf wundersame Weise wird das Verhalten von QMdiSubWindow und QDialog miteinander vermischt, so dass ein QMdiSubDialog entsteht, der alles genau so macht, wie ich mir das wünsche.
In Wirklichkeit macht Python ein Tuple aus dem Objekt QMdiSubWindow und dem Rückgabewert von QDialog.__init__ und verwirft es gleich wieder.
Hättest Du einmal in die Dokumentation geschaut:

Code: Alles auswählen

QMdiSubWindow addSubWindow(self, QWidget widget, Qt.WindowFlags flags=0)
wäre klar, woher das QMdiSubWindow kommt und dass Du ein QWidget statt eines QDialogs brauchst.
Hallo Sirius3,

an dieser Stelle bin ich in der Dokumentation auch angekommen. Aber ehrlich gesagt sagt mir dieser Ausschnitt nicht viel. Gut, wir brauchen statt einen QDialog ein QWidget? Super, dann werde ich folgendes machen:

TestDiaolog.py

Code: Alles auswählen

# -*- coding: utf-8 -*-
import sys
from PyQt4.QtGui import QWidget, QApplication, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox, QTextEdit, QMdiSubWindow, QDialog 
from PyQt4.QtCore import Qt

class MyForm(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        [...]
MDIForm.py (Hier haben wir zwei Funktionen, einmal die, die das Fenster zum Inhalt von 'addSubWindow()' macht und dann eine Funktiontion, die das Fenster wieder schließen soll. Und jetzt fehlt mir der Sprung zu QMdisubwindow bzw. der Sprung um das QWidget schließen zu können)

Code: Alles auswählen

[...]
    def CreateNewMovie(self):                   # Neues Fenster für Film hinzufügen öffnen
        self.MDIChild = MyForm(self)
        self.mdiArea.addSubWindow(self.MDIChild)
        self.MDIChild.show()
        print "Dialog lädt"

    def CloseQWidget(self):
        self.MDIChild = MyForm(self)
        #self.mdiArea.closeAllSubWindows()
        #self.mdiArea.removeSubWindow(self.MDIChild)
        self.close()
[...]
Den kompletten Code habe ich soeben hochgeladen, daher habe ich den hier extrem verkürzt und nicht lauffähig dargestellt.
Sirius3
User
Beiträge: 18229
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: Weil Du sowieso nicht aufgibt, bis man es Dir vorkaut:

Code: Alles auswählen

[...]
    def CreateNewMovie(self):                   # Neues Fenster für Film hinzufügen öffnen
        self.form = MyForm(self)
        self.subwindow = self.mdiArea.addSubWindow(self.form)
        self.form.show()
 
    def CloseQWidget(self):
        self.subwindow.close()
[...]
BlackJack

@Sirius3: Wobei man sich dann natürlich fragt wie/womit `CloseQWidget()` verknüpft wird, und das *ein* Attribut für das Fenster für MDI-Fenster, von denen man ja durchaus mehr als eins erzeugen kann, nicht funktionieren wird. Die `CloseQWidget()`-Methode schliesst dann immer nur das zuletzt geöffnete. Sophus hat sich hier einfach hoffnungslos übernommen und kommt da auch nicht raus ohne sich endlich mal mit OOP, und den Grundlagen von Qt zu beschäftigen.
Antworten