PySide - QStackedLayout.setCurrentIndex() 在 for 循环内时无法按预期工作
PySide - QStackedLayout.setCurrentIndex() does not work as expected when it's inside a for-loop
我正在实现一个UI,上面有几个按钮,按钮下面有一个QStackedLayout对象,目的是点击不同的按钮会自动切换到它关联的QWidget,也就是在 QStackedLayout 对象中。并且按钮的数量和它们关联的 QWidget 是动态添加的。
例如,这里我想实现一个简单的 window,它包含两个按钮 'a' 和 'b',理想情况下,当单击 'a' 按钮时,您应该请参阅下面的标签 'a',这意味着 QStackedLayout 设置为包含 QLabel 'a' 的适当小部件,类似的规则也应适用于按钮 'b'。所以我写了以下代码:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class main_gui(QWidget):
def __init__(self, parent = None):
super(main_gui, self).__init__(parent)
#create a root level widget
self.main_widget = QWidget()
#create a root level layout that holds all the child widgets
self.main_layout = QVBoxLayout(self.main_widget)
# widgets for buttons layout
self.asset_type_buttons_widget = QWidget()
# layout for all buttons
self.asset_type_buttons_layout = QHBoxLayout(self.asset_type_buttons_widget)
# now create the stack layout
self.asset_stacked_widget = QWidget()
self.asset_stacked_layout = QStackedLayout(self.asset_stacked_widget)
# add the buttons and stack layout into the root level layout
self.main_layout.addWidget(self.asset_type_buttons_widget)
self.main_layout.addWidget(self.asset_stacked_widget)
#dynamically adds buttons and stacked widgets, here we're going to add 2 buttons, which their labels are 'a' and 'b'
self.create_asset_sections(self.asset_stacked_layout, self.asset_type_buttons_layout, 'a','b')
self.main_widget.show()
def create_asset_sections(self, stack_layout, parent_buttons_layout, *asset_types):
# asset_types represents any arbitrary number of buttons and their associated stacked widgets
for type in asset_types:
index = asset_types.index(type)
self.type_top_button = QPushButton(type)
parent_buttons_layout.addWidget(self.type_top_button)
self.type_top_widget = QWidget()
self.type_top_layout = QVBoxLayout(self.type_top_widget)
i = stack_layout.insertWidget(index, self.type_top_widget)
self.test_label = QLabel(type)
self.type_top_layout.addWidget(self.test_label)
self.type_top_button.clicked.connect(lambda: stack_layout.setCurrentIndex(i))
app = QApplication(sys.argv)
gui = main_gui()
app.exec_()
但是执行上面的代码你应该注意到标签'a'只出现了一次,那么无论你点击按钮'a'还是按钮'b',标签'b'都是始终显示在按钮下方。
我也尝试修改代码然后使用 QStackedLayout.setCurrentWidget() 方法,这是 create_asset_sections()
的另一个版本
def create_asset_sections(self, stack_layout, parent_buttons_layout, *asset_types):
# create a dictionary that holds the buttons and their associated stack widgets
self.map_buttons_widgets = {}
for type in asset_types:
self.type_top_button = QPushButton(type)
parent_buttons_layout.addWidget(self.type_top_button)
self.type_top_widget = QWidget()
self.type_top_layout = QVBoxLayout(self.type_top_widget)
stack_layout.addWidget(self.type_top_widget)
self.test_label = QLabel(type)
self.type_top_layout.addWidget(self.test_label)
self.map_buttons_widgets[self.type_top_button] = self.type_top_widget
for btn, wigt in self.map_buttons_widgets.iteritems():
btn.clicked.connect(lambda: stack_layout.setCurrentWidget(wigt))
所以用上面的方法代替之前的方法也不能达到我原来的目的
有什么想法吗?预先感谢您的回答。
看到这个 question。这是一个不同的问题,但他们遇到的问题本质上是相同的。这一行就是问题
self.type_top_button.clicked.connect(lambda: stack_layout.setCurrentIndex(i))
具体
lambda: stack_layout.setCurrentIndex(i)
问题是当您创建 lambda 函数时,i
的值没有计算。它在调用 lambda 函数时进行评估,到那时,循环已经完成,每个 lambda
将在循环结束时使用完全相同的 i
值,而不是 i
创建 lambda
时。
您可以通过两种方式解决这个问题。第一种是在 lambda
中使用默认参数,这会强制在函数创建时计算 i
的值。
lambda i=i: stack_layout.setCurrentIndex(i)
或者,您可以使用 functools.partial
from functools import partial
self.type_top_button.clicked.connect(partial(layout.setCurrentIndex, i))
我正在实现一个UI,上面有几个按钮,按钮下面有一个QStackedLayout对象,目的是点击不同的按钮会自动切换到它关联的QWidget,也就是在 QStackedLayout 对象中。并且按钮的数量和它们关联的 QWidget 是动态添加的。
例如,这里我想实现一个简单的 window,它包含两个按钮 'a' 和 'b',理想情况下,当单击 'a' 按钮时,您应该请参阅下面的标签 'a',这意味着 QStackedLayout 设置为包含 QLabel 'a' 的适当小部件,类似的规则也应适用于按钮 'b'。所以我写了以下代码:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class main_gui(QWidget):
def __init__(self, parent = None):
super(main_gui, self).__init__(parent)
#create a root level widget
self.main_widget = QWidget()
#create a root level layout that holds all the child widgets
self.main_layout = QVBoxLayout(self.main_widget)
# widgets for buttons layout
self.asset_type_buttons_widget = QWidget()
# layout for all buttons
self.asset_type_buttons_layout = QHBoxLayout(self.asset_type_buttons_widget)
# now create the stack layout
self.asset_stacked_widget = QWidget()
self.asset_stacked_layout = QStackedLayout(self.asset_stacked_widget)
# add the buttons and stack layout into the root level layout
self.main_layout.addWidget(self.asset_type_buttons_widget)
self.main_layout.addWidget(self.asset_stacked_widget)
#dynamically adds buttons and stacked widgets, here we're going to add 2 buttons, which their labels are 'a' and 'b'
self.create_asset_sections(self.asset_stacked_layout, self.asset_type_buttons_layout, 'a','b')
self.main_widget.show()
def create_asset_sections(self, stack_layout, parent_buttons_layout, *asset_types):
# asset_types represents any arbitrary number of buttons and their associated stacked widgets
for type in asset_types:
index = asset_types.index(type)
self.type_top_button = QPushButton(type)
parent_buttons_layout.addWidget(self.type_top_button)
self.type_top_widget = QWidget()
self.type_top_layout = QVBoxLayout(self.type_top_widget)
i = stack_layout.insertWidget(index, self.type_top_widget)
self.test_label = QLabel(type)
self.type_top_layout.addWidget(self.test_label)
self.type_top_button.clicked.connect(lambda: stack_layout.setCurrentIndex(i))
app = QApplication(sys.argv)
gui = main_gui()
app.exec_()
但是执行上面的代码你应该注意到标签'a'只出现了一次,那么无论你点击按钮'a'还是按钮'b',标签'b'都是始终显示在按钮下方。
我也尝试修改代码然后使用 QStackedLayout.setCurrentWidget() 方法,这是 create_asset_sections()
的另一个版本def create_asset_sections(self, stack_layout, parent_buttons_layout, *asset_types):
# create a dictionary that holds the buttons and their associated stack widgets
self.map_buttons_widgets = {}
for type in asset_types:
self.type_top_button = QPushButton(type)
parent_buttons_layout.addWidget(self.type_top_button)
self.type_top_widget = QWidget()
self.type_top_layout = QVBoxLayout(self.type_top_widget)
stack_layout.addWidget(self.type_top_widget)
self.test_label = QLabel(type)
self.type_top_layout.addWidget(self.test_label)
self.map_buttons_widgets[self.type_top_button] = self.type_top_widget
for btn, wigt in self.map_buttons_widgets.iteritems():
btn.clicked.connect(lambda: stack_layout.setCurrentWidget(wigt))
所以用上面的方法代替之前的方法也不能达到我原来的目的
有什么想法吗?预先感谢您的回答。
看到这个 question。这是一个不同的问题,但他们遇到的问题本质上是相同的。这一行就是问题
self.type_top_button.clicked.connect(lambda: stack_layout.setCurrentIndex(i))
具体
lambda: stack_layout.setCurrentIndex(i)
问题是当您创建 lambda 函数时,i
的值没有计算。它在调用 lambda 函数时进行评估,到那时,循环已经完成,每个 lambda
将在循环结束时使用完全相同的 i
值,而不是 i
创建 lambda
时。
您可以通过两种方式解决这个问题。第一种是在 lambda
中使用默认参数,这会强制在函数创建时计算 i
的值。
lambda i=i: stack_layout.setCurrentIndex(i)
或者,您可以使用 functools.partial
from functools import partial
self.type_top_button.clicked.connect(partial(layout.setCurrentIndex, i))