从另一个文件中的按钮切换 QStackedWidget 中的小部件

Posted

技术标签:

【中文标题】从另一个文件中的按钮切换 QStackedWidget 中的小部件【英文标题】:Switch widget in QStackWidget from a button in another file 【发布时间】:2020-05-29 14:08:02 【问题描述】:

我有两个 py 文件。一个是主窗口,里面有一个 QStackedWidget,setCurrentWidget 是根据条件设置的。另一个文件有一个小部件,该小部件动态添加到堆叠的小部件中,并在单击主窗口中的按钮时设置为当前小部件。 第二个文件中的小部件有一个对话框,其中有一个按钮。我要做的是,单击对话框内的按钮时,应关闭对话框并根据条件设置 setCurrentWidget 并将小部件从堆叠的小部件中删除。

这是我尝试过的:

主窗口.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)

我可以将代码合并在一起并使其工作,但我试图保持目录干净。

【问题讨论】:

【参考方案1】:

这里发生了很多事情,但让我们分解一下。

主要问题似乎是模块之间的杂耍。尽管来回导入模块看起来很吸引人,但它并没有真正起作用。您需要寻找的是可以使用的内置Signals module。

另一个更大的问题是您正在重新分配一些属性,尽管您确实不应该这样做。您还应该重新访问用于分配.setCurrentWidget 的条件。当前条件为if list1 doesn't exist, do this. Else, do the other。另外,switch_widget 应该在def __init__(self): 之外。

我重写了代码的某些部分,以使其与信号一起工作,作为您的示例。

主窗口.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)

最后,查看Python coding conventions 以了解命名和其他“次要”细节。

【讨论】:

效果很好。 P.S:这是从我的原始代码中复制某些内容的快速尝试,该代码太大而无法在此处发布。谢谢。

以上是关于从另一个文件中的按钮切换 QStackedWidget 中的小部件的主要内容,如果未能解决你的问题,请参考以下文章

从另一个线程更改按钮图标/切换按钮

单击按钮时如何从另一个 Python 文件中读取 QLineEdit 值的值

使用 UIView 中的按钮从另一个 ViewController 触发方法

如何知道从另一个视图控制器中的 UICollectionViewController 按下了哪个按钮

文件中的两个字符串,将它们转换为整数然后从另一个中减去一个整数

从另一个场景切换启用/禁用 MenuItem javafx?