Search code examples
pythonpython-3.xpyqt5pyside2

Switch widget in QStackWidget from a button in another file


I got two py files. One has the main window with a QStackedWidget inside, the setCurrentWidget is set according to a condition. The other file has a widget which is dynamically added into the stacked widget and set as current widget when a button in the main window is clicked. The widget in the second file has a dialog with a button in it. What I'm trying to do is, on clicking the button inside the dialog, the dialog should be closed and the setCurrentWidget is set according to the condition and the widget is removed from the stacked widget.

Here is what I've tried:

mainwindow.py

import sys
import os
import pathlib
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *


list1 = ["item1", "item2", "item3"]


class MainWindow(QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.resize(400, 300)

        self.toolbar = QWidget()
        self.toolbar.setFixedHeight(30)
        self.toolbar.setStyleSheet("background: grey;")

        self.button = QPushButton("Click here!")
        t_layout = QHBoxLayout()
        t_layout.setMargin(0)
        t_layout.addWidget(self.button)
        self.toolbar.setLayout(t_layout)

        self.p1_label = QLabel("Such empty!")
        self.p1_label.setStyleSheet("font-size: 30px;")
        self.p1_label.setAlignment(Qt.AlignCenter)

        self.p2_widget = QWidget()
        self.p2_widget.setStyleSheet("background: orange;")

        self.sw = QStackedWidget()
        self.sw.addWidget(self.p1_label)
        self.sw.addWidget(self.p2_widget)

        if not list1:
            self.sw.setCurrentWidget(self.p1_label)
        else:
           self.sw.setCurrentWidget(self.p2_widget)

        self.mw_layout = QVBoxLayout()
        self.mw_layout.addWidget(self.toolbar)
        self.mw_layout.addWidget(self.sw)
        self.setLayout(self.mw_layout)

        def switch_widget():
            import widget_test
            p3 = widget_test.widget()
            self.sw.addWidget(p3)
            self.sw.setCurrentWidget(p3)

        self.button.clicked.connect(switch_widget)

    def switch_back(self):
        import widget_test
        p3 = widget_test.widget()
        mwin = MainWindow()
        sw_ = mwin.sw
        sw_.removeWidget(p3)
        p1 = mwin.p1_label
        p2 = mwin.p2_widget
        if not list1:
            sw_.setCurrentWidget(p1)
        else:
            sw_.setCurrentWidget(p2)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())

widget.py

import sys
import os  
import pathlib
import datetime
from PySide2.QtWidgets import *
from PySide2 import *
from PySide2.QtCore import *
from PySide2.QtGui import *


class widget(QWidget):
    def __init__(self):
        super(widget, self).__init__()
        self.setStyleSheet("background: teal;")

        widget_label = QLabel("fluid dynamics is cool")
        show_pop_up = QPushButton("show pop up")

        pop_up = QDialog(self)
        pop_up_label = QLabel("click below to, hopefully, get outta here")
        get_outta_here = QPushButton("get outta here")
        pop_up_layout = QVBoxLayout()
        pop_up_layout.addWidget(pop_up_label)
        pop_up_layout.addWidget(get_outta_here)
        pop_up.setLayout(pop_up_layout)

        def show_popup():
            pop_up.show()

        def get_out():
            from main_test import MainWindow
            MainWindow.switch_back(self)
            pop_up.reject()

        get_outta_here.clicked.connect(get_out)

        show_pop_up.clicked.connect(show_popup)

        widget_layout = QVBoxLayout()
        widget_layout.addWidget(widget_label)
        widget_layout.addWidget(show_pop_up)
        self.setLayout(widget_layout)

I could merge the code together and make it work but I'm trying to keep the directory clean.


