Widget ausblenden/beenden

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

mein Programm besteht nun aus mehreren QWidgets innerhalb des MainWindows
jedes QWidget erhält Buttons, LineEdits etc

Wenn ich jetzt von einem Widget ins andere wechsel, bleiben die zuvor geladenen Buttons bestehen und werden auch im neuen Widget angezeigt.

Wie krieg ich die weg? Gibt es da eine destroy Methode etc?


(button.destroy() oder ähnlich)
lunar

Was verstehst Du denn unter „ins andere Widget wechseln“?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich weiß nicht genau, was Du da machst, aber generell gibt es Methoden wie show() und hide().

Eigentlich ist es eher unüblich, ständig neue UI-Elemente zu erzeugen, sondern man nutzt die einmal erstellten und füttert sie ggf. mit neueren / aktuellen Werten.

Du kannst Objekte natürlich (implizit) löschen, dazu gibt es das "del"-Statement:

Code: Alles auswählen

In [1]: a = 43

In [2]: del a

In [3]: a
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)

C:\Dokumente und Einstellungen\nelson\Eigene Dateien\<ipython console> in <modul
e>()

NameError: name 'a' is not defined
Der Name "a" wird durch del gelöscht, das Objekt dahinter dann vom Garbage-Collector. D.h. Du hast keinen Einfluss darauf, wann das passiert!

Aber beachte:

Code: Alles auswählen

In [4]: a = range(10)

In [5]: b = a

In [6]: del a

In [7]: b
Out[7]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Das Listen-Objekt ist noch an den Namen "b" gebunden, daher wird das Objekt vom Interpreter nicht gelöscht.

Ich glaube ehrlich gesagt, Du suchst etwas ganz anderes, als ständig Widgets und UI-Elemente zu generieren und wieder zu löschen. Evtl. sind TabWidgets, StackWidgets usw. etwas für Dich?
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

Hier mal der Code:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui


class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        #Window description
        self.resize(800, 400)
        self.setWindowTitle(str('Happy Birthday'))

        #Menupoints description

        exit = QtGui.QAction('Quit', self)
        settings = QtGui.QAction("Settings", self)
        help2 = QtGui.QAction("Help", self)
        about = QtGui.QAction("About",self)


        #menu creation
        menubar = self.menuBar()

        file = menubar.addMenu('&Options')
        file.addAction(settings)
        file.addAction(help2)
        file.addAction(about)
        file.addAction(exit)


        #Button function
        settings.triggered.connect(self.settingsm)
        exit.triggered.connect(self.close)
        about.triggered.connect(self.about)
        help2.triggered.connect(self.help2)
        #back.triggered.connect(self.__init__)

        #Pushbuttons

        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)

        #Button Slots
        newgrp.clicked.connect(self.newgrp)
        edit.clicked.connect(self.edgrp)
        delgrp.clicked.connect(self.delgrp)



    def newgrp(self):
        self.newgrp = QtGui.QWidget(self)

        self.setWindowTitle("New group")
        self.resize(800,400)
        name=QtGui.QLabel(self)
        name.setText("Groupname:")
        name.setGeometry(10,10,200,50)
        grpname=QtGui.QLineEdit(self)
        grpname.setGeometry(180,10,200,50)
        dialname=QtGui.QLabel(self)
        dialname.setText("Dialing number:")
        dialname.setGeometry(10,50,200,50)
        dialed=QtGui.QLineEdit(self)
        dialed.setGeometry(180,50,200,50)
        add=QtGui.QPushButton(self)
        add.setText("Add")
        add.setGeometry(400,50,100,50)
        add.show()
        dialed.show()
        dialname.show()
        grpname.show()
        name.show()
    def edgrp(self):
        self.edgrp = QtGui.QWidget(self)

        self.setWindowTitle("Edit group")
        self.resize(800,400)

    def delgrp(self):
        self.delgrp = QtGui.QWidget(self)

        self.setWindowTitle("Delete group")
        self.resize(800,400)

        table=QtGui.QComboBox(self)
        table.setGeometry(50,50,200,200)
        delbut=QtGui.QPushButton(self)
        delbut.setText("Delete")
        delbut.setGeometry(50,20,100,50)
        delbut.show
#        table.show()

    def settingsm(self):
        self.settingsm = QtGui.QWidget(self)

        self.setWindowTitle("Settings")
        self.resize(800,400)

        exit = QtGui.QPushButton("Exit",self)
        exit.clicked.connect(self.close)
        exit.setGeometry(100,100,100,100)

        #back = QtGui.QPushButton("Back",self)
        #back.clicked.connect(self.exit)

        exit.show()
        #back.show()

        #self.settingsm.show()





    def help2(self):
        QtGui.QMessageBox.information(self, "Introduction:\n",
                 "1.Create a new group for example:\n"
                 "Girls or Boys. Friends or business partners\n"
                 "2.Chose the dialing numbers, you wish to use\n"
                 "3.Create your own unpersonal greeting message\n"
                 "4.Save your group")


    def about(self):
        QtGui.QMessageBox.about(self, "About",
                 "sfdafefawegwa<gweg .")


app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
Nach dem Start sehe ich 3 Buttons, New Group, Edit Groups, Delete Groups

Klicke ich auf New Group, werden 2 LineEdits und 2 Labels erzeugt
wechsel ich dann nach Edit Groups, bleiben diese Inhalte bestehen, und das möchte ich eigentlich nicht

Was mich auch ein bischen stutzig macht ist, dass die 3 Buttons in jedem Widget angezeigt werden, obwohl sie eigentlich nur im QMainWindow sichtbar sein sollten
BlackJack

@Robokopp: Vergiss am besten erst einmal, dass es `setGeometry()` gibt. Widgets werden mit Layouts platziert.
Robokopp
User
Beiträge: 64
Registriert: Mittwoch 3. November 2010, 12:04

Aber so ist es irgendwie einfacher^^
Da kann ich alles so anordnen wie ich will

Aber zu meinem eigentlichen Problem:
Wie krieg ich diese Buttons wieder weg?
mit einem simplen del ist es nicht getan irgendwie
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich glaube Du hast ein paar Verständnisprobleme bezüglich Widgets. Bettest Du ein QWidet in ein anderes, so bekommt es natürlich keinen Window-Titel u.ä.. Nur der "Inhalt" wird dargestellt. Außerdem musst Du Dich um das Ein- bzw. Ausblenden selber kümmern (s. show() und hide()).

hinzu kommt das imho eigentümliche UI-Design an sich. Du benötigst doch irgend einen Datentypen ("Gruppe"?), der die Daten hält, die Du da verwalten willst. Imho ist das also ein Fall für ein Modell, welches Du dann in einem Container-Widget wie einem QListView anzeigen lässt. Daneben gibt es dann idR Felder für die Details, die beim Anklicken eines Items in dem View angezeigt wird. Daneben kann es dann noch die Buttons geben, die Du da bisher "global" im MainWindow stehen hast.

Ich habe mal ein kleines Demo-UI mit dem Designer zusammengeklickt:
Bild

Und hier der ui-Code:
UI-File

Natürlich habe ich hier das nicht modellbasierte QListWidget gewählt, damit ich im Test Einträge anlegen könnte. Das sollte man dann gegen ein QListView mit passendem Modell austauschen.
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 versteh grad garnix mehr

Der WindowTitel wird aber angezeigt.

Genau, das ein und ausbetten ist ja das wo ich hänge
ich müsste die Buttons bzw das ganze zuvor aufgerufene Widget ausbetten und ich hab keine Ahnung wie.

Wie muss ich diese Datentypen definieren?

Wiegesagt, ich hab noch keinen Bezug zu den UI Files und ich weiß nicht, wie sie arbeiten, weswegen ich damit nicht wirklich was anfangen kann
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Robokopp hat geschrieben:Ich versteh grad garnix mehr
Ich vermute einfach mal, das liegt daran, dass es hier ziemlich viele XY-Probleme gibt ;-)
Robokopp hat geschrieben: Der WindowTitel wird aber angezeigt.
Stimmt, mein Fehler.
Robokopp hat geschrieben: Genau, das ein und ausbetten ist ja das wo ich hänge
ich müsste die Buttons bzw das ganze zuvor aufgerufene Widget ausbetten und ich hab keine Ahnung wie.
Naja, indem Du eben je nach Button-Druck ein show() bzw. hide() für das entsprechende Widgets aufrufst.
Robokopp hat geschrieben: Wie muss ich diese Datentypen definieren?
Dazu gibt es einen Leitfaden zur Model-View-Controller-Programmierung. Ich weiß nicht, ob Riverbank dazu etwas eigenes bei ihrer PyQt-Doku hat, bei Nokias Qt-Doku gibt es einen.

Andere Frage: Wie wolltest Du denn bisher die einegegeben Gruppen speichern? Viele Anfänger nehmen eben ein QListWidget und stellen dann fest, dass sie manuell ein Mapping zwischen Item und dem dahinter liegenden Daten bauen müssen. Genau das leistet aber das Zusammenspiel von Model View und Controller letztlich einfacher und besser.
Wiegesagt, ich hab noch keinen Bezug zu den UI Files und ich weiß nicht, wie sie arbeiten, weswegen ich damit nicht wirklich was anfangen kann
Naja, Du kannst es Dir doch mal im Designer angucken. Außerdem habe ich deswegen ja auch den Screenshot gemacht.

Mir ging es um das UI-Design im allgemeinen. Ich kapiere halt Deinen Ansatz nicht so wirklich bzw. empfinde ihn atypisch. Vielleicht liege ich auch komplett daneben und Dein Entwurf bietet Funtktionalität oder Ergonomie für einen speziellen Anwendungsfall, den ich nicht kenne. Aus dem Bauch heraus wollte ich Dir damit nur zeigen, wie man das Problem obsolet machen kann, indem man Container-Widgets benutzt und die Buttons entsprechend logisch anordnet.

Es gibt da natürlich viele Wege nach Rom :-)

Zu den Layouts: Ja, die sind komplexer, daher verwenden viele ja auch einen Designer zum Anordnen und Managen der UI-Elemente. Andererseits bekommst Du nur so ein wirklich flexibles und anpassungsfähigs Endprodukt. Starre Layouts passen sich ja nicht gut den verschiedenen Auflösungen, Schruftgrößen usw. an.
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

Naja, indem Du eben je nach Button-Druck ein show() bzw. hide() für das entsprechende Widgets aufrufst.
button.clicked.connect(widget.hide())?

Zur Speicherung hab ich mir noch garkeine Gedanken gemacht.Ich wollte erstmal das Grundgerüst aufbauen, sehen dass der Menüwechsel klappt usw.

Um die einzelnen Funktionen kümmere ich mich später, zumal ich noch garnicht weiß, wie genau da was zusammenarbeiten muss.

Werde mir das mal anschauen

Ich erstelle mir grad selbst eine UI im Designer unter der Verwendung des QStackWidgets, in der Hoffnung dass dies in meinem Fall funktioniert.
Denn es macht ja im Prinzip nichts anderes, als verschiedene Seiten anzuzeigen, was mein Problem lösen könnte

Noch ne Frage zu den UI´s:

Ich erstelle ein Grundgerüst mit Buttons, die ich alle benenne und richtig platziere.
Muss ich dann im eigentlichen Code nur noch die connect-Zeile schreiben und Button.show() unter die jeweilige Klasse schreiben?
Und was ist, wenn ich ein vollwertiges Signal-Slot Konzept im Designer festgelegt habe? Dann muss ich ja eigentlich nur noch dafür sorgen, dass der Button und das zugehörige Element angezeigt werden, oder?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Robokopp hat geschrieben:
Naja, indem Du eben je nach Button-Druck ein show() bzw. hide() für das entsprechende Widgets aufrufst.
button.clicked.connect(widget.hide())?
z.B. :-)
Robokopp hat geschrieben: Noch ne Frage zu den UI´s:

Ich erstelle ein Grundgerüst mit Buttons, die ich alle benenne und richtig platziere.
Muss ich dann im eigentlichen Code nur noch die connect-Zeile schreiben und Button.show() unter die jeweilige Klasse schreiben?
Und was ist, wenn ich ein vollwertiges Signal-Slot Konzept im Designer festgelegt habe? Dann muss ich ja eigentlich nur noch dafür sorgen, dass der Button und das zugehörige Element angezeigt werden, oder?
Prinzipiell ja. Das show() ist iirc auch überflüssig, weiß ich jetzt nicht aus dem Kopf. Ist im Zweifel ja aber durch Ausprobieren sofort ersichtlich. Ich würde Dir dann noch dazu raten, das uic-Modul zum einbinden der ui-Files zu nutzen. (und nicht durch pyuic per Hand eine Python datei zu erstellen).
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

habs jetzt so versucht:

Code: Alles auswählen

newgrp.clicked.connect(self.delgrp.hide())
Resultat: AttributeError: 'function' object has no attribute 'hide'

Ich flipp aus

Prinzipiell ja. Das show() ist iirc auch überflüssig, weiß ich jetzt nicht aus dem Kopf. Ist im Zweifel ja aber durch Ausprobieren sofort ersichtlich. Ich würde Dir dann noch dazu raten, das uic-Modul zum einbinden der ui-Files zu nutzen. (und nicht durch pyuic per Hand eine Python datei zu erstellen).
Gut zu wissen

Ich dachte, man muss die UI files immer konvertieren.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Robokopp hat geschrieben:habs jetzt so versucht:

Code: Alles auswählen

newgrp.clicked.connect(self.delgrp.hide())
Resultat: AttributeError: 'function' object has no attribute 'hide'

Ich flipp aus
Du darfst die Funktion ja auch nicht aufrufen!

Code: Alles auswählen

newgrp.clicked.connect(self.delgrp.hide)
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
ging auch nich
ich versuch des jetzt mit dem UI File
es ist soweit fertig, nun versuch ich die Buttons zuzuordnen

Da hab ich so meine Probleme

wenn jetzt ein Button im Dsigner exit heißt, kann ich irgendwie per exit.clicked.connect(self.close) nichts bewirken

Was mache ich falsch?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Robokopp hat geschrieben:Okay
ging auch nich
Bei mir geht es - du hast also etwas falsch gemacht!
Robokopp hat geschrieben: wenn jetzt ein Button im Dsigner exit heißt, kann ich irgendwie per exit.clicked.connect(self.close) nichts bewirken

Was mache ich falsch?
K.A. ohne Quellcode geht da wenig ;-) Ich würde mal drauf tippen, dass Du "self.exit" nehmen musst. Aber das hängt natürlich durchaus von der Art ab, wie Du die UI-Daten in Deinen Code einbaust.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Robokopp: An was und wie hast Du den Namen `exit` denn vor dieser Zeile gebunden?

Ich habe so ein bisschen das Gefühl, dass GUI noch nicht Deine Baustelle ist -- dir fehlen noch Grundlagen in der Sprache selbst.
Robokopp
User
Beiträge: 64
Registriert: Mittwoch 3. November 2010, 12:04

Ok
Also bei mir geht jetzt eigentlich alles, was ein separates Fenster öffnet.About, Help und Exit (was ich als eigene Methode definieren musste)

Das mit dem Aufruf von Newgrp, Delgrp usw kann ja garnicht mehr gehen weil ich das jetzt alles im StackedWidget drin hab^^

Wie änder ich da jetzt die angezeigte Seite?

mit

Code: Alles auswählen

self.ui.newgrp.connect.stackedWidget.setCurrentIndex(self, 2)
gehts nicht

mit aufruf der Methode newgrp, welche das beinhaltet:

Code: Alles auswählen

self.stackedWidget.setCurrentIndex(self, 2)

auch nicht
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also Doku lesen musst Du schon mal lernen:
http://doc.qt.nokia.com/4.7/qstackedwid ... rentWidget

Ist doch sehr einfach zu finden!
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 hab ich doch
daher hab ich ja auch das setCurrentIndex

bekomme aber folgenden Fehler

QStackedWidget.setCurrentIndex(int): argument 1 has unexpected type 'MainWindow'

Edit:

Hab das self mal weggelassen

self.stackedWidget.setCurrentIndex(2)

Jetzt ist der Fehler weg aber der Index wird trotzdem nicht gewechselt
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Robokopp hat geschrieben:Ja hab ich doch
Aber offensichtlich nicht verstanden:
Doku hat geschrieben: the currently shown widget can be retrieved using the currentWidget() function, and altered using the setCurrentWidget() function.
Robokopp hat geschrieben: daher hab ich ja auch das setCurrentIndex
s.o. ;-)
Robokopp hat geschrieben: bekomme aber folgenden Fehler

QStackedWidget.setCurrentIndex(int): argument 1 has unexpected type 'MainWindow'
Wie BlackJack schon schrieb, mangelt es Dir an Basiswissen und Erfahrung:
"unexpected type" und dazu der Typ sagt Dir doch, dass Dein Aufruf falsch ist, da Du einen Typen übergibst, der nicht erwartet wird. In diesem Falle übergibst Du ein MainWindow-Objekt, die Funktion erwartet aber einen Integer.

Solche Fehler kann man leicht selber finden.
Robokopp hat geschrieben: Hab das self mal weggelassen

self.stackedWidget.setCurrentIndex(2)
Wie kommst Du überhaupt darauf, da ein self zu übergeben?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten