Replace CentralWidget in MainWindow

2020-06-17 05:33发布

问题:

I'm kinda new to PySide.I have a main window object which shows one widget at a time. I've been trying to change the central widget of the QMainWindow class in order to replace the visible Widget in the window when pressing a button. The problem is that the button pressed is in the Widget class, not in the main window class.

say...

class App(QtGui.QMainWindow):

    def __init__(self):
        super(App, self).__init__()

        self.initUI()

    def initUI(self):

        self.statusBar().showMessage('Listo.') #Status Bar
        self.login_screen = LoginScreen()
        self.logged_in_screen = LoggedInScreen()

        self.setCentralWidget(self.login_screen)

        self.setGeometry(300, 300, 450, 600) #Window Size
        self.setWindowTitle('PyTransactio - Client') #Window Title
        self.setWindowIcon(QtGui.QIcon('icon.png')) #App Icon
        self.show()

The pressed button is in the login_screen instance. The method called when the button is clicked is inside the LoginScreen class:

def login(self):
        """ Send login data to the server in order to log in """

        #Process

        self.setParent(None)

Setting the parent widget to None removes the widget (login_screen) from the main window. What should I do in order to get another widget (e.g. logged_in_screen) as the central widget of the main window when the loginButton (inside the login_screen widget) is pressed?

Maybe the login method should be inside the main window class? If so, how can I connect the buttons pressed in login_screen with the main window's method?

回答1:

You may use a QStackedWidget as central widget and add both the log-in screen and "logged-in" screen to it.

An example usage:

from PyQt4 import QtCore, QtGui


class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.central_widget = QtGui.QStackedWidget()
        self.setCentralWidget(self.central_widget)
        login_widget = LoginWidget(self)
        login_widget.button.clicked.connect(self.login)
        self.central_widget.addWidget(login_widget)
    def login(self):
        logged_in_widget = LoggedWidget(self)
        self.central_widget.addWidget(logged_in_widget)
        self.central_widget.setCurrentWidget(logged_in_widget)


class LoginWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(LoginWidget, self).__init__(parent)
        layout = QtGui.QHBoxLayout()
        self.button = QtGui.QPushButton('Login')
        layout.addWidget(self.button)
        self.setLayout(layout)
        # you might want to do self.button.click.connect(self.parent().login) here


class LoggedWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(LoggedWidget, self).__init__(parent)
        layout = QtGui.QHBoxLayout()
        self.label = QtGui.QLabel('logged in!')
        layout.addWidget(self.label)
        self.setLayout(layout)



if __name__ == '__main__':
    app = QtGui.QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

If you do not want to use this widget, then I think you'll have to call QMainWindow.setCentralWidget every time you change the central widget.

As to where the login method should be, it depends. Probably you could define a simple interface for your mainwindow to add/remove/show specific central widgets, and call it from the login method of LoginScreen. In this way the LoginScreen class does not have to know about implementation details such as if the central widget is actually a QStackedWidget or this thing is done in an other way.



回答2:

You can use QMainWindow.setCentralWidget to do this (repeatedly):

#! /usr/bin/env python3

from PySide import QtGui
from PySide import QtCore

import sys 

app = QtGui.QApplication(sys.argv)
mw = QtGui.QMainWindow()
w2 = QtGui.QWidget()
pb = QtGui.QPushButton('push me', w2) 

l1 = QtGui.QLabel('orig')
l2 = QtGui.QLabel('changed')
mw.setCentralWidget(l1)
pb.clicked.connect(lambda: mw.setCentralWidget(l2))
mw.show()
w2.show()
sys.exit(app.exec_())