Solution

  • There is a lot going on here, but let's break it down.

    The main problem seems to be juggling between modules. Eventhough it might seem appealing to import the modules back and forth, it doesn't really work. What you need to look for, is the built-in Signals module that you can utilize.

    Another bigger problem is that you are re-assigning some attributes eventhough you really shouldn't. You also should revisit the condition you are using to assign the .setCurrentWidget. Currently the condition reads as if list1 doesn't exist, do this. Else, do the other. Also, switch_widget should be outside of the def __init__(self):.

    I rewrote some parts of the code to make it work with signals as an example for you.

    mainwindow.py

    import sys
    import os
    import pathlib
    from PySide2.QtWidgets import *
    from PySide2 import *
    from PySide2.QtCore import *
    from PySide2.QtGui import *
    from widget_test import widget
    
    
    
    list1 = ["item1", "item2", "item3"]
    
    
    class MainWindow(QWidget):
        def __init__(self):
            super(MainWindow, self).__init__()
            self.resize(400, 300)
    
            self.toolbar = QWidget()
            self.toolbar.setFixedHeight(30)
            self.toolbar.setStyleSheet("background: grey;")
    
            self.button = QPushButton("Click here!")
            t_layout = QHBoxLayout()
            t_layout.setMargin(0)
            t_layout.addWidget(self.button)
            self.toolbar.setLayout(t_layout)
    
            self.p1_label = QLabel("Such empty!")
            self.p1_label.setStyleSheet("font-size: 30px;")
            self.p1_label.setAlignment(Qt.AlignCenter)
    
            self.p2_widget = QWidget()
            self.p2_widget.setStyleSheet("background: orange;")
    
            self.p3 = None
    
            self.sw = QStackedWidget()
            self.sw.addWidget(self.p1_label)
            self.sw.addWidget(self.p2_widget)
    
            if not list1:
                self.sw.setCurrentWidget(self.p1_label)
            else:
               self.sw.setCurrentWidget(self.p2_widget)
    
            self.mw_layout = QVBoxLayout()
            self.mw_layout.addWidget(self.toolbar)
            self.mw_layout.addWidget(self.sw)
            self.setLayout(self.mw_layout)
    
            self.button.clicked.connect(self.switch_widget)
    
        def switch_widget(self):
            self.p3 = widget()
            self.p3.update_signal.connect(self.switch_back)
            self.sw.addWidget(self.p3)
            self.sw.setCurrentWidget(self.p3)
    
    
        def switch_back(self):
            self.sw.removeWidget(self.p3)
            if list1:
                self.sw.setCurrentWidget(self.p1_label)
            else:
                self.sw.setCurrentWidget(self.p2_widget)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        mw = MainWindow()
        mw.show()
        sys.exit(app.exec_())
    

    widget.py

    import sys
    import os
    import pathlib
    import datetime
    from PySide2.QtWidgets import *
    from PySide2 import *
    from PySide2.QtCore import *
    from PySide2.QtGui import *
    from PySide2.QtCore import Signal
    
    
    class widget(QWidget):
        update_signal = Signal()
        def __init__(self):
            super(widget, self).__init__()
            self.setStyleSheet("background: teal;")
    
            widget_label = QLabel("fluid dynamics is cool")
            show_pop_up = QPushButton("show pop up")
    
            pop_up = QDialog(self)
            pop_up_label = QLabel("click below to, hopefully, get outta here")
            get_outta_here = QPushButton("get outta here")
            pop_up_layout = QVBoxLayout()
            pop_up_layout.addWidget(pop_up_label)
            pop_up_layout.addWidget(get_outta_here)
            pop_up.setLayout(pop_up_layout)
    
            def show_popup():
                pop_up.show()
    
            def get_out():
                self.update_signal.emit()
                pop_up.reject()
    
            get_outta_here.clicked.connect(get_out)
    
            show_pop_up.clicked.connect(show_popup)
    
            widget_layout = QVBoxLayout()
            widget_layout.addWidget(widget_label)
            widget_layout.addWidget(show_pop_up)
            self.setLayout(widget_layout)
    

    Finally, check Python coding conventions for naming and other "minor" details.