Neues Fenster erzeugen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Robokopp
User
Beiträge: 64
Registriert: Mittwoch 3. November 2010, 12:04

Hallo

ich habe eine GUI erstellt, in der nun per Klick auf einen Menüeintrag ein neues MainWindow erzeugt werden soll.
Leider bekomm ich es nicht hin..

Hier mal der Quellcode:

Code: Alles auswählen

 #!/usr/bin/python



import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import QPushButton
import settings


class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        

#Beschreibung des Hauptfensters

        self.resize(800, 400)
        self.setWindowTitle(str('HappyBirthday'))
        
# Funktion 1: Exitbutton
        exit = QtGui.QAction('Quit', self)
       

        self.connect(exit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))
       
#Oeffnen eines neuen Fensters

        self.connect(self.settings,QtCore.SIGNAL('triggered()'),self.openWindow)

        def openWindow(self):
            self.window2 = settings.Window2()

        
        
        menubar = self.menuBar()
        
        file = menubar.addMenu('&Options')
        
        file.addAction(settings)
        file.addAction("Help")
        file.addAction("About")
        file.addAction(exit)
        
       
     #Buttons
     
     
             
        newgrp=QtGui.QPushButton(self)
        newgrp.setText("New group")
        newgrp.setGeometry(100, 300, 150, 100)
        
        edit=QtGui.QPushButton(self)
        edit.setText("Edit group")
        edit.setGeometry(300, 300, 150, 100)
 
        
        delgrp=QtGui.QPushButton(self)
        delgrp.setText("Delete group")
        delgrp.setGeometry(500, 300, 150, 100)
        

       # settings = QtGui.QPushButton(self)
        #settings.setText("Settings")


        
    #Label/Textfelder
    
        ueberschrift=QtGui.QLabel(self)
        ueberschrift.setText("HappyBirthday")
        ueberschrift.setGeometry(300, 40, 200, 30)
        
                                      
        font = QtGui.QFont('Serif', 20, QtGui.QFont.Light)  
        ueberschrift.setFont(font)                            

    
app = QtGui.QApplication(sys.argv)


main = MainWindow()
main.show()
sys.exit(app.exec_())


Das Fenster soll dann aus dem Script settings.py geladen werden:

Code: Alles auswählen

 #!/usr/bin/python
# -*- coding: utf-8 -*-

from PyQt4 import QtCore
from PyQt4 import QtGui

class Window2(QtGui.QMainWindow):
    def __init__(self,parent=None):
        QtGui.QMainWindow.__init__(self,parent)
Dabei erhalte ich immer diesen Fehler:

AttributeError: 'MainWindow' object has no attribute 'settings'

Ich muss mich für das Durcheinander entschuldigen. Habe viel rumprobiert und erstmal die Ordnung außenvor gelassen^^

Kann mir da jemand helfen und gibt es vielleicht noch eine einfachere Möglichkeit, um ein neues Fenster zu erstellen?

MfG
BlackJack

