通过 QStackedWidget 动态修改同一小部件​​的多个实例

问题描述

我无法动态更改 QStackedWidget 的多个实例的布局/元素。下面的完整代码使人们能够切换按钮,单击该按钮时将创建一个 QFrame,其具有被切换的按钮的相应名称,因此当取消切换时,将删除具有与该按钮相关联的相应名称的框架。但是,我希望能够使用它旁边的 QComboBox 来修改通过左侧按钮创建的 QFrames 的布局。在前面的示例中,我已经能够取消单击所有按钮,从而删除框架,然后通过组合框选择正确的布局,然后在我通过重新切换按钮重新创建框架时查看调整后的框架布局。我正在寻找一种解决方案,让我显然无需单击和取消单击框架的相应按钮即可执行此操作。

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys



class Box(QFrame):
    def __init__ (self,title):
        super().__init__()
        self.title = title

        self.frame1_UI = QWidget()
        self.frame2_UI = QWidget()
        self.frame3_UI= QWidget()

        self.frame1()
        self.frame2()
        self.frame3()

        self.Stack = QStackedWidget(self)
        self.Stack.addWidget(self.frame1_UI)
        self.Stack.addWidget(self.frame2_UI)
        self.Stack.addWidget(self.frame3_UI)

        name = QLabel(title)  
        task_h_box = QHBoxLayout()
        task_h_box.addWidget(name)
        task_h_box.addWidget(self.Stack)
        self.setLayout(task_h_box)

    def text(self):
        return self.title

    def frame1(self):
        label = QLabel('frame1')
        task_h_box = QHBoxLayout()
        task_h_box.addWidget(label)
        self.setStyleSheet("QFrame{background-color: rgb(0,0); border-radius: 10px;}")
        self.frame1_UI.setLayout(task_h_box)
    
    def frame2(self):
        
        label = QLabel('frame2')
        task_h_box = QHBoxLayout()
        task_h_box.addWidget(label)
        self.frame2_UI.setLayout(task_h_box)
        self.setStyleSheet("QFrame{background-color: rgb(100,100,100); border-radius: 10px;}")

    def frame3(self):
        label = QLabel('frame3')
        task_h_box = QHBoxLayout()
        task_h_box.addWidget(label)
        self.frame3_UI.setLayout(task_h_box)
        self.setStyleSheet("QFrame{background-color: rgb(150,150,150); border-radius: 10px;}")


class window(QMainWindow):
    def __init__(self):
        super().__init__()
        

        widget = QWidget(self)
        
        #Widgets
        creator_button = QPushButton('Creator')
        creator_button.setCheckable(True)
        creator_button.clicked.connect(self.creation)

        creator_button2 = QPushButton('Creator 2')
        creator_button2.setCheckable(True)
        creator_button2.clicked.connect(self.creation)
        
        self.control_button = QComboBox()
        self.control_button.addItem('frame1')
        self.control_button.addItem('frame2')
        self.control_button.addItem('frame3')
        
        self.control_button.currentIndexChanged.connect(self.transition)
        
        #Layouts
        self.layout = QHBoxLayout(widget)
        self.creator_layout = QVBoxLayout()
        self.control_layout = QVBoxLayout()
        self.box_layout = QVBoxLayout()
        self.layout.addLayout(self.creator_layout)
        self.layout.addLayout(self.control_layout)
        self.layout.addLayout(self.box_layout)
        
        #Placements
        self.creator_layout.addWidget(creator_button)
        self.creator_layout.addWidget(creator_button2)
        self.control_layout.addWidget(self.control_button)

        self.setCentralWidget(widget)
        self.boxList = []
        self.show()

    def creation(self,checked):
        sender = self.sender()
        title = str('I am son of ' + sender.text())
        if checked:
            widget = Box(title)
            self.box_layout.addWidget(widget)
            self.boxList.append(widget.text())
        elif not checked:
            x = self.boxList.index(title)
            self.box_layout.itemAt(x).widget().deleteLater()
            self.boxList.remove(title)

    
    def transition(self,i): 
        title = ('I am son of Creator 2') 
        self.Box = Box(title)
        self.Box.Stack.setCurrentIndex(i)

        
        

app = QApplication(sys.argv)
window = window()
sys.exit(app.exec_())

解决方法

您不需要在 transition 中创建另一个 Box,只需更改现有的 QStackWidget 的索引即可。

def transition(self,i): 
    for box in self.findChildren(Box):
        box.Stack.setCurrentIndex(i)

然后在创建 Box 时设置索引也是有意义的。

def creation(self,checked):
    sender = self.sender()
    title = str('I am son of ' + sender.text())
    if checked:
        widget = Box(title)
        widget.Stack.setCurrentIndex(self.control_button.currentIndex())
        self.box_layout.addWidget(widget)
        self.boxList.append(widget.text())
    elif not checked:
        x = self.boxList.index(title)
        self.box_layout.itemAt(x).widget().deleteLater()
        self.boxList.remove(title)

这应该对代码进行最少的更改。但是,如果您在切换按钮时显示/隐藏 Box 小部件而不是每次都创建/销毁一个新实例,那么整个事情就可以简化。

class window(QMainWindow):
    def __init__(self):
        super().__init__()
        widget = QWidget(self)

        self.box = Box('I am son of Creator',visible=False)
        self.box2 = Box('I am son of Creator 2',visible=False)

        creator_button = QPushButton('Creator',checkable=True)
        creator_button.toggled[bool].connect(self.box.setVisible)
        creator_button2 = QPushButton('Creator 2',checkable=True)
        creator_button2.toggled[bool].connect(self.box2.setVisible)
        
        control_button = QComboBox()
        control_button.addItems(['frame1','frame2','frame3'])
        control_button.currentIndexChanged.connect(self.transition)
        
        grid = QGridLayout(widget)
        grid.addWidget(creator_button,0)
        grid.addWidget(creator_button2,1,0)
        grid.addWidget(control_button,2,1)
        grid.addWidget(self.box,2)
        grid.addWidget(self.box2,2)
        
        self.setCentralWidget(widget)
        self.show()
    
    def transition(self,i):
        self.box.Stack.setCurrentIndex(i)
        self.box2.Stack.setCurrentIndex(i)

并且只需要为 visible=False 的 Box 构造函数添加 unpack 关键字参数。

class Box(QFrame):
    def __init__ (self,title,**kwargs):
        super().__init__(**kwargs)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...