Framestappel - Frame hervor holen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
xXSkyWalkerXx1
User
Beiträge: 379
Registriert: Mittwoch 27. Juni 2018, 17:39

Abend ,

ich habe bereits vor langen immer Mal an GUIs gearbeitet, doch als Anfänger kennt man noch nicht alle Wege / Methoden, um am effizentesten ein Ziel zu erreichen.

Ich hatte es immer so gemacht:
Als zentrales Widget habe ich ein QFrame, welchen ich in 2 weitere Frame gesplittet habe (vertikal). Links sind Buttons, mit denen man die Frames wechselt, die rechts angezeigt werden. Okay, ein Wechsel war es eigentlich nicht wirklich. ^^ Ich hatte für jede neue "Seite" einfach bloß das Layout geändert und mit der for-Schleife Widgets zeigen lassen (.show()) bzw verstecken lassen (.hide()).
Eben nicht die smarte Variante... Da ich allerdings dabei bin mein Programmcode mal "professioneller" aussehen zu lassen, habe ich nachgeschaut wie das mit neuen Seiten innerhalb einer GUI ist, dabei bin ich auf ".raise_()" gestoßen - also z.b page_1_frame.raise_() , um ein Frame hervor zu holen und über die anderen Frames zu legen.

Nun ist die Frage, wie stelle ich das am Besten an, dass das zentrale Widget, also der Frame, geteilt wird ,aber nur rechts der Frame aktualisiert wird, also wenn ein neuer Frame hervor geholt wird?

Vllt wird das Ganze ja mehr mit dem Beispielprogramm klar?

Code: Alles auswählen

from PyQt5.QtWidgets import QApplication,QMainWindow,QLabel,QFrame,QHBoxLayout,QPushButton,QSplitter,QVBoxLayout
from PyQt5.QtCore    import Qt
import sys

#Testprogramm für raise_() von verschiedenen Seiten in einer GUI
#Bezüglich Frames stappeln und nur das gewünschte Frame hervor holen

class programm():
    app = QApplication(sys.argv)

    def main_window(self):
        self.window = QMainWindow()
        self.window.setWindowTitle("FrameStack Test")
        self.window.setGeometry(400,500,500,250)

        self.c_frame = QFrame()
        self.frame_left = QFrame()
        self.frame_right = QFrame()
        self.button1 = QPushButton("Seite 1")
        self.button2 = QPushButton("Seite 2")
        self.label1 = QLabel("Seite 1")
        self.label2 = QLabel("Seite 2")
        
        self.layout = QHBoxLayout()
        self.splitter = QSplitter(Qt.Horizontal)
        self.splitter.addWidget(self.frame_left)
        self.splitter.addWidget(self.frame_right)
        self.layout.addWidget(self.splitter)

        self.frame_right.setStyleSheet("background: solid red") #zum besseren Auseinanderhalten von beiden Frames

        self.layout_left = QVBoxLayout()
        self.splitter_left = QSplitter(Qt.Vertical)
        self.splitter_left.addWidget(self.button1)
        self.splitter_left.addWidget(self.button2)
        self.layout_left.addWidget(self.splitter_left)

        self.button1.clicked.connect(self.page_1)
        self.button2.clicked.connect(self.page_2)

        self.frame_left.setLayout(self.layout_left)
        self.c_frame.setLayout(self.layout)
        self.window.setCentralWidget(self.c_frame)
        self.window.show()


    def page_1(self):
        pass


    def page_2(self):
        pass
    


prog = programm()
prog.main_window()
sys.exit(prog.app.exec_())
Hierbei soll nur der rote Frame verändert werden.
Beim Programmstart wird die Startseite angezeigt.
Klicke ich aber auf den Button "Seite 1" soll im rechten, dem roten, Frame der Frame für die Seite 1 angezeigt werden.

Könnt ihr mir helfen?

Grüße,
xXSkyWalkerXx1
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Eine Klasse `programm` (eigentlich `Programm`) macht wenig Sinn. Die Klasse sieht eher aus, als ob es eine MainWindow-Klasse wäre. Das Klassenattribut `app` sollte in eine Funktion `main` wandern, die auch die letzten 3 Zeilen enthalten sollte, die Methode main_window sollte __init__ heißen.
xXSkyWalkerXx1
User
Beiträge: 379
Registriert: Mittwoch 27. Juni 2018, 17:39

Stimmt, eine Klasse schreibt man ja anfangs immer groß. Jetzt verstehe ich, wofür es jetzt hilfreich ist, dass meine Infolehrerin in der Oberschule uns dieses UML beibrachte.^^

Wegen MainWindow-Klasse, meinst damit, dass die Klasse "Programm" "Main Window" heißen sollte? Hm, dann baut sich gerade eine Vorstellung auf, wie ich den Code zu schreiben habe - also Hauptfenster mit den Menü-Leiste Funktionen in eine Klasse und in die anderen Klassen jeweils die für die neuen Seiten.
Dennoch ist damit noch nicht ganz meine Frage geklärt. :/

Und stimmt, sollte echt eher __init__ heißen...
xXSkyWalkerXx1
User
Beiträge: 379
Registriert: Mittwoch 27. Juni 2018, 17:39

Und, wie macht man sowas am Besten?
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

xXSkyWalkerXx1
User
Beiträge: 379
Registriert: Mittwoch 27. Juni 2018, 17:39

Bei https://doc.qt.io/qtforpython/PySide2/Q ... idget.html habe ich Mal so ein paar Codeschnippsel gefunden.

Doch, die "connect" - Sache funzt nicht, auch nicht, wenn ich "self.widget_stack.connect" schreibe (wobei self.widget_stack = QStackedWidget heißt)?

Code: Alles auswählen

connect(pageComboBox, SIGNAL("activated(int)"),
        stackedWidget, SLOT("setCurrentIndex(int)"))
Heißt das, dass es den Index der ComboBox abruft und vom gleichen Index das Widget des QStackWidget's abruft?
Und dadurch wird das Ganze auch angezeigt oder wie, also wie durch den Befehl ".show()"?
Ich mein, zum Bsp unten, wenn ich Seite 2 lade, wird dann "secondPageWidget" geöffnet oder wie? Und müsste ich somit auf dessen QWidget das Layout legen, worin der Splitter/GridLayout ist, um Widgets anzeigen zu lassen?

Und wie lasse ich dies in meinem Bsp.programm im rechten Frame anzeigen?
Einfach statt ein Frame rechts ein QStackedWidget legen und der Rest wie in dem Bsp. unten?

Code: Alles auswählen

firstPageWidget =  QWidget()
secondPageWidget =  QWidget()
thirdPageWidget =  QWidget()

stackedWidget =  QStackedWidget()
stackedWidget.addWidget(firstPageWidget)
stackedWidget.addWidget(secondPageWidget)
stackedWidget.addWidget(thirdPageWidget)

layout =  QVBoxLayout()
layout.addWidget(stackedWidget)
setLayout(layout)

pageComboBox = QComboBox()
pageComboBox.addItem(tr("Page 1"))
pageComboBox.addItem(tr("Page 2"))
pageComboBox.addItem(tr("Page 3"))
connect(pageComboBox, SIGNAL("activated(int)"),
        stackedWidget, SLOT("setCurrentIndex(int)"))
Ansonsten, denke ich, habe ich es ziemlich verstanden, hat geholfen dein Link, danke! @deets
xXSkyWalkerXx1
User
Beiträge: 379
Registriert: Mittwoch 27. Juni 2018, 17:39

Code: Alles auswählen

connect(pageComboBox, SIGNAL("activated(int)"),
        stackedWidget, SLOT("setCurrentIndex(int)"))
Also wie holt man genau mittels QStackedWidget ein Widget hervor?

Mittels des genannten "connect" oder wie?
Kann mir jemand die Parameter des "connect" 's erklären bzw eine Seite verlinken, die die Params diesen Befehls nennen? Habe nämlich zu "connect", außer in Bezug auf Socket, nichts gefunden.
xXSkyWalkerXx1
User
Beiträge: 379
Registriert: Mittwoch 27. Juni 2018, 17:39

Code: Alles auswählen

from PyQt5.QtWidgets import QApplication,QMainWindow,QStackedWidget,QWidget,QComboBox,QLabel,QFrame,QHBoxLayout,QPushButton,QSplitter,QVBoxLayout
from PyQt5.QtCore    import Qt
import sys

#Testprogramm für raise_() von verschiedenen Seiten in einer GUI

class programm():
    app = QApplication(sys.argv)

    def __init__(self):
        self.window = QMainWindow()
        self.window.setWindowTitle("FrameStack Test")
        self.window.setGeometry(400,500,500,250)
        self.stack = QStackedWidget()

        self.c_frame = QFrame()
        self.frame_left = QFrame()
        self.button1 = QPushButton("Seite 1")
        self.button2 = QPushButton("Seite 2")
        self.label1 = QLabel("Seite 1")
        self.label2 = QLabel("Seite 2")
        
        self.layout = QHBoxLayout()
        self.splitter = QSplitter(Qt.Horizontal)
        self.splitter.addWidget(self.frame_left)
        self.splitter.addWidget(self.stack)
        self.layout.addWidget(self.splitter)

        self.layout_left = QVBoxLayout()
        self.splitter_left = QSplitter(Qt.Vertical)
        self.splitter_left.addWidget(self.button1)
        self.splitter_left.addWidget(self.button2)
        self.layout_left.addWidget(self.splitter_left)

        self.page1 = QWidget()
        self.page2 = QWidget()
        self.stack.addWidget(self.page1)
        self.stack.addWidget(self.page2)
        self.button1.clicked.connect(lambda : self.stack.setCurrentIndex(0))
        self.button2.clicked.connect(lambda : self.stack.setCurrentIndex(1))

        self.frame_left.setLayout(self.layout_left)
        self.c_frame.setLayout(self.layout)
        self.window.setCentralWidget(self.c_frame)
        self.window.show()


    def page_1(self):
        self.button = QPushButton("Nächste...")
        self.layout_stack = QVBoxLayout()
        self.splitter_stack = QSplitter(Qt.Vertical)
        self.splitter_stack.addWidget(QLabel("Öffne Seite 2:"))
        self.splitter_stack.addWidget(self.button)
        self.layout_stack.addWidget(self.splitter_stack)

        self.page1.setLayout(self.layout_stack)
        self.button.clicked.connect(lambda : self.stack.setCurrentIndex(1))


    def page_2(self):
        self.button = QPushButton("Nächste...")
        self.layout_stack = QVBoxLayout()
        self.splitter_stack = QSplitter(Qt.Vertical)
        self.splitter_stack.addWidget(QLabel("Öffne Seite 1:"))
        self.splitter_stack.addWidget(self.button)
        self.layout_stack.addWidget(self.splitter_stack)

        self.page2.setLayout(self.layout_stack)
        self.button.clicked.connect(lambda : self.stack.setCurrentIndex(0))
    


prog = programm()
prog.__init__()
sys.exit(prog.app.exec_())
Okay,hatte diese Idee - aber sie funzt nicht, wieso?
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wie du

Code: Alles auswählen

self.button2.clicked.connect
benutzen kannst, aber es dir nicht ersichtlich ist, dass ANDERE Signale genauso verwendet werden - das erschliesst sich mir jetzt nicht so recht.
xXSkyWalkerXx1
User
Beiträge: 379
Registriert: Mittwoch 27. Juni 2018, 17:39

Wie meinst du das - verstehe nicht worauf du hinaus willst?
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das connect, das du in den Beispielen gesehen hast, und das ein SIGNAL mit einem SLOT verbindet - das BENUTZT du doch schon. Was also ist jetzt die grosse konzeptionelle Unbekannte, auf deren Suche du bist?

Code: Alles auswählen

connect(pageComboBox, SIGNAL("activated(int)"),
        stackedWidget, SLOT("setCurrentIndex(int)"))
ist doch einfach nur das verbinden von einem Signal mit einem Slot.

So wie du das auch schon andauernd in deinem eigenen Code machst. Was also ist ein Signal, was ist ein Slot, und wie verbindet man die? Was koennte also die Umsetzung von dem code-snippet hier sein, wenn man das in Python machen will?
xXSkyWalkerXx1
User
Beiträge: 379
Registriert: Mittwoch 27. Juni 2018, 17:39

Okay, hatte es eben so gelöst, dass ich eine Funktion normal aufrufe und da den QStackedWidget Index setze.

Dann habe ich gesehen, dass du geantwortet hast und dein's durchdacht und dann dachte ich mir so: Boar, na klar! Wie dumm bin ich manchmal?! xD Verstehe auch nun, wie deine vorherige Nachricht gemeint war und ja, kenne die anderen Signale... Aber, ich weiß auch nicht worin das Problem lag - so hohl von mir. ^^
Und jetzt funktioniert es, danke! :)
Antworten