@Robokopp: Die Ausnahme ist doch auch irgendwie logisch!? Geh mal den Quelltext von `MainWindow.__init__()` durch bis Du zu der Zeile ``self.connect(self.settings...`` kommst und erklär mal wo Deiner Meinung nach das Attribut `settings` herkommen soll!? Das dürfte doch die Zeile sein, auf die Dich der Traceback hinweist, oder? Den könntest Du übrigens das nächste mal auch komplett zeigen. Die Informationen in Tracebacks stehen da nicht zum Spass, sondern um die Quelle von Ausnahmen leichter zu finden.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Da Du noch die Old-style Methode für connect() verwendest, sei mal der Hinweis auf die schönere New-style Doku angebracht: http://www.riverbankcomputing.co.uk/sta ... slots.html

Also z.B. aus Deinem Code:

Code: Alles auswählen

# aus
# self.connect(exit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))
# wird
self.exit.triggered.connect(self.close)
Liest sich doch eleganter, oder? :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Robokopp
User
Beiträge: 64
Registriert: Mittwoch 3. November 2010, 12:04

Wo du Recht hast.. :D

aber kannst du mir vielleicht bei meinem eigentlichen Problem lösen?
Ich kriegs nicht gebacken


EDIT:

hab das gerade mal getestet mit der "Neuen Schreibweise"

jetzt erhalte ich folgenden Error:

AttributeError: 'MainWindow' object has no attribute 'exit'
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Robokopp hat geschrieben: hab das gerade mal getestet mit der "Neuen Schreibweise"

jetzt erhalte ich folgenden Error:

AttributeError: 'MainWindow' object has no attribute 'exit'
Richtig, "exit" ist bei Dir ja ein lokales Attribut. Also ohne "self.", dann sollte es aber klappen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Robokopp
User
Beiträge: 64
Registriert: Mittwoch 3. November 2010, 12:04

Okay

ich hab jetzt das bei "Settings" auch nochmal geändert und bekomme den Fehler AttributeError: 'MainWindow' object has no attribute 'openWindow'

Warum? ich habe openWindow definiert unter MainWindow
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Robokopp hat geschrieben:Okay

ich hab jetzt das bei "Settings" auch nochmal geändert und bekomme den Fehler AttributeError: 'MainWindow' object has no attribute 'openWindow'

Warum? ich habe openWindow definiert unter MainWindow
Du hast eine Funktion openWindow() innerhalb der __init__-Methode Deiner MainWindow-Klasse definiert^1. Die "verschwindet" aber ja nach dem Abarbeiten von init. Was bleibt ist das Attribut self.window2.

^1 Was imho auch ziemlich merkwürdig ist!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Robokopp
User
Beiträge: 64
Registriert: Mittwoch 3. November 2010, 12:04

Also ich hab jetzt def openWindow weiter raus gerückt.Jetzt startet das Programm wieder.
Nur leider wurde das Setting Fenster nicht aufgerufen, weshalb ich den Code geändert hab:

Code: Alles auswählen

class Window2(QtGui.QMainWindow):
    def __init__(self,parent=None):
        QtGui.QMainWindow.__init__(self,parent)
        
        
        self.resize(800, 400)
        self.setWindowTitle(str('Settings'))
        

app2 = QtGui.QApplication(sys.argv)

        
set = Window2()
set.show()
sys.exit(app2.exec_())
Wenn ich jetzt mein Hauptprogramm starte, wird nur noch Settings angezeigt....das Hauptfenster nicht.
Danach hab ich "import settings" unter die Methode des Fensteraufrufs geschrieben.
Jetzt wird wieder das Hauptfenster beim Starten angezeigt und wenn ich auf Settings klicke, öffnet sich kurz das Fenster und beide schließen sich wieder.

Danach stürzt Python ab und ich bekomme eine Fehlermeldung von Windows^^
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also anstatt zu beschreiben, wo Du welchen import hinschreibst, solltest Du (in einem paste-bin wie paste.pocoo.org oder hier im Forum unter dem Logo) den lauffähigen Quellcode mal posten. So muss man sich alles zusammenreimen; unsauber wirkt er auch - die falsche Einrüclung zeigt mir, dass Du da entweder ein wenig schlampig arbeitest oder aber Wissenslücken hast (die viele Leerzeilen sind da auch nicht grad hilfreich; schau Dir doch mal PEP8 genauer an, da werden Empfehlungen zur Anzahl Leerzeilen gegeben).

Was ist eigentlich Dein Ziel? Zwei "QMainWindow" zu haben ist an sich eher ungewöhnlich. Ich würde wage darauf tippen, dass Du einen Dialog öffnen willst und kein neues MainWindow aufmachen möchtest.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Robokopp
User
Beiträge: 64
Registriert: Mittwoch 3. November 2010, 12:04

Ich bin Neuling auf dem Gebiet weswegen ich auch geschrieben habe, dass es sehr wirr ist^^

Was ist eigentlich Dein Ziel? Zwei "QMainWindow" zu haben ist an sich eher ungewöhnlich. Ich würde wage darauf tippen, dass Du einen Dialog öffnen willst und kein neues MainWindow aufmachen möchtest.
ich möchte halt lediglich einen neuen Bereich, in dem dann die Einstellungen aufgeführt sind

Mir erscheint das mit dem neuen Mainwindow auch ein bischen komisch, weil ich da dann ja entweder 2 offene Fenster gleichzeitig habe, oder immer eins schließen müsste
Dann werde ich das wohl mit dem Dialog mal versuchen....
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also das klingt für mich nach einem Dialog! Schau Dir doch mal in der Doku von Qt die verschiedenen Dialog-Klassen an; vermutlich gibt es da keinen fertigen "QSettingsDialog" passend zu den QSettings, zumindest hab ich in der Doku auf die schnelle keinen gefunden. Aber mit einem Dialog fährst Du richtig imho - zumindest sind bei allen GUI-Programmen, die ich so kenne, Einstellungen immer in Dialogen vorgehalten :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Robokopp
User
Beiträge: 64
Registriert: Mittwoch 3. November 2010, 12:04

Okay vielen Dank für die Info :)

Dazu hab ich dann gleich noch eine Frage

Dabei wird doch die QMainWindow Klasse behalten und darin dann das Dialogfenster geöffnet oder muss ich dafür dann ein QWidget nehmen?
Robokopp
User
Beiträge: 64
Registriert: Mittwoch 3. November 2010, 12:04

Ich brauch nochmal eben Hilfe^^

Ich habe jetzt ein MainWindow mit Menü erzeugt. Der Menüpunkt soll ein QWidget aufrufen.

den Menüpunkt habe ich mit folgendem definiert:

Code: Alles auswählen

settings=QtGui.QMenu("Settings", self)
menubar = self.menuBar
file.addAction(settings)
für das QWidget habe ich diese Methode erstellt:

Code: Alles auswählen

    def settings(self):
        self.settings = QtGui.QWidget(self)
        self.settings.show()
Wie realisiere ich jetzt den Aufruf?

Code: Alles auswählen

settings.triggered.connect(self.settings)
Das hier klappt nicht
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du musst doch eine QAction erstellen und das triggered Signal dieser Action mit einem Slot verbinden.

Im übrigen bringt es wenig, wenn Du Code-Schnipsel zeigst, die Namen beinhalten, von denen man keine Ahnung hat, welche Objekte an sie gebunden sind. Was ist "file"? (Der Name suggeriert wenig gutes und überschreibt zudem ein built-in, was man vermeiden sollte).

Was bringt die Zeile:

Code: Alles auswählen

menubar = self.menubar
?

Und gibt es einen Grund, wieso Du augenscheinlich nicht eine Dialog-Klasse aufrufst? (Ich gehe mal davon aus, dass ein neues Fenster aufpoppen soll, wie es bisher von Dir ja geschildert wurde im Threadverlauf)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Robokopp: Wenn der Aufruf der `settings()`-Methode klappt, bekommst Du gleich das nächste Problem: Sie definiert ein `settings`-Attribut und damit ist dann die Methode nicht mehr unter diesem Namen erreichbar. An ein Attribut kann eben immer nur ein Objekt gebunden sein.
Robokopp
User
Beiträge: 64
Registriert: Mittwoch 3. November 2010, 12:04

Okay sry
hier mal der ganze code

Code: Alles auswählen

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        
        exit = QtGui.QAction('Quit', self)
        settings=QtGui.QMenu("Settings", self)
        
        self.resize(800, 400)
        self.setWindowTitle(str('Settings'))
        
        menubar = self.menuBar()
        
        file = menubar.addMenu('&Options')
        file.addAction(settings)
        file.addAction("Help")
        file.addAction("About")
        file.addAction(exit)
        
        settings.triggered.connect(self.settings)
        exit.triggered.connect(self.close)
        
    def settings(self):
        self.settings = QtGui.QWidget(self)
        self.settings.show()
        
        
app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
Wie mit einem Slot verbinden?
Muss ich doch bei exit auch nicht machen und es klappt


@BlackJack

Müsste ich dann die Methode umbenennen?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Das ganze ist ja nicht mal ausführbar! Den Fehler hättest Du doch längst posten können! :roll:
Robokopp hat geschrieben:

Code: Alles auswählen

        # So ist es richtig
        exit = QtGui.QAction('Quit', self)
        # Das ist KEINE QAction!
        settings=QtGui.QMenu("Settings", self)
        
        # wozu das hier?      
        menubar = self.menuBar()
        
        # file ist kein guter Name, in diesem Zusammenhang eh nicht
        file = menubar.addMenu('&Options')
        # wäre settings eine QAction, wäre das richtig!
        file.addAction(settings)
        file.addAction(exit)
        # prinzipiell richtig, wenn settings eine QAction wäre        
        settings.triggered.connect(self.settings)
        # Genau HIER verbindest Du die Aktion doch mit einem SLOT!!!
        exit.triggered.connect(self.close)
        
    def settings(self):
        # Hier solltest Du imho einen Dialog nutzen.
        self.settings = QtGui.QWidget(self)
        self.settings.show()
        
        
app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
Wie mit einem Slot verbinden?
Muss ich doch bei exit auch nicht machen und es klappt
Doch! Siehe Kommentare im Code
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Vielleicht noch ein kleiner Tipp: Mit dem QtDesigner kannst Du die Menüs bereits komfortabel anlegen und die Actions definieren. Lediglich das connecten auf eigene Slots musst Du dann später manuell vornehmen. Standard-Slots wie "close" kannst Du sogar auch schon im Designer mit einer Action verbinden.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Robokopp
User
Beiträge: 64
Registriert: Mittwoch 3. November 2010, 12:04

ja schon, aaber

wenn ich nun settings = QtGui.QAction("settings", self) verwende, geht es genauso wenig.

Hatte das vorher so, aber dann dachte ich es liegt wohl an QAction, weil ich immer einen Fehler mit "QAction" bekommen habe, weswegen ich das geändert habe

das menubar = self.menuBar() habe ich aus irgendeinem Example entnommen, genauso wie die Bezeichnung "File"



LOL: Es geht auf einmal, aber ich weiß jetzt nicht warum. Hab das eigentlich genauso wie vorher...


Naja mit dem Designer kann ich zur Zeit noch garnix anfangen.Da fehlen mir irgendwie noch die Zusammenhänge

Ich will mir erstmal die Basics aneignen, um zu sehen, wie das alles funktioniert

Edit:Nächstes Problem

Ich habe ein paar Buttons im erzeugten QDialog erstellt.Die werden nicht angezeigt und Windowresize klappt auch nicht
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Robokopp hat geschrieben: wenn ich nun settings = QtGui.QAction("settings", self) verwende, geht es genauso wenig.

Hatte das vorher so, aber dann dachte ich es liegt wohl an QAction, weil ich immer einen Fehler mit "QAction" bekommen habe, weswegen ich das geändert habe.
Man kann ja trotz korrekter Klassen durchaus noch Fehler machen, aber "planloses" Ändern nach "Trial & Error" ist beim Programmieren selten zielführend. Du solltest Dir dann besser mal die Dokumentation angucken, oder Code-Schnipsel, die so etwas zeigen. Bei dem hättest Du Dir auch mal ein Beispiel im Desigber bauen können, das ui-File manuell per pyuic in eine Python-Datei wandeln und Dir angucken, wie die Jungs von Pyqt das "lösen".
das menubar = self.menuBar() habe ich aus irgendeinem Example ...
Vielleicht hatte es da auch Sinn! Hier ist es doch sinnlos, da Du doch nur eine Objektvariable an einen lokalen Namen bindest.

Code: Alles auswählen

menubar = self.menuBar()
file_menu = menubar.addMenu('&Options')
# ist doch so einfacher
file_menu = self.menuBar().addMenu('&Options')
... entnommen, genauso wie die Bezeichnung "File"
Dann war dieses Beispiel nicht gut ;-) (Kann ja auch ein C++ Beispiel gewesen sein?). Achte einfach darauf, dass man built-ins am besten nicht überschreibt. Viele Editoren mit Syntax-Highlighting bieten ja sogar spezielle Hervroherbungen für built-ins. Gibt auch Tools, die so etwas prüfen: http://pychecker.sourceforge.net/ (Man hat ja tatsächlich nicht immer alles im Kopf)
Naja mit dem Designer kann ich zur Zeit noch garnix anfangen.Da fehlen mir irgendwie noch die Zusammenhänge

Ich will mir erstmal die Basics aneignen, um zu sehen, wie das alles funktioniert
Prinzipiell auch eine gute Idee! Aber wie ich es oben beschrieb, kann einem der Designer da durchaus ja auch Hilfen geben, wie oben beschrieben beispielsweise.

Ich kann Dir auf jeden Fall auch mal die Snippet-Seite von lunar empfehlen; da findet man viel nützliches :-)
https://bitbucket.org/lunar/snippets/src
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten