PyQt 根据 QComboBox 数据在 QSpinBox 和 QTimeEdit 小部件之间动态切换
PyQt dynamically switch between QSpinBox to QTimeEdit widgets depending on QComboBox data
I have a combo box with 2 options 'time' or 'interval' when 'time' is selected I would like to show a QTimeEdit and When 'interval is selected I would like to show一个 QSpinBox。
我可以隐藏间隔小部件并显示时间小部件,但我不知道如何重新定位它以使其显示在间隔小部件所在的位置。
这是我目前的情况:
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
from PyQt5 import QtCore as qtc
class MainWindow(qtw.QMainWindow):
def __init__(self):
super().__init__()
form = qtw.QWidget()
self.setCentralWidget(form)
layout = qtw.QFormLayout()
form.setLayout(layout)
self.when_list = qtw.QComboBox(currentIndexChanged=self.on_change)
self.when_list.addItem('Every X Minutes', 'interval')
self.when_list.addItem('At a specific time', 'time')
self.interval_box = qtw.QSpinBox()
self.time_edit = qtw.QTimeEdit()
self.event_list = qtw.QComboBox()
self.event_list.addItem('Event 1')
self.event_list.addItem('Event 2')
self.event_msg = qtw.QLineEdit()
self.add_button = qtw.QPushButton('Add Event', clicked=self.add_event)
layout.addRow(self.when_list, self.interval_box)
layout.addRow(self.event_list)
layout.addRow(self.event_msg)
layout.addRow(self.add_button)
self.show()
def on_change(self):
if self.when_list.currentData() == 'time':
# Hide interval
self.interval_box.hide()
# Show time - how do I put this where interval_box was?
self.time_edit.show()
elif self.when_list.currentData() == 'interval':
# Hide time - ERROR object has no attribute time_edit
self.time_edit.hide()
# show interval - ERROR object has no attribute interval_box
self.interval_box.show()
def add_event(self):
pass
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
mw = MainWindow()
sys.exit(app.exec())
如何修复错误并在小部件之间动态切换?
您可以使用 QStackedWidget(类似于选项卡小部件,但没有选项卡)并使用组合框信号 select 显示哪个小部件,而不是隐藏和显示小部件。
请注意,如果您要设置可以调用该信号的属性并且插槽使用尚不存在的对象,则不应在构造函数中连接到 *changed
信号:在您的情况下您在构造函数中连接了 currentIndexChanged
信号,但是当一个项目被添加到先前为空的组合框时,该信号总是被调用,并且由于此时尚未创建 time_edit
对象,您将添加第一项后立即收到 AttributeError。
虽然在构造函数中使用信号连接很有用,但必须始终小心使用。
class MainWindow(qtw.QMainWindow):
def __init__(self):
# ...
self.when_list = qtw.QComboBox()
self.when_list.addItem('Every X Minutes', 'interval')
self.when_list.addItem('At a specific time', 'time')
self.when_list.currentIndexChanged.connect(self.on_change)
# ...
self.time_stack = qtw.QStackedWidget()
self.time_stack.addWidget(self.interval_box)
self.time_stack.addWidget(self.time_edit)
layout.addRow(self.when_list, self.time_stack)
# ...
def on_change(self):
if self.when_list.currentData() == 'time':
self.time_stack.setCurrentWidget(self.time_edit)
elif self.when_list.currentData() == 'interval':
self.time_stack.setCurrentWidget(self.interval_box)
另一种解决方案是删除要隐藏的小部件并使用 QFormLayout 函数在同一位置插入一行,但是虽然该布局在许多情况下都很有用,但它主要用于漂亮的“静态”界面。另一种方法是使用 QGridLayout,它允许在同一个“单元格”上设置更多小部件:在这种情况下,您可以轻松切换项目的可见性,但它可能会产生一些问题,因为布局也会尝试每次调整其内容(可以通过对小部件的大小策略使用 setRetainSizeWhenHidden()
来解决。
I have a combo box with 2 options 'time' or 'interval' when 'time' is selected I would like to show a QTimeEdit and When 'interval is selected I would like to show一个 QSpinBox。
我可以隐藏间隔小部件并显示时间小部件,但我不知道如何重新定位它以使其显示在间隔小部件所在的位置。
这是我目前的情况:
import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
from PyQt5 import QtCore as qtc
class MainWindow(qtw.QMainWindow):
def __init__(self):
super().__init__()
form = qtw.QWidget()
self.setCentralWidget(form)
layout = qtw.QFormLayout()
form.setLayout(layout)
self.when_list = qtw.QComboBox(currentIndexChanged=self.on_change)
self.when_list.addItem('Every X Minutes', 'interval')
self.when_list.addItem('At a specific time', 'time')
self.interval_box = qtw.QSpinBox()
self.time_edit = qtw.QTimeEdit()
self.event_list = qtw.QComboBox()
self.event_list.addItem('Event 1')
self.event_list.addItem('Event 2')
self.event_msg = qtw.QLineEdit()
self.add_button = qtw.QPushButton('Add Event', clicked=self.add_event)
layout.addRow(self.when_list, self.interval_box)
layout.addRow(self.event_list)
layout.addRow(self.event_msg)
layout.addRow(self.add_button)
self.show()
def on_change(self):
if self.when_list.currentData() == 'time':
# Hide interval
self.interval_box.hide()
# Show time - how do I put this where interval_box was?
self.time_edit.show()
elif self.when_list.currentData() == 'interval':
# Hide time - ERROR object has no attribute time_edit
self.time_edit.hide()
# show interval - ERROR object has no attribute interval_box
self.interval_box.show()
def add_event(self):
pass
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
mw = MainWindow()
sys.exit(app.exec())
如何修复错误并在小部件之间动态切换?
您可以使用 QStackedWidget(类似于选项卡小部件,但没有选项卡)并使用组合框信号 select 显示哪个小部件,而不是隐藏和显示小部件。
请注意,如果您要设置可以调用该信号的属性并且插槽使用尚不存在的对象,则不应在构造函数中连接到 *changed
信号:在您的情况下您在构造函数中连接了 currentIndexChanged
信号,但是当一个项目被添加到先前为空的组合框时,该信号总是被调用,并且由于此时尚未创建 time_edit
对象,您将添加第一项后立即收到 AttributeError。
虽然在构造函数中使用信号连接很有用,但必须始终小心使用。
class MainWindow(qtw.QMainWindow):
def __init__(self):
# ...
self.when_list = qtw.QComboBox()
self.when_list.addItem('Every X Minutes', 'interval')
self.when_list.addItem('At a specific time', 'time')
self.when_list.currentIndexChanged.connect(self.on_change)
# ...
self.time_stack = qtw.QStackedWidget()
self.time_stack.addWidget(self.interval_box)
self.time_stack.addWidget(self.time_edit)
layout.addRow(self.when_list, self.time_stack)
# ...
def on_change(self):
if self.when_list.currentData() == 'time':
self.time_stack.setCurrentWidget(self.time_edit)
elif self.when_list.currentData() == 'interval':
self.time_stack.setCurrentWidget(self.interval_box)
另一种解决方案是删除要隐藏的小部件并使用 QFormLayout 函数在同一位置插入一行,但是虽然该布局在许多情况下都很有用,但它主要用于漂亮的“静态”界面。另一种方法是使用 QGridLayout,它允许在同一个“单元格”上设置更多小部件:在这种情况下,您可以轻松切换项目的可见性,但它可能会产生一些问题,因为布局也会尝试每次调整其内容(可以通过对小部件的大小策略使用 setRetainSizeWhenHidden()
来解